syscons util remove use kbdcontrol & vidcontrol instead
[unix-history] / sys / netinet / in_pcb.orig.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 if (sin->sin_port == 0)
155 return (EADDRNOTAVAIL);
156 if (in_ifaddr) {
157 /*
158 * If the destination address is INADDR_ANY,
159 * use the primary local address.
160 * If the supplied address is INADDR_BROADCAST,
161 * and the primary interface supports broadcast,
162 * choose the broadcast address for that interface.
163 */
164#define satosin(sa) ((struct sockaddr_in *)(sa))
165 if (sin->sin_addr.s_addr == INADDR_ANY)
166 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
167 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
168 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
169 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
170 }
171 if (inp->inp_laddr.s_addr == INADDR_ANY) {
172 register struct route *ro;
173 struct ifnet *ifp;
174
175 ia = (struct in_ifaddr *)0;
176 /*
177 * If route is known or can be allocated now,
178 * our src addr is taken from the i/f, else punt.
179 */
180 ro = &inp->inp_route;
181 if (ro->ro_rt &&
182 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
183 sin->sin_addr.s_addr ||
184 inp->inp_socket->so_options & SO_DONTROUTE)) {
185 RTFREE(ro->ro_rt);
186 ro->ro_rt = (struct rtentry *)0;
187 }
188 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
189 (ro->ro_rt == (struct rtentry *)0 ||
190 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
191 /* No route yet, so try to acquire one */
192 ro->ro_dst.sa_family = AF_INET;
193 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
194 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
195 sin->sin_addr;
196 rtalloc(ro);
197 }
198 /*
199 * If we found a route, use the address
200 * corresponding to the outgoing interface
201 * unless it is the loopback (in case a route
202 * to our address on another net goes to loopback).
203 */
204 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
205 (ifp->if_flags & IFF_LOOPBACK) == 0)
206 for (ia = in_ifaddr; ia; ia = ia->ia_next)
207 if (ia->ia_ifp == ifp)
208 break;
209 if (ia == 0) {
210 int fport = sin->sin_port;
211
212 sin->sin_port = 0;
213 ia = (struct in_ifaddr *)
214 ifa_ifwithdstaddr((struct sockaddr *)sin);
215 sin->sin_port = fport;
216 if (ia == 0)
217 ia = in_iaonnetof(in_netof(sin->sin_addr));
218 if (ia == 0)
219 ia = in_ifaddr;
220 if (ia == 0)
221 return (EADDRNOTAVAIL);
222 }
223#ifdef MULTICAST
224 /*
225 * If the destination address is multicast and an outgoing
226 * interface has been set as a multicast option, use the
227 * address of that interface as our source address.
228 */
229 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
230 inp->inp_moptions != NULL) {
231 struct ip_moptions *imo;
232 struct ifnet *ifp;
233
234 imo = inp->inp_moptions;
235 if (imo->imo_multicast_ifp != NULL) {
236 ifp = imo->imo_multicast_ifp;
237 for (ia = in_ifaddr; ia; ia = ia->ia_next)
238 if (ia->ia_ifp == ifp)
239 break;
240 if (ia == 0)
241 return (EADDRNOTAVAIL);
242 }
243 }
244#endif
245 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
246 }
247 if (in_pcblookup(inp->inp_head,
248 sin->sin_addr,
249 sin->sin_port,
250 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
251 inp->inp_lport,
252 0))
253 return (EADDRINUSE);
254 if (inp->inp_laddr.s_addr == INADDR_ANY) {
255 if (inp->inp_lport == 0)
256 (void)in_pcbbind(inp, (struct mbuf *)0);
257 inp->inp_laddr = ifaddr->sin_addr;
258 }
259 inp->inp_faddr = sin->sin_addr;
260 inp->inp_fport = sin->sin_port;
261#ifdef MTUDISC
262 /*
263 * If the upper layer asked for PMTU discovery services, see
264 * if we can get an idea of what the MTU should be...
265 */
266 in_pcbmtu(inp);
267#endif /* MTUDISC */
268 return (0);
269}
270
271void
272in_pcbdisconnect(inp)
273 struct inpcb *inp;
274{
275
276 inp->inp_faddr.s_addr = INADDR_ANY;
277 inp->inp_fport = 0;
278#ifdef MTUDISC
279 inp->inp_flags &= ~INP_MTUDISCOVERED;
280#endif
281 if (inp->inp_socket->so_state & SS_NOFDREF)
282 in_pcbdetach(inp);
283}
284
285void
286in_pcbdetach(inp)
287 struct inpcb *inp;
288{
289 struct socket *so = inp->inp_socket;
290
291 so->so_pcb = 0;
292 sofree(so);
293 if (inp->inp_options)
294 (void)m_free(inp->inp_options);
295 if (inp->inp_route.ro_rt)
296 rtfree(inp->inp_route.ro_rt);
297#ifdef MULTICAST
298 ip_freemoptions(inp->inp_moptions);
299#endif
300 remque(inp);
301 (void) m_free(dtom(inp));
302}
303
304void
305in_setsockaddr(inp, nam)
306 register struct inpcb *inp;
307 struct mbuf *nam;
308{
309 register struct sockaddr_in *sin;
310
311 nam->m_len = sizeof (*sin);
312 sin = mtod(nam, struct sockaddr_in *);
313 bzero((caddr_t)sin, sizeof (*sin));
314 sin->sin_family = AF_INET;
315 sin->sin_len = sizeof(*sin);
316 sin->sin_port = inp->inp_lport;
317 sin->sin_addr = inp->inp_laddr;
318}
319
320void
321in_setpeeraddr(inp, nam)
322 struct inpcb *inp;
323 struct mbuf *nam;
324{
325 register struct sockaddr_in *sin;
326
327 nam->m_len = sizeof (*sin);
328 sin = mtod(nam, struct sockaddr_in *);
329 bzero((caddr_t)sin, sizeof (*sin));
330 sin->sin_family = AF_INET;
331 sin->sin_len = sizeof(*sin);
332 sin->sin_port = inp->inp_fport;
333 sin->sin_addr = inp->inp_faddr;
334}
335
336/*
337 * Pass some notification to all connections of a protocol
338 * associated with address dst. The local address and/or port numbers
339 * may be specified to limit the search. The "usual action" will be
340 * taken, depending on the ctlinput cmd. The caller must filter any
341 * cmds that are uninteresting (e.g., no error in the map).
342 * Call the protocol specific routine (if any) to report
343 * any errors for each matching socket.
344 *
345 * Must be called at splnet.
346 */
347void
348in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
349 struct inpcb *head;
350 struct sockaddr *dst;
351 u_short fport, lport;
352 struct in_addr laddr;
353 int cmd;
354 void (*notify)(struct inpcb *, int);
355{
356 register struct inpcb *inp, *oinp;
357 struct in_addr faddr;
358 int errno;
359
360 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
361 return;
362 faddr = ((struct sockaddr_in *)dst)->sin_addr;
363 if (faddr.s_addr == INADDR_ANY)
364 return;
365
366 /*
367 * Redirects go to all references to the destination,
368 * and use in_rtchange to invalidate the route cache.
369 * Dead host indications: notify all references to the destination.
370 * MTU change indications: same thing.
371 * Otherwise, if we have knowledge of the local port and address,
372 * deliver only to that socket.
373 */
374 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD
375 || cmd == PRC_MTUCHANGED) {
376 fport = 0;
377 lport = 0;
378 laddr.s_addr = 0;
379 if (cmd != PRC_HOSTDEAD && cmd != PRC_MTUCHANGED)
380 notify = in_rtchange;
381 }
382 errno = inetctlerrmap[cmd];
383 for (inp = head->inp_next; inp != head;) {
384 if (inp->inp_faddr.s_addr != faddr.s_addr ||
385 inp->inp_socket == 0 ||
386 (lport && inp->inp_lport != lport) ||
387 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
388 (fport && inp->inp_fport != fport)) {
389 inp = inp->inp_next;
390 continue;
391 }
392 oinp = inp;
393 inp = inp->inp_next;
394 if (notify)
395 (*notify)(oinp, errno);
396 }
397}
398
399/*
400 * Check for alternatives when higher level complains
401 * about service problems. For now, invalidate cached
402 * routing information. If the route was created dynamically
403 * (by a redirect), time to try a default gateway again.
404 */
405void
406in_losing(inp)
407 struct inpcb *inp;
408{
409 register struct rtentry *rt;
410
411 if ((rt = inp->inp_route.ro_rt)) {
412 rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
413 rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
414 (struct sockaddr *)0, rt->rt_flags, 0);
415 if (rt->rt_flags & RTF_DYNAMIC)
416 (void) rtrequest(RTM_DELETE, rt_key(rt),
417 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
418 (struct rtentry **)0);
419 inp->inp_route.ro_rt = 0;
420 rtfree(rt);
421
422#ifdef MTUDISC
423 /*
424 * When doing MTU discovery, we want to find out as
425 * quickly as possible what the MTU of the new route is.
426 */
427 in_pcbmtu(inp);
428#endif /* MTUDISC */
429 }
430}
431
432/*
433 * After a routing change, flush old routing
434 * and allocate a (hopefully) better one.
435 */
436void
437in_rtchange(inp, errno)
438 register struct inpcb *inp;
439 int errno;
440{
441 if (inp->inp_route.ro_rt) {
442 rtfree(inp->inp_route.ro_rt);
443 inp->inp_route.ro_rt = 0;
444#ifdef MTUDISC
445 /*
446 * A new route can be allocated the next time
447 * output is attempted, but make sure to let
448 * MTU discovery know about it.
449 */
450 in_pcbmtu(inp);
451#endif /* MTUDISC */
452 }
453}
454
455struct inpcb *
456in_pcblookup(head, faddr, fport, laddr, lport, flags)
457 struct inpcb *head;
458 struct in_addr faddr, laddr;
459 u_short fport, lport;
460 int flags;
461{
462 register struct inpcb *inp, *match = 0;
463 int matchwild = 3, wildcard;
464
465 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
466 if (inp->inp_lport != lport)
467 continue;
468 wildcard = 0;
469 if (inp->inp_laddr.s_addr != INADDR_ANY) {
470 if (laddr.s_addr == INADDR_ANY)
471 wildcard++;
472 else if (inp->inp_laddr.s_addr != laddr.s_addr)
473 continue;
474 } else {
475 if (laddr.s_addr != INADDR_ANY)
476 wildcard++;
477 }
478 if (inp->inp_faddr.s_addr != INADDR_ANY) {
479 if (faddr.s_addr == INADDR_ANY)
480 wildcard++;
481 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
482 inp->inp_fport != fport)
483 continue;
484 } else {
485 if (faddr.s_addr != INADDR_ANY)
486 wildcard++;
487 }
488 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
489 continue;
490 if (wildcard < matchwild) {
491 match = inp;
492 matchwild = wildcard;
493 if (matchwild == 0)
494 break;
495 }
496 }
497 return (match);
498}