|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)in_pcb.c 7.2 (Berkeley) 9/4/86
7: */
8:
9: #include "param.h"
10: #include "systm.h"
11: #include "dir.h"
12: #include "user.h"
13: #include "mbuf.h"
14: #include "socket.h"
15: #include "socketvar.h"
16: #include "ioctl.h"
17: #include "in.h"
18: #include "in_systm.h"
19: #include "../net/if.h"
20: #include "../net/route.h"
21: #include "in_pcb.h"
22: #include "in_var.h"
23: #include "protosw.h"
24:
25: struct in_addr zeroin_addr;
26:
27: in_pcballoc(so, head)
28: struct socket *so;
29: struct inpcb *head;
30: {
31: struct mbuf *m;
32: register struct inpcb *inp;
33:
34: m = m_getclr(M_DONTWAIT, MT_PCB);
35: if (m == NULL)
36: return (ENOBUFS);
37: inp = mtod(m, struct inpcb *);
38: inp->inp_head = head;
39: inp->inp_socket = so;
40: insque(inp, head);
41: so->so_pcb = (caddr_t)inp;
42: return (0);
43: }
44:
45: in_pcbbind(inp, nam)
46: register struct inpcb *inp;
47: struct mbuf *nam;
48: {
49: register struct socket *so = inp->inp_socket;
50: register struct inpcb *head = inp->inp_head;
51: register struct sockaddr_in *sin;
52: u_short lport = 0;
53:
54: if (in_ifaddr == 0)
55: return (EADDRNOTAVAIL);
56: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
57: return (EINVAL);
58: if (nam == 0)
59: goto noname;
60: sin = mtod(nam, struct sockaddr_in *);
61: if (nam->m_len != sizeof (*sin))
62: return (EINVAL);
63: if (sin->sin_addr.s_addr != INADDR_ANY) {
64: int tport = sin->sin_port;
65:
66: sin->sin_port = 0; /* yech... */
67: if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
68: return (EADDRNOTAVAIL);
69: sin->sin_port = tport;
70: }
71: lport = sin->sin_port;
72: if (lport) {
73: u_short aport = ntohs(lport);
74: int wild = 0;
75:
76: /* GROSS */
77: if (aport < IPPORT_RESERVED && u.u_uid != 0)
78: return (EACCES);
79: /* even GROSSER, but this is the Internet */
80: if ((so->so_options & SO_REUSEADDR) == 0 &&
81: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
82: (so->so_options & SO_ACCEPTCONN) == 0))
83: wild = INPLOOKUP_WILDCARD;
84: if (in_pcblookup(head,
85: zeroin_addr, 0, sin->sin_addr, lport, wild))
86: return (EADDRINUSE);
87: }
88: inp->inp_laddr = sin->sin_addr;
89: noname:
90: if (lport == 0)
91: do {
92: if (head->inp_lport++ < IPPORT_RESERVED ||
93: head->inp_lport > IPPORT_USERRESERVED)
94: head->inp_lport = IPPORT_RESERVED;
95: lport = htons(head->inp_lport);
96: } while (in_pcblookup(head,
97: zeroin_addr, 0, inp->inp_laddr, lport, 0));
98: inp->inp_lport = lport;
99: return (0);
100: }
101:
102: /*
103: * Connect from a socket to a specified address.
104: * Both address and port must be specified in argument sin.
105: * If don't have a local address for this socket yet,
106: * then pick one.
107: */
108: in_pcbconnect(inp, nam)
109: struct inpcb *inp;
110: struct mbuf *nam;
111: {
112: struct in_ifaddr *ia;
113: struct sockaddr_in *ifaddr;
114: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
115:
116: if (nam->m_len != sizeof (*sin))
117: return (EINVAL);
118: if (sin->sin_family != AF_INET)
119: return (EAFNOSUPPORT);
120: if (sin->sin_port == 0)
121: return (EADDRNOTAVAIL);
122: if (in_ifaddr) {
123: /*
124: * If the destination address is INADDR_ANY,
125: * use the primary local address.
126: * If the supplied address is INADDR_BROADCAST,
127: * and the primary interface supports broadcast,
128: * choose the broadcast address for that interface.
129: */
130: #define satosin(sa) ((struct sockaddr_in *)(sa))
131: if (sin->sin_addr.s_addr == INADDR_ANY)
132: sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
133: else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
134: (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
135: sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
136: }
137: if (inp->inp_laddr.s_addr == INADDR_ANY) {
138: register struct route *ro;
139: struct ifnet *ifp;
140:
141: ia = (struct in_ifaddr *)0;
142: /*
143: * If route is known or can be allocated now,
144: * our src addr is taken from the i/f, else punt.
145: */
146: ro = &inp->inp_route;
147: if (ro->ro_rt &&
148: satosin(&ro->ro_dst)->sin_addr.s_addr !=
149: sin->sin_addr.s_addr) {
150: RTFREE(ro->ro_rt);
151: ro->ro_rt = (struct rtentry *)0;
152: }
153: if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
154: (ro->ro_rt == (struct rtentry *)0 ||
155: ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
156: /* No route yet, so try to acquire one */
157: ro->ro_dst.sa_family = AF_INET;
158: ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
159: sin->sin_addr;
160: rtalloc(ro);
161: }
162: /*
163: * If we found a route, use the address
164: * corresponding to the outgoing interface
165: * unless it is the loopback (in case a route
166: * to our address on another net goes to loopback).
167: */
168: if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
169: (ifp->if_flags & IFF_LOOPBACK) == 0)
170: for (ia = in_ifaddr; ia; ia = ia->ia_next)
171: if (ia->ia_ifp == ifp)
172: break;
173: if (ia == 0) {
174: ia = (struct in_ifaddr *)
175: ifa_ifwithdstaddr((struct sockaddr *)sin);
176: if (ia == 0)
177: ia = in_iaonnetof(in_netof(sin->sin_addr));
178: if (ia == 0)
179: ia = in_ifaddr;
180: if (ia == 0)
181: return (EADDRNOTAVAIL);
182: }
183: ifaddr = (struct sockaddr_in *)&ia->ia_addr;
184: }
185: if (in_pcblookup(inp->inp_head,
186: sin->sin_addr,
187: sin->sin_port,
188: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
189: inp->inp_lport,
190: 0))
191: return (EADDRINUSE);
192: if (inp->inp_laddr.s_addr == INADDR_ANY) {
193: if (inp->inp_lport == 0)
194: (void)in_pcbbind(inp, (struct mbuf *)0);
195: inp->inp_laddr = ifaddr->sin_addr;
196: }
197: inp->inp_faddr = sin->sin_addr;
198: inp->inp_fport = sin->sin_port;
199: return (0);
200: }
201:
202: in_pcbdisconnect(inp)
203: struct inpcb *inp;
204: {
205:
206: inp->inp_faddr.s_addr = INADDR_ANY;
207: inp->inp_fport = 0;
208: if (inp->inp_socket->so_state & SS_NOFDREF)
209: in_pcbdetach(inp);
210: }
211:
212: in_pcbdetach(inp)
213: struct inpcb *inp;
214: {
215: struct socket *so = inp->inp_socket;
216:
217: so->so_pcb = 0;
218: sofree(so);
219: if (inp->inp_options)
220: (void)m_free(inp->inp_options);
221: if (inp->inp_route.ro_rt)
222: rtfree(inp->inp_route.ro_rt);
223: remque(inp);
224: (void) m_free(dtom(inp));
225: }
226:
227: in_setsockaddr(inp, nam)
228: register struct inpcb *inp;
229: struct mbuf *nam;
230: {
231: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
232:
233: nam->m_len = sizeof (*sin);
234: sin = mtod(nam, struct sockaddr_in *);
235: bzero((caddr_t)sin, sizeof (*sin));
236: sin->sin_family = AF_INET;
237: sin->sin_port = inp->inp_lport;
238: sin->sin_addr = inp->inp_laddr;
239: }
240:
241: in_setpeeraddr(inp, nam)
242: register struct inpcb *inp;
243: struct mbuf *nam;
244: {
245: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
246:
247: nam->m_len = sizeof (*sin);
248: sin = mtod(nam, struct sockaddr_in *);
249: bzero((caddr_t)sin, sizeof (*sin));
250: sin->sin_family = AF_INET;
251: sin->sin_port = inp->inp_fport;
252: sin->sin_addr = inp->inp_faddr;
253: }
254:
255: /*
256: * Pass some notification to all connections of a protocol
257: * associated with address dst. Call the protocol specific
258: * routine (if any) to handle each connection.
259: */
260: in_pcbnotify(head, dst, errno, notify)
261: struct inpcb *head;
262: register struct in_addr *dst;
263: int errno, (*notify)();
264: {
265: register struct inpcb *inp, *oinp;
266: int s = splimp();
267:
268: for (inp = head->inp_next; inp != head;) {
269: if (inp->inp_faddr.s_addr != dst->s_addr ||
270: inp->inp_socket == 0) {
271: inp = inp->inp_next;
272: continue;
273: }
274: if (errno)
275: inp->inp_socket->so_error = errno;
276: oinp = inp;
277: inp = inp->inp_next;
278: if (notify)
279: (*notify)(oinp);
280: }
281: splx(s);
282: }
283:
284: /*
285: * Check for alternatives when higher level complains
286: * about service problems. For now, invalidate cached
287: * routing information. If the route was created dynamically
288: * (by a redirect), time to try a default gateway again.
289: */
290: in_losing(inp)
291: struct inpcb *inp;
292: {
293: register struct rtentry *rt;
294:
295: if ((rt = inp->inp_route.ro_rt)) {
296: if (rt->rt_flags & RTF_DYNAMIC)
297: (void) rtrequest((int)SIOCDELRT, rt);
298: rtfree(rt);
299: inp->inp_route.ro_rt = 0;
300: /*
301: * A new route can be allocated
302: * the next time output is attempted.
303: */
304: }
305: }
306:
307: /*
308: * After a routing change, flush old routing
309: * and allocate a (hopefully) better one.
310: */
311: in_rtchange(inp)
312: register struct inpcb *inp;
313: {
314: if (inp->inp_route.ro_rt) {
315: rtfree(inp->inp_route.ro_rt);
316: inp->inp_route.ro_rt = 0;
317: /*
318: * A new route can be allocated the next time
319: * output is attempted.
320: */
321: }
322: }
323:
324: struct inpcb *
325: in_pcblookup(head, faddr, fport, laddr, lport, flags)
326: struct inpcb *head;
327: struct in_addr faddr, laddr;
328: u_short fport, lport;
329: int flags;
330: {
331: register struct inpcb *inp, *match = 0;
332: int matchwild = 3, wildcard;
333:
334: for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
335: if (inp->inp_lport != lport)
336: continue;
337: wildcard = 0;
338: if (inp->inp_laddr.s_addr != INADDR_ANY) {
339: if (laddr.s_addr == INADDR_ANY)
340: wildcard++;
341: else if (inp->inp_laddr.s_addr != laddr.s_addr)
342: continue;
343: } else {
344: if (laddr.s_addr != INADDR_ANY)
345: wildcard++;
346: }
347: if (inp->inp_faddr.s_addr != INADDR_ANY) {
348: if (faddr.s_addr == INADDR_ANY)
349: wildcard++;
350: else if (inp->inp_faddr.s_addr != faddr.s_addr ||
351: inp->inp_fport != fport)
352: continue;
353: } else {
354: if (faddr.s_addr != INADDR_ANY)
355: wildcard++;
356: }
357: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
358: continue;
359: if (wildcard < matchwild) {
360: match = inp;
361: matchwild = wildcard;
362: if (matchwild == 0)
363: break;
364: }
365: }
366: return (match);
367: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.