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