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