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