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