in_pcb.c revision 1.13 1 /* $NetBSD: in_pcb.c,v 1.13 1995/04/13 06:28:21 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/ioctl.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/proc.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/in_var.h>
58 #include <netinet/ip_var.h>
59
60 struct in_addr zeroin_addr;
61
62 int
63 in_pcballoc(so, head)
64 struct socket *so;
65 struct inpcb *head;
66 {
67 register struct inpcb *inp;
68
69 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK);
70 if (inp == NULL)
71 return (ENOBUFS);
72 bzero((caddr_t)inp, sizeof(*inp));
73 inp->inp_head = head;
74 inp->inp_socket = so;
75 insque(inp, head);
76 so->so_pcb = (caddr_t)inp;
77 return (0);
78 }
79
80 int
81 in_pcbbind(inp, nam)
82 register struct inpcb *inp;
83 struct mbuf *nam;
84 {
85 register struct socket *so = inp->inp_socket;
86 register struct inpcb *head = inp->inp_head;
87 register struct sockaddr_in *sin;
88 struct proc *p = curproc; /* XXX */
89 u_int16_t lport = 0;
90 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
91 int error;
92
93 if (in_ifaddr == 0)
94 return (EADDRNOTAVAIL);
95 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
96 return (EINVAL);
97 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
98 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
99 (so->so_options & SO_ACCEPTCONN) == 0))
100 wild = INPLOOKUP_WILDCARD;
101 if (nam) {
102 sin = mtod(nam, struct sockaddr_in *);
103 if (nam->m_len != sizeof (*sin))
104 return (EINVAL);
105 #ifdef notdef
106 /*
107 * We should check the family, but old programs
108 * incorrectly fail to initialize it.
109 */
110 if (sin->sin_family != AF_INET)
111 return (EAFNOSUPPORT);
112 #endif
113 lport = sin->sin_port;
114 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
115 /*
116 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
117 * allow complete duplication of binding if
118 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
119 * and a multicast address is bound on both
120 * new and duplicated sockets.
121 */
122 if (so->so_options & SO_REUSEADDR)
123 reuseport = SO_REUSEADDR|SO_REUSEPORT;
124 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
125 sin->sin_port = 0; /* yech... */
126 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
127 return (EADDRNOTAVAIL);
128 }
129 if (lport) {
130 struct inpcb *t;
131
132 /* GROSS */
133 if (ntohs(lport) < IPPORT_RESERVED &&
134 (error = suser(p->p_ucred, &p->p_acflag)))
135 return (EACCES);
136 t = in_pcblookup(head, zeroin_addr, 0,
137 sin->sin_addr, lport, wild);
138 if (t && (reuseport & t->inp_socket->so_options) == 0)
139 return (EADDRINUSE);
140 }
141 inp->inp_laddr = sin->sin_addr;
142 }
143 if (lport == 0)
144 do {
145 if (head->inp_lport++ < IPPORT_RESERVED ||
146 head->inp_lport > IPPORT_USERRESERVED)
147 head->inp_lport = IPPORT_RESERVED;
148 lport = htons(head->inp_lport);
149 } while (in_pcblookup(head,
150 zeroin_addr, 0, inp->inp_laddr, lport, wild));
151 inp->inp_lport = lport;
152 return (0);
153 }
154
155 /*
156 * Connect from a socket to a specified address.
157 * Both address and port must be specified in argument sin.
158 * If don't have a local address for this socket yet,
159 * then pick one.
160 */
161 int
162 in_pcbconnect(inp, nam)
163 register struct inpcb *inp;
164 struct mbuf *nam;
165 {
166 struct in_ifaddr *ia;
167 struct sockaddr_in *ifaddr;
168 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
169
170 if (nam->m_len != sizeof (*sin))
171 return (EINVAL);
172 if (sin->sin_family != AF_INET)
173 return (EAFNOSUPPORT);
174 if (sin->sin_port == 0)
175 return (EADDRNOTAVAIL);
176 if (in_ifaddr) {
177 /*
178 * If the destination address is INADDR_ANY,
179 * use the primary local address.
180 * If the supplied address is INADDR_BROADCAST,
181 * and the primary interface supports broadcast,
182 * choose the broadcast address for that interface.
183 */
184 #define satosin(sa) ((struct sockaddr_in *)(sa))
185 #define sintosa(sin) ((struct sockaddr *)(sin))
186 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
187 if (sin->sin_addr.s_addr == INADDR_ANY)
188 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
189 else if (sin->sin_addr.s_addr == (u_int32_t)INADDR_BROADCAST &&
190 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
191 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
192 }
193 if (inp->inp_laddr.s_addr == INADDR_ANY) {
194 register struct route *ro;
195
196 ia = (struct in_ifaddr *)0;
197 /*
198 * If route is known or can be allocated now,
199 * our src addr is taken from the i/f, else punt.
200 */
201 ro = &inp->inp_route;
202 if (ro->ro_rt &&
203 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
204 sin->sin_addr.s_addr ||
205 inp->inp_socket->so_options & SO_DONTROUTE)) {
206 RTFREE(ro->ro_rt);
207 ro->ro_rt = (struct rtentry *)0;
208 }
209 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
210 (ro->ro_rt == (struct rtentry *)0 ||
211 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
212 /* No route yet, so try to acquire one */
213 ro->ro_dst.sa_family = AF_INET;
214 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
215 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
216 sin->sin_addr;
217 rtalloc(ro);
218 }
219 /*
220 * If we found a route, use the address
221 * corresponding to the outgoing interface
222 * unless it is the loopback (in case a route
223 * to our address on another net goes to loopback).
224 */
225 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
226 ia = ifatoia(ro->ro_rt->rt_ifa);
227 if (ia == 0) {
228 u_int16_t fport = sin->sin_port;
229
230 sin->sin_port = 0;
231 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
232 if (ia == 0)
233 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
234 sin->sin_port = fport;
235 if (ia == 0)
236 ia = in_ifaddr;
237 if (ia == 0)
238 return (EADDRNOTAVAIL);
239 }
240 /*
241 * If the destination address is multicast and an outgoing
242 * interface has been set as a multicast option, use the
243 * address of that interface as our source address.
244 */
245 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
246 inp->inp_moptions != NULL) {
247 struct ip_moptions *imo;
248 struct ifnet *ifp;
249
250 imo = inp->inp_moptions;
251 if (imo->imo_multicast_ifp != NULL) {
252 ifp = imo->imo_multicast_ifp;
253 for (ia = in_ifaddr; ia; ia = ia->ia_next)
254 if (ia->ia_ifp == ifp)
255 break;
256 if (ia == 0)
257 return (EADDRNOTAVAIL);
258 }
259 }
260 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
261 }
262 if (in_pcblookup(inp->inp_head,
263 sin->sin_addr,
264 sin->sin_port,
265 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
266 inp->inp_lport,
267 0))
268 return (EADDRINUSE);
269 if (inp->inp_laddr.s_addr == INADDR_ANY) {
270 if (inp->inp_lport == 0)
271 (void)in_pcbbind(inp, (struct mbuf *)0);
272 inp->inp_laddr = ifaddr->sin_addr;
273 }
274 inp->inp_faddr = sin->sin_addr;
275 inp->inp_fport = sin->sin_port;
276 return (0);
277 }
278
279 int
280 in_pcbdisconnect(inp)
281 struct inpcb *inp;
282 {
283
284 inp->inp_faddr.s_addr = INADDR_ANY;
285 inp->inp_fport = 0;
286 if (inp->inp_socket->so_state & SS_NOFDREF)
287 in_pcbdetach(inp);
288 }
289
290 int
291 in_pcbdetach(inp)
292 struct inpcb *inp;
293 {
294 struct socket *so = inp->inp_socket;
295
296 so->so_pcb = 0;
297 sofree(so);
298 if (inp->inp_options)
299 (void)m_free(inp->inp_options);
300 if (inp->inp_route.ro_rt)
301 rtfree(inp->inp_route.ro_rt);
302 ip_freemoptions(inp->inp_moptions);
303 remque(inp);
304 FREE(inp, M_PCB);
305 }
306
307 int
308 in_setsockaddr(inp, nam)
309 register struct inpcb *inp;
310 struct mbuf *nam;
311 {
312 register struct sockaddr_in *sin;
313
314 nam->m_len = sizeof (*sin);
315 sin = mtod(nam, struct sockaddr_in *);
316 bzero((caddr_t)sin, sizeof (*sin));
317 sin->sin_family = AF_INET;
318 sin->sin_len = sizeof(*sin);
319 sin->sin_port = inp->inp_lport;
320 sin->sin_addr = inp->inp_laddr;
321 }
322
323 int
324 in_setpeeraddr(inp, nam)
325 struct inpcb *inp;
326 struct mbuf *nam;
327 {
328 register struct sockaddr_in *sin;
329
330 nam->m_len = sizeof (*sin);
331 sin = mtod(nam, struct sockaddr_in *);
332 bzero((caddr_t)sin, sizeof (*sin));
333 sin->sin_family = AF_INET;
334 sin->sin_len = sizeof(*sin);
335 sin->sin_port = inp->inp_fport;
336 sin->sin_addr = inp->inp_faddr;
337 }
338
339 /*
340 * Pass some notification to all connections of a protocol
341 * associated with address dst. The local address and/or port numbers
342 * may be specified to limit the search. The "usual action" will be
343 * taken, depending on the ctlinput cmd. The caller must filter any
344 * cmds that are uninteresting (e.g., no error in the map).
345 * Call the protocol specific routine (if any) to report
346 * any errors for each matching socket.
347 *
348 * Must be called at splnet.
349 */
350 int
351 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
352 struct inpcb *head;
353 struct sockaddr *dst;
354 u_int fport_arg, lport_arg;
355 struct in_addr laddr;
356 int cmd;
357 void (*notify) __P((struct inpcb *, int));
358 {
359 extern u_char inetctlerrmap[];
360 register struct inpcb *inp, *oinp;
361 struct in_addr faddr;
362 u_int16_t fport = fport_arg, lport = lport_arg;
363 int errno;
364
365 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
366 return;
367 faddr = ((struct sockaddr_in *)dst)->sin_addr;
368 if (faddr.s_addr == INADDR_ANY)
369 return;
370
371 /*
372 * Redirects go to all references to the destination,
373 * and use in_rtchange to invalidate the route cache.
374 * Dead host indications: notify all references to the destination.
375 * Otherwise, if we have knowledge of the local port and address,
376 * deliver only to that socket.
377 */
378 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
379 fport = 0;
380 lport = 0;
381 laddr.s_addr = 0;
382 if (cmd != PRC_HOSTDEAD)
383 notify = in_rtchange;
384 }
385 errno = inetctlerrmap[cmd];
386 for (inp = head->inp_next; inp != head;) {
387 if (inp->inp_faddr.s_addr != faddr.s_addr ||
388 inp->inp_socket == 0 ||
389 (lport && inp->inp_lport != lport) ||
390 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
391 (fport && inp->inp_fport != fport)) {
392 inp = inp->inp_next;
393 continue;
394 }
395 oinp = inp;
396 inp = inp->inp_next;
397 if (notify)
398 (*notify)(oinp, errno);
399 }
400 }
401
402 /*
403 * Check for alternatives when higher level complains
404 * about service problems. For now, invalidate cached
405 * routing information. If the route was created dynamically
406 * (by a redirect), time to try a default gateway again.
407 */
408 int
409 in_losing(inp)
410 struct inpcb *inp;
411 {
412 register struct rtentry *rt;
413 struct rt_addrinfo info;
414
415 if ((rt = inp->inp_route.ro_rt)) {
416 inp->inp_route.ro_rt = 0;
417 bzero((caddr_t)&info, sizeof(info));
418 info.rti_info[RTAX_DST] =
419 (struct sockaddr *)&inp->inp_route.ro_dst;
420 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
421 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
422 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
423 if (rt->rt_flags & RTF_DYNAMIC)
424 (void) rtrequest(RTM_DELETE, rt_key(rt),
425 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
426 (struct rtentry **)0);
427 else
428 /*
429 * A new route can be allocated
430 * the next time output is attempted.
431 */
432 rtfree(rt);
433 }
434 }
435
436 /*
437 * After a routing change, flush old routing
438 * and allocate a (hopefully) better one.
439 */
440 void
441 in_rtchange(inp, errno)
442 register struct inpcb *inp;
443 int errno;
444 {
445 if (inp->inp_route.ro_rt) {
446 rtfree(inp->inp_route.ro_rt);
447 inp->inp_route.ro_rt = 0;
448 /*
449 * A new route can be allocated the next time
450 * output is attempted.
451 */
452 }
453 }
454
455 struct inpcb *
456 in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
457 struct inpcb *head;
458 struct in_addr faddr, laddr;
459 u_int fport_arg, lport_arg;
460 int flags;
461 {
462 register struct inpcb *inp, *match = 0;
463 int matchwild = 3, wildcard;
464 u_int16_t fport = fport_arg, lport = lport_arg;
465
466 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
467 if (inp->inp_lport != lport)
468 continue;
469 wildcard = 0;
470 if (inp->inp_laddr.s_addr != INADDR_ANY) {
471 if (laddr.s_addr == INADDR_ANY)
472 wildcard++;
473 else if (inp->inp_laddr.s_addr != laddr.s_addr)
474 continue;
475 } else {
476 if (laddr.s_addr != INADDR_ANY)
477 wildcard++;
478 }
479 if (inp->inp_faddr.s_addr != INADDR_ANY) {
480 if (faddr.s_addr == INADDR_ANY)
481 wildcard++;
482 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
483 inp->inp_fport != fport)
484 continue;
485 } else {
486 if (faddr.s_addr != INADDR_ANY)
487 wildcard++;
488 }
489 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
490 continue;
491 if (wildcard < matchwild) {
492 match = inp;
493 matchwild = wildcard;
494 if (matchwild == 0)
495 break;
496 }
497 }
498 return (match);
499 }
500