split out descend and inherit attributes; add signal tracing
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
2b6b6284 3 * All rights reserved.
8ae0e4b4 4 *
2b6b6284 5 * Redistribution and use in source and binary forms are permitted
616d42db
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2b6b6284 16 *
b6cdc71a 17 * @(#)in_pcb.c 7.12 (Berkeley) %G%
8ae0e4b4 18 */
af092e86 19
20666ad3
JB
20#include "param.h"
21#include "systm.h"
20666ad3 22#include "user.h"
9d91b170 23#include "malloc.h"
20666ad3
JB
24#include "mbuf.h"
25#include "socket.h"
26#include "socketvar.h"
2ba2de86 27#include "ioctl.h"
4ad99bae 28#include "../net/if.h"
c124e997 29#include "../net/route.h"
b1dd4cca
MK
30#include "in.h"
31#include "in_systm.h"
32#include "ip.h"
20666ad3 33#include "in_pcb.h"
5d305bdd 34#include "in_var.h"
20666ad3 35#include "protosw.h"
af092e86 36
1a3dbf93 37struct in_addr zeroin_addr;
405c9168 38
8f0d18de
BJ
39in_pcballoc(so, head)
40 struct socket *so;
41 struct inpcb *head;
42{
43 struct mbuf *m;
44 register struct inpcb *inp;
45
cce93e4b 46 m = m_getclr(M_DONTWAIT, MT_PCB);
5cdc4d65 47 if (m == NULL)
8f0d18de
BJ
48 return (ENOBUFS);
49 inp = mtod(m, struct inpcb *);
50 inp->inp_head = head;
51 inp->inp_socket = so;
52 insque(inp, head);
53 so->so_pcb = (caddr_t)inp;
54 return (0);
55}
56
8075bb0e 57in_pcbbind(inp, nam)
8f0d18de 58 register struct inpcb *inp;
8075bb0e 59 struct mbuf *nam;
8f0d18de
BJ
60{
61 register struct socket *so = inp->inp_socket;
62 register struct inpcb *head = inp->inp_head;
8075bb0e 63 register struct sockaddr_in *sin;
8f0d18de
BJ
64 u_short lport = 0;
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
BJ
69 return (EINVAL);
70 if (nam == 0)
71 goto noname;
72 sin = mtod(nam, struct sockaddr_in *);
73 if (nam->m_len != sizeof (*sin))
74 return (EINVAL);
5cdc4d65 75 if (sin->sin_addr.s_addr != INADDR_ANY) {
8075bb0e 76 int tport = sin->sin_port;
8f0d18de 77
8075bb0e 78 sin->sin_port = 0; /* yech... */
5d305bdd 79 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
8075bb0e
BJ
80 return (EADDRNOTAVAIL);
81 sin->sin_port = tport;
8f0d18de 82 }
8075bb0e
BJ
83 lport = sin->sin_port;
84 if (lport) {
f2d10020 85 u_short aport = ntohs(lport);
8075bb0e 86 int wild = 0;
c124e997 87
8075bb0e
BJ
88 /* GROSS */
89 if (aport < IPPORT_RESERVED && u.u_uid != 0)
90 return (EACCES);
b4a3d4a7
SL
91 /* even GROSSER, but this is the Internet */
92 if ((so->so_options & SO_REUSEADDR) == 0 &&
93 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
94 (so->so_options & SO_ACCEPTCONN) == 0))
8075bb0e
BJ
95 wild = INPLOOKUP_WILDCARD;
96 if (in_pcblookup(head,
97 zeroin_addr, 0, sin->sin_addr, lport, wild))
98 return (EADDRINUSE);
4ad99bae 99 }
8075bb0e
BJ
100 inp->inp_laddr = sin->sin_addr;
101noname:
b454c3ea
BJ
102 if (lport == 0)
103 do {
f44e5691
MK
104 if (head->inp_lport++ < IPPORT_RESERVED ||
105 head->inp_lport > IPPORT_USERRESERVED)
1aa87517 106 head->inp_lport = IPPORT_RESERVED;
b454c3ea 107 lport = htons(head->inp_lport);
1aa87517
BJ
108 } while (in_pcblookup(head,
109 zeroin_addr, 0, inp->inp_laddr, lport, 0));
4ad99bae 110 inp->inp_lport = lport;
4ad99bae 111 return (0);
af092e86
BJ
112}
113
1acff8ec
BJ
114/*
115 * Connect from a socket to a specified address.
116 * Both address and port must be specified in argument sin.
117 * If don't have a local address for this socket yet,
118 * then pick one.
119 */
8075bb0e 120in_pcbconnect(inp, nam)
552daad2 121 register struct inpcb *inp;
8075bb0e 122 struct mbuf *nam;
2b4b57cd 123{
5d305bdd 124 struct in_ifaddr *ia;
ee787340 125 struct sockaddr_in *ifaddr;
8075bb0e 126 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 127
8075bb0e
BJ
128 if (nam->m_len != sizeof (*sin))
129 return (EINVAL);
4ad99bae
BJ
130 if (sin->sin_family != AF_INET)
131 return (EAFNOSUPPORT);
5d305bdd 132 if (sin->sin_port == 0)
4ad99bae 133 return (EADDRNOTAVAIL);
5d305bdd 134 if (in_ifaddr) {
3f319daa
MK
135 /*
136 * If the destination address is INADDR_ANY,
137 * use the primary local address.
138 * If the supplied address is INADDR_BROADCAST,
139 * and the primary interface supports broadcast,
140 * choose the broadcast address for that interface.
141 */
5d305bdd
MK
142#define satosin(sa) ((struct sockaddr_in *)(sa))
143 if (sin->sin_addr.s_addr == INADDR_ANY)
3f319daa 144 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
c9aca561 145 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
3f319daa
MK
146 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
147 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
5d305bdd 148 }
5cdc4d65 149 if (inp->inp_laddr.s_addr == INADDR_ANY) {
c198b4ed
MK
150 register struct route *ro;
151 struct ifnet *ifp;
99578149 152
c198b4ed
MK
153 ia = (struct in_ifaddr *)0;
154 /*
155 * If route is known or can be allocated now,
156 * our src addr is taken from the i/f, else punt.
157 */
158 ro = &inp->inp_route;
159 if (ro->ro_rt &&
1bf75d4e
MK
160 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
161 sin->sin_addr.s_addr ||
162 inp->inp_socket->so_options & SO_DONTROUTE)) {
c198b4ed
MK
163 RTFREE(ro->ro_rt);
164 ro->ro_rt = (struct rtentry *)0;
165 }
9f21d23f
MK
166 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
167 (ro->ro_rt == (struct rtentry *)0 ||
d4538fe2 168 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
c198b4ed
MK
169 /* No route yet, so try to acquire one */
170 ro->ro_dst.sa_family = AF_INET;
b4dc7708 171 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
c198b4ed
MK
172 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
173 sin->sin_addr;
174 rtalloc(ro);
ee787340 175 }
d4538fe2
MK
176 /*
177 * If we found a route, use the address
178 * corresponding to the outgoing interface
179 * unless it is the loopback (in case a route
180 * to our address on another net goes to loopback).
181 */
182 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
183 (ifp->if_flags & IFF_LOOPBACK) == 0)
184 for (ia = in_ifaddr; ia; ia = ia->ia_next)
185 if (ia->ia_ifp == ifp)
186 break;
9f21d23f 187 if (ia == 0) {
1bf75d4e
MK
188 int fport = sin->sin_port;
189
190 sin->sin_port = 0;
9f21d23f
MK
191 ia = (struct in_ifaddr *)
192 ifa_ifwithdstaddr((struct sockaddr *)sin);
1bf75d4e 193 sin->sin_port = fport;
9f21d23f
MK
194 if (ia == 0)
195 ia = in_iaonnetof(in_netof(sin->sin_addr));
196 if (ia == 0)
197 ia = in_ifaddr;
198 if (ia == 0)
199 return (EADDRNOTAVAIL);
c198b4ed 200 }
5d305bdd 201 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
1aa87517
BJ
202 }
203 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
204 sin->sin_addr,
205 sin->sin_port,
ee787340 206 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
207 inp->inp_lport,
208 0))
b454c3ea 209 return (EADDRINUSE);
3cd2053b
SL
210 if (inp->inp_laddr.s_addr == INADDR_ANY) {
211 if (inp->inp_lport == 0)
8011f5df 212 (void)in_pcbbind(inp, (struct mbuf *)0);
ee787340 213 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 214 }
4ad99bae
BJ
215 inp->inp_faddr = sin->sin_addr;
216 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
217 return (0);
218}
219
405c9168
BJ
220in_pcbdisconnect(inp)
221 struct inpcb *inp;
222{
223
5cdc4d65 224 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 225 inp->inp_fport = 0;
8f0d18de 226 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
227 in_pcbdetach(inp);
228}
229
230in_pcbdetach(inp)
af092e86
BJ
231 struct inpcb *inp;
232{
233 struct socket *so = inp->inp_socket;
234
ba55c9af
BJ
235 so->so_pcb = 0;
236 sofree(so);
c9aca561 237 if (inp->inp_options)
8011f5df 238 (void)m_free(inp->inp_options);
c124e997 239 if (inp->inp_route.ro_rt)
f6311fb6 240 rtfree(inp->inp_route.ro_rt);
7545cf09 241 remque(inp);
cdad2eb1 242 (void) m_free(dtom(inp));
af092e86
BJ
243}
244
8075bb0e 245in_setsockaddr(inp, nam)
126472ab 246 register struct inpcb *inp;
8075bb0e 247 struct mbuf *nam;
126472ab 248{
2aa0644d 249 register struct sockaddr_in *sin;
8075bb0e
BJ
250
251 nam->m_len = sizeof (*sin);
252 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
253 bzero((caddr_t)sin, sizeof (*sin));
254 sin->sin_family = AF_INET;
b4dc7708 255 sin->sin_len = sizeof(*sin);
126472ab
SL
256 sin->sin_port = inp->inp_lport;
257 sin->sin_addr = inp->inp_laddr;
258}
259
a7343092 260in_setpeeraddr(inp, nam)
552daad2 261 struct inpcb *inp;
a7343092
SL
262 struct mbuf *nam;
263{
2aa0644d 264 register struct sockaddr_in *sin;
a7343092
SL
265
266 nam->m_len = sizeof (*sin);
267 sin = mtod(nam, struct sockaddr_in *);
268 bzero((caddr_t)sin, sizeof (*sin));
269 sin->sin_family = AF_INET;
b4dc7708 270 sin->sin_len = sizeof(*sin);
a7343092
SL
271 sin->sin_port = inp->inp_fport;
272 sin->sin_addr = inp->inp_faddr;
273}
274
72e4f44e 275/*
842b6bb5 276 * Pass some notification to all connections of a protocol
b1dd4cca
MK
277 * associated with address dst. The local address and/or port numbers
278 * may be specified to limit the search. The "usual action" will be
279 * taken, depending on the ctlinput cmd. The caller must filter any
280 * cmds that are uninteresting (e.g., no error in the map).
281 * Call the protocol specific routine (if any) to report
282 * any errors for each matching socket.
283 *
284 * Must be called at splnet.
72e4f44e 285 */
b1dd4cca 286in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
72e4f44e 287 struct inpcb *head;
b1dd4cca
MK
288 struct sockaddr *dst;
289 u_short fport, lport;
290 struct in_addr laddr;
291 int cmd, (*notify)();
72e4f44e
SL
292{
293 register struct inpcb *inp, *oinp;
b1dd4cca
MK
294 struct in_addr faddr;
295 int errno;
296 int in_rtchange();
297 extern u_char inetctlerrmap[];
298
299 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
300 return;
301 faddr = ((struct sockaddr_in *)dst)->sin_addr;
302 if (faddr.s_addr == INADDR_ANY)
303 return;
72e4f44e 304
b1dd4cca
MK
305 /*
306 * Redirects go to all references to the destination,
307 * and use in_rtchange to invalidate the route cache.
308 * Dead host indications: notify all references to the destination.
309 * Otherwise, if we have knowledge of the local port and address,
310 * deliver only to that socket.
311 */
312 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
313 fport = 0;
314 lport = 0;
315 laddr.s_addr = 0;
316 if (cmd != PRC_HOSTDEAD)
317 notify = in_rtchange;
318 }
319 errno = inetctlerrmap[cmd];
72e4f44e 320 for (inp = head->inp_next; inp != head;) {
b1dd4cca
MK
321 if (inp->inp_faddr.s_addr != faddr.s_addr ||
322 inp->inp_socket == 0 ||
323 (lport && inp->inp_lport != lport) ||
324 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
325 (fport && inp->inp_fport != fport)) {
72e4f44e
SL
326 inp = inp->inp_next;
327 continue;
328 }
72e4f44e
SL
329 oinp = inp;
330 inp = inp->inp_next;
c9aca561 331 if (notify)
b6cdc71a 332 (*notify)(oinp, errno);
72e4f44e 333 }
72e4f44e
SL
334}
335
2ba2de86
MK
336/*
337 * Check for alternatives when higher level complains
338 * about service problems. For now, invalidate cached
339 * routing information. If the route was created dynamically
340 * (by a redirect), time to try a default gateway again.
341 */
342in_losing(inp)
343 struct inpcb *inp;
344{
345 register struct rtentry *rt;
346
347 if ((rt = inp->inp_route.ro_rt)) {
b4dc7708
KS
348 rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
349 rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
350 (struct sockaddr *)0, rt->rt_flags, 0);
2ba2de86 351 if (rt->rt_flags & RTF_DYNAMIC)
b4dc7708
KS
352 (void) rtrequest(RTM_DELETE, rt_key(rt),
353 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
354 (struct rtentry **)0);
2ba2de86 355 inp->inp_route.ro_rt = 0;
b4dc7708 356 rtfree(rt);
2ba2de86
MK
357 /*
358 * A new route can be allocated
359 * the next time output is attempted.
360 */
361 }
362}
363
842b6bb5
MK
364/*
365 * After a routing change, flush old routing
366 * and allocate a (hopefully) better one.
367 */
368in_rtchange(inp)
2ba2de86 369 register struct inpcb *inp;
842b6bb5
MK
370{
371 if (inp->inp_route.ro_rt) {
372 rtfree(inp->inp_route.ro_rt);
373 inp->inp_route.ro_rt = 0;
374 /*
375 * A new route can be allocated the next time
376 * output is attempted.
377 */
378 }
842b6bb5
MK
379}
380
cdad2eb1 381struct inpcb *
ebcadd38 382in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 383 struct inpcb *head;
4ad99bae 384 struct in_addr faddr, laddr;
af092e86 385 u_short fport, lport;
ebcadd38 386 int flags;
af092e86 387{
1aa87517
BJ
388 register struct inpcb *inp, *match = 0;
389 int matchwild = 3, wildcard;
af092e86 390
405c9168 391 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 392 if (inp->inp_lport != lport)
405c9168 393 continue;
1aa87517 394 wildcard = 0;
5cdc4d65
SL
395 if (inp->inp_laddr.s_addr != INADDR_ANY) {
396 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
397 wildcard++;
398 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
399 continue;
400 } else {
5cdc4d65 401 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
402 wildcard++;
403 }
5cdc4d65
SL
404 if (inp->inp_faddr.s_addr != INADDR_ANY) {
405 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
406 wildcard++;
407 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 408 inp->inp_fport != fport)
1aa87517
BJ
409 continue;
410 } else {
5cdc4d65 411 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
412 wildcard++;
413 }
ebcadd38 414 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 415 continue;
1aa87517
BJ
416 if (wildcard < matchwild) {
417 match = inp;
418 matchwild = wildcard;
419 if (matchwild == 0)
420 break;
405c9168 421 }
1aa87517 422 }
405c9168 423 return (match);
af092e86 424}