4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
8ae0e4b4 1/*
e7a3707f
KB
2 * Copyright (c) 1982, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
8ae0e4b4 4 *
dbf0c423 5 * %sccs.include.redist.c%
2b6b6284 6 *
e7a3707f 7 * @(#)in_pcb.c 8.1 (Berkeley) %G%
8ae0e4b4 8 */
af092e86 9
5548a02f
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/malloc.h>
13#include <sys/mbuf.h>
14#include <sys/protosw.h>
15#include <sys/socket.h>
16#include <sys/socketvar.h>
17#include <sys/ioctl.h>
18#include <sys/errno.h>
6d5b2d5f
MK
19#include <sys/time.h>
20#include <sys/proc.h>
6aa944c6 21
5548a02f
KB
22#include <net/if.h>
23#include <net/route.h>
6aa944c6 24
5548a02f
KB
25#include <netinet/in.h>
26#include <netinet/in_systm.h>
27#include <netinet/ip.h>
28#include <netinet/in_pcb.h>
29#include <netinet/in_var.h>
5548a02f 30#include <netinet/ip_var.h>
d6fa15c2 31
1a3dbf93 32struct in_addr zeroin_addr;
405c9168 33
0be5ae70 34int
8f0d18de
BJ
35in_pcballoc(so, head)
36 struct socket *so;
37 struct inpcb *head;
38{
39 struct mbuf *m;
40 register struct inpcb *inp;
41
d6fa15c2
KS
42 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK);
43 if (inp == NULL)
8f0d18de 44 return (ENOBUFS);
d6fa15c2 45 bzero((caddr_t)inp, sizeof(*inp));
8f0d18de
BJ
46 inp->inp_head = head;
47 inp->inp_socket = so;
48 insque(inp, head);
49 so->so_pcb = (caddr_t)inp;
50 return (0);
51}
0be5ae70
KB
52
53int
8075bb0e 54in_pcbbind(inp, nam)
8f0d18de 55 register struct inpcb *inp;
8075bb0e 56 struct mbuf *nam;
8f0d18de
BJ
57{
58 register struct socket *so = inp->inp_socket;
59 register struct inpcb *head = inp->inp_head;
8075bb0e 60 register struct sockaddr_in *sin;
6d5b2d5f 61 struct proc *p = curproc; /* XXX */
8f0d18de 62 u_short lport = 0;
6d5b2d5f
MK
63 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
64 int error;
8f0d18de 65
5d305bdd 66 if (in_ifaddr == 0)
8f0d18de 67 return (EADDRNOTAVAIL);
5cdc4d65 68 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
8075bb0e 69 return (EINVAL);
6d5b2d5f 70 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
12472eef
KM
71 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
72 (so->so_options & SO_ACCEPTCONN) == 0))
73 wild = INPLOOKUP_WILDCARD;
6d5b2d5f
MK
74 if (nam) {
75 sin = mtod(nam, struct sockaddr_in *);
76 if (nam->m_len != sizeof (*sin))
77 return (EINVAL);
78#ifdef notdef
79 /*
80 * We should check the family, but old programs
81 * incorrectly fail to initialize it.
82 */
83 if (sin->sin_family != AF_INET)
84 return (EAFNOSUPPORT);
85#endif
86 lport = sin->sin_port;
87 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
88 /*
89 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
90 * allow complete duplication of binding if
91 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
92 * and a multicast address is bound on both
93 * new and duplicated sockets.
94 */
95 if (so->so_options & SO_REUSEADDR)
96 reuseport = SO_REUSEADDR|SO_REUSEPORT;
97 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
98 sin->sin_port = 0; /* yech... */
99 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
100 return (EADDRNOTAVAIL);
101 }
102 if (lport) {
103 struct inpcb *t;
c124e997 104
6d5b2d5f
MK
105 /* GROSS */
106 if (ntohs(lport) < IPPORT_RESERVED &&
107 (error = suser(p->p_ucred, &p->p_acflag)))
108 return (error);
109 t = in_pcblookup(head, zeroin_addr, 0,
110 sin->sin_addr, lport, wild);
111 if (t && (reuseport & t->inp_socket->so_options) == 0)
112 return (EADDRINUSE);
113 }
114 inp->inp_laddr = sin->sin_addr;
4ad99bae 115 }
b454c3ea
BJ
116 if (lport == 0)
117 do {
f44e5691
MK
118 if (head->inp_lport++ < IPPORT_RESERVED ||
119 head->inp_lport > IPPORT_USERRESERVED)
1aa87517 120 head->inp_lport = IPPORT_RESERVED;
b454c3ea 121 lport = htons(head->inp_lport);
1aa87517 122 } while (in_pcblookup(head,
12472eef 123 zeroin_addr, 0, inp->inp_laddr, lport, wild));
4ad99bae 124 inp->inp_lport = lport;
4ad99bae 125 return (0);
af092e86
BJ
126}
127
1acff8ec
BJ
128/*
129 * Connect from a socket to a specified address.
130 * Both address and port must be specified in argument sin.
131 * If don't have a local address for this socket yet,
132 * then pick one.
133 */
0be5ae70 134int
8075bb0e 135in_pcbconnect(inp, nam)
552daad2 136 register struct inpcb *inp;
8075bb0e 137 struct mbuf *nam;
2b4b57cd 138{
5d305bdd 139 struct in_ifaddr *ia;
ee787340 140 struct sockaddr_in *ifaddr;
8075bb0e 141 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 142
8075bb0e
BJ
143 if (nam->m_len != sizeof (*sin))
144 return (EINVAL);
4ad99bae
BJ
145 if (sin->sin_family != AF_INET)
146 return (EAFNOSUPPORT);
5d305bdd 147 if (sin->sin_port == 0)
4ad99bae 148 return (EADDRNOTAVAIL);
5d305bdd 149 if (in_ifaddr) {
3f319daa
MK
150 /*
151 * If the destination address is INADDR_ANY,
152 * use the primary local address.
153 * If the supplied address is INADDR_BROADCAST,
154 * and the primary interface supports broadcast,
155 * choose the broadcast address for that interface.
156 */
5d305bdd 157#define satosin(sa) ((struct sockaddr_in *)(sa))
09ed489e
KS
158#define sintosa(sin) ((struct sockaddr *)(sin))
159#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
5d305bdd 160 if (sin->sin_addr.s_addr == INADDR_ANY)
3f319daa 161 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
c9aca561 162 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
3f319daa
MK
163 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
164 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
5d305bdd 165 }
5cdc4d65 166 if (inp->inp_laddr.s_addr == INADDR_ANY) {
c198b4ed 167 register struct route *ro;
99578149 168
c198b4ed
MK
169 ia = (struct in_ifaddr *)0;
170 /*
171 * If route is known or can be allocated now,
172 * our src addr is taken from the i/f, else punt.
173 */
174 ro = &inp->inp_route;
175 if (ro->ro_rt &&
1bf75d4e
MK
176 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
177 sin->sin_addr.s_addr ||
178 inp->inp_socket->so_options & SO_DONTROUTE)) {
c198b4ed
MK
179 RTFREE(ro->ro_rt);
180 ro->ro_rt = (struct rtentry *)0;
181 }
9f21d23f
MK
182 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
183 (ro->ro_rt == (struct rtentry *)0 ||
d4538fe2 184 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
c198b4ed
MK
185 /* No route yet, so try to acquire one */
186 ro->ro_dst.sa_family = AF_INET;
b4dc7708 187 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
c198b4ed
MK
188 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
189 sin->sin_addr;
190 rtalloc(ro);
ee787340 191 }
d4538fe2
MK
192 /*
193 * If we found a route, use the address
194 * corresponding to the outgoing interface
195 * unless it is the loopback (in case a route
196 * to our address on another net goes to loopback).
197 */
09ed489e
KS
198 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
199 ia = ifatoia(ro->ro_rt->rt_ifa);
9f21d23f 200 if (ia == 0) {
0be5ae70 201 u_short fport = sin->sin_port;
1bf75d4e
MK
202
203 sin->sin_port = 0;
09ed489e 204 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
9f21d23f 205 if (ia == 0)
09ed489e
KS
206 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
207 sin->sin_port = fport;
9f21d23f
MK
208 if (ia == 0)
209 ia = in_ifaddr;
210 if (ia == 0)
211 return (EADDRNOTAVAIL);
c198b4ed 212 }
d6fa15c2
KS
213 /*
214 * If the destination address is multicast and an outgoing
215 * interface has been set as a multicast option, use the
216 * address of that interface as our source address.
217 */
218 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
219 inp->inp_moptions != NULL) {
220 struct ip_moptions *imo;
09ed489e 221 struct ifnet *ifp;
d6fa15c2
KS
222
223 imo = inp->inp_moptions;
224 if (imo->imo_multicast_ifp != NULL) {
225 ifp = imo->imo_multicast_ifp;
226 for (ia = in_ifaddr; ia; ia = ia->ia_next)
227 if (ia->ia_ifp == ifp)
228 break;
229 if (ia == 0)
230 return (EADDRNOTAVAIL);
231 }
232 }
5d305bdd 233 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
1aa87517
BJ
234 }
235 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
236 sin->sin_addr,
237 sin->sin_port,
ee787340 238 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
239 inp->inp_lport,
240 0))
b454c3ea 241 return (EADDRINUSE);
3cd2053b
SL
242 if (inp->inp_laddr.s_addr == INADDR_ANY) {
243 if (inp->inp_lport == 0)
8011f5df 244 (void)in_pcbbind(inp, (struct mbuf *)0);
ee787340 245 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 246 }
4ad99bae
BJ
247 inp->inp_faddr = sin->sin_addr;
248 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
249 return (0);
250}
251
0be5ae70 252int
405c9168
BJ
253in_pcbdisconnect(inp)
254 struct inpcb *inp;
255{
256
5cdc4d65 257 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 258 inp->inp_fport = 0;
8f0d18de 259 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
260 in_pcbdetach(inp);
261}
262
0be5ae70 263int
405c9168 264in_pcbdetach(inp)
af092e86
BJ
265 struct inpcb *inp;
266{
267 struct socket *so = inp->inp_socket;
268
ba55c9af
BJ
269 so->so_pcb = 0;
270 sofree(so);
c9aca561 271 if (inp->inp_options)
8011f5df 272 (void)m_free(inp->inp_options);
c124e997 273 if (inp->inp_route.ro_rt)
f6311fb6 274 rtfree(inp->inp_route.ro_rt);
d6fa15c2 275 ip_freemoptions(inp->inp_moptions);
7545cf09 276 remque(inp);
d6fa15c2 277 FREE(inp, M_PCB);
af092e86
BJ
278}
279
0be5ae70 280int
8075bb0e 281in_setsockaddr(inp, nam)
126472ab 282 register struct inpcb *inp;
8075bb0e 283 struct mbuf *nam;
126472ab 284{
2aa0644d 285 register struct sockaddr_in *sin;
8075bb0e
BJ
286
287 nam->m_len = sizeof (*sin);
288 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
289 bzero((caddr_t)sin, sizeof (*sin));
290 sin->sin_family = AF_INET;
b4dc7708 291 sin->sin_len = sizeof(*sin);
126472ab
SL
292 sin->sin_port = inp->inp_lport;
293 sin->sin_addr = inp->inp_laddr;
294}
295
0be5ae70 296int
a7343092 297in_setpeeraddr(inp, nam)
552daad2 298 struct inpcb *inp;
a7343092
SL
299 struct mbuf *nam;
300{
2aa0644d 301 register struct sockaddr_in *sin;
a7343092
SL
302
303 nam->m_len = sizeof (*sin);
304 sin = mtod(nam, struct sockaddr_in *);
305 bzero((caddr_t)sin, sizeof (*sin));
306 sin->sin_family = AF_INET;
b4dc7708 307 sin->sin_len = sizeof(*sin);
a7343092
SL
308 sin->sin_port = inp->inp_fport;
309 sin->sin_addr = inp->inp_faddr;
310}
311
72e4f44e 312/*
842b6bb5 313 * Pass some notification to all connections of a protocol
b1dd4cca
MK
314 * associated with address dst. The local address and/or port numbers
315 * may be specified to limit the search. The "usual action" will be
316 * taken, depending on the ctlinput cmd. The caller must filter any
317 * cmds that are uninteresting (e.g., no error in the map).
318 * Call the protocol specific routine (if any) to report
319 * any errors for each matching socket.
320 *
321 * Must be called at splnet.
72e4f44e 322 */
0be5ae70
KB
323int
324in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
72e4f44e 325 struct inpcb *head;
b1dd4cca 326 struct sockaddr *dst;
0be5ae70 327 u_int fport_arg, lport_arg;
b1dd4cca 328 struct in_addr laddr;
0be5ae70
KB
329 int cmd;
330 void (*notify) __P((struct inpcb *, int));
72e4f44e 331{
0be5ae70 332 extern u_char inetctlerrmap[];
72e4f44e 333 register struct inpcb *inp, *oinp;
b1dd4cca 334 struct in_addr faddr;
0be5ae70 335 u_short fport = fport_arg, lport = lport_arg;
b1dd4cca 336 int errno;
b1dd4cca
MK
337
338 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
339 return;
340 faddr = ((struct sockaddr_in *)dst)->sin_addr;
341 if (faddr.s_addr == INADDR_ANY)
342 return;
72e4f44e 343
b1dd4cca
MK
344 /*
345 * Redirects go to all references to the destination,
346 * and use in_rtchange to invalidate the route cache.
347 * Dead host indications: notify all references to the destination.
348 * Otherwise, if we have knowledge of the local port and address,
349 * deliver only to that socket.
350 */
351 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
352 fport = 0;
353 lport = 0;
354 laddr.s_addr = 0;
355 if (cmd != PRC_HOSTDEAD)
356 notify = in_rtchange;
357 }
358 errno = inetctlerrmap[cmd];
72e4f44e 359 for (inp = head->inp_next; inp != head;) {
b1dd4cca
MK
360 if (inp->inp_faddr.s_addr != faddr.s_addr ||
361 inp->inp_socket == 0 ||
362 (lport && inp->inp_lport != lport) ||
363 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
364 (fport && inp->inp_fport != fport)) {
72e4f44e
SL
365 inp = inp->inp_next;
366 continue;
367 }
72e4f44e
SL
368 oinp = inp;
369 inp = inp->inp_next;
c9aca561 370 if (notify)
b6cdc71a 371 (*notify)(oinp, errno);
72e4f44e 372 }
72e4f44e
SL
373}
374
2ba2de86
MK
375/*
376 * Check for alternatives when higher level complains
377 * about service problems. For now, invalidate cached
378 * routing information. If the route was created dynamically
379 * (by a redirect), time to try a default gateway again.
380 */
0be5ae70 381int
2ba2de86
MK
382in_losing(inp)
383 struct inpcb *inp;
384{
385 register struct rtentry *rt;
400be97f 386 struct rt_addrinfo info;
2ba2de86
MK
387
388 if ((rt = inp->inp_route.ro_rt)) {
60da172c 389 inp->inp_route.ro_rt = 0;
400be97f
KS
390 bzero((caddr_t)&info, sizeof(info));
391 info.rti_info[RTAX_DST] =
392 (struct sockaddr *)&inp->inp_route.ro_dst;
393 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
394 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
395 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
2ba2de86 396 if (rt->rt_flags & RTF_DYNAMIC)
b4dc7708
KS
397 (void) rtrequest(RTM_DELETE, rt_key(rt),
398 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
399 (struct rtentry **)0);
60da172c 400 else
2ba2de86
MK
401 /*
402 * A new route can be allocated
403 * the next time output is attempted.
404 */
60da172c 405 rtfree(rt);
2ba2de86
MK
406 }
407}
408
842b6bb5
MK
409/*
410 * After a routing change, flush old routing
411 * and allocate a (hopefully) better one.
412 */
0be5ae70
KB
413void
414in_rtchange(inp, errno)
2ba2de86 415 register struct inpcb *inp;
0be5ae70 416 int errno;
842b6bb5
MK
417{
418 if (inp->inp_route.ro_rt) {
419 rtfree(inp->inp_route.ro_rt);
420 inp->inp_route.ro_rt = 0;
421 /*
422 * A new route can be allocated the next time
423 * output is attempted.
424 */
425 }
842b6bb5
MK
426}
427
cdad2eb1 428struct inpcb *
0be5ae70 429in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
af092e86 430 struct inpcb *head;
4ad99bae 431 struct in_addr faddr, laddr;
0be5ae70 432 u_int fport_arg, lport_arg;
ebcadd38 433 int flags;
af092e86 434{
1aa87517
BJ
435 register struct inpcb *inp, *match = 0;
436 int matchwild = 3, wildcard;
0be5ae70 437 u_short fport = fport_arg, lport = lport_arg;
af092e86 438
405c9168 439 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 440 if (inp->inp_lport != lport)
405c9168 441 continue;
1aa87517 442 wildcard = 0;
5cdc4d65
SL
443 if (inp->inp_laddr.s_addr != INADDR_ANY) {
444 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
445 wildcard++;
446 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
447 continue;
448 } else {
5cdc4d65 449 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
450 wildcard++;
451 }
5cdc4d65
SL
452 if (inp->inp_faddr.s_addr != INADDR_ANY) {
453 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
454 wildcard++;
455 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 456 inp->inp_fport != fport)
1aa87517
BJ
457 continue;
458 } else {
5cdc4d65 459 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
460 wildcard++;
461 }
ebcadd38 462 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 463 continue;
1aa87517
BJ
464 if (wildcard < matchwild) {
465 match = inp;
466 matchwild = wildcard;
467 if (matchwild == 0)
468 break;
405c9168 469 }
1aa87517 470 }
405c9168 471 return (match);
af092e86 472}