source: rtems/cpukit/libnetworking/netinet/in_pcb.c @ ff0f694d

4.104.114.84.95
Last change on this file since ff0f694d was ff0f694d, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 20, 1998 at 9:47:37 PM

Fixed many warnings.

  • Property mode set to 100644
File size: 20.9 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1991, 1993, 1995
3 *      The Regents of the University of California.  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    8.4 (Berkeley) 5/24/95
34 *      $Id$
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <sys/ioctl.h>
46#include <sys/errno.h>
47#include <sys/time.h>
48#include <sys/proc.h>
49#include <sys/kernel.h>
50#include <sys/sysctl.h>
51
52#include <net/if.h>
53#include <net/route.h>
54
55#include <netinet/in.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/in_pcb.h>
59#include <netinet/in_var.h>
60#include <netinet/ip_var.h>
61
62struct  in_addr zeroin_addr;
63
64static void      in_pcbinshash __P((struct inpcb *));
65static void      in_rtchange __P((struct inpcb *, int));
66
67/*
68 * These configure the range of local port addresses assigned to
69 * "unspecified" outgoing connections/packets/whatever.
70 */
71static int ipport_lowfirstauto  = IPPORT_RESERVED - 1;  /* 1023 */
72static int ipport_lowlastauto = IPPORT_RESERVEDSTART;   /* 600 */
73static int ipport_firstauto = IPPORT_RESERVED;          /* 1024 */
74static int ipport_lastauto  = IPPORT_USERRESERVED;      /* 5000 */
75static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;     /* 40000 */
76static int ipport_hilastauto  = IPPORT_HILASTAUTO;      /* 44999 */
77
78#define RANGECHK(var, min, max) \
79        if ((var) < (min)) { (var) = (min); } \
80        else if ((var) > (max)) { (var) = (max); }
81
82#if 0
83static int
84sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
85{
86        int error = sysctl_handle_int(oidp,
87                oidp->oid_arg1, oidp->oid_arg2, req);
88        if (!error) {
89                RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
90                RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
91                RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
92                RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
93                RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
94                RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
95        }
96        return error;
97}
98#endif
99
100#undef RANGECHK
101
102SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
103
104SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
105           &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
106SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
107           &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
108SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
109           &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
110SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
111           &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
112SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
113           &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
114SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
115           &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
116
117int
118in_pcballoc(so, pcbinfo)
119        struct socket *so;
120        struct inpcbinfo *pcbinfo;
121{
122        register struct inpcb *inp;
123        int s;
124
125        MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT);
126        if (inp == NULL)
127                return (ENOBUFS);
128        bzero((caddr_t)inp, sizeof(*inp));
129        inp->inp_pcbinfo = pcbinfo;
130        inp->inp_socket = so;
131        s = splnet();
132        LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
133        in_pcbinshash(inp);
134        splx(s);
135        so->so_pcb = (caddr_t)inp;
136        return (0);
137}
138
139int
140in_pcbbind(inp, nam)
141        register struct inpcb *inp;
142        struct mbuf *nam;
143{
144        register struct socket *so = inp->inp_socket;
145        unsigned short *lastport;
146        struct sockaddr_in *sin;
147        u_short lport = 0;
148        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
149        int error;
150
151        if (in_ifaddr == 0)
152                return (EADDRNOTAVAIL);
153        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
154                return (EINVAL);
155        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
156            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
157             (so->so_options & SO_ACCEPTCONN) == 0))
158                wild = 1;
159        if (nam) {
160                sin = mtod(nam, struct sockaddr_in *);
161                if (nam->m_len != sizeof (*sin))
162                        return (EINVAL);
163#ifdef notdef
164                /*
165                 * We should check the family, but old programs
166                 * incorrectly fail to initialize it.
167                 */
168                if (sin->sin_family != AF_INET)
169                        return (EAFNOSUPPORT);
170#endif
171                lport = sin->sin_port;
172                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
173                        /*
174                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
175                         * allow complete duplication of binding if
176                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
177                         * and a multicast address is bound on both
178                         * new and duplicated sockets.
179                         */
180                        if (so->so_options & SO_REUSEADDR)
181                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
182                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
183                        sin->sin_port = 0;              /* yech... */
184                        if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
185                                return (EADDRNOTAVAIL);
186                }
187                if (lport) {
188                        struct inpcb *t;
189
190                        /* GROSS */
191                        if (ntohs(lport) < IPPORT_RESERVED &&
192                            (error = suser(p->p_ucred, &p->p_acflag)))
193                                return (EACCES);
194                        if (so->so_uid) {
195                                t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr,
196                                    0, sin->sin_addr, lport,
197                                    INPLOOKUP_WILDCARD);
198                                if (t && (so->so_uid != t->inp_socket->so_uid))
199                                        return (EADDRINUSE);
200                        }
201                        t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0,
202                            sin->sin_addr, lport, wild);
203                        if (t && (reuseport & t->inp_socket->so_options) == 0)
204                                return (EADDRINUSE);
205                }
206                inp->inp_laddr = sin->sin_addr;
207        }
208        if (lport == 0) {
209                ushort first, last;
210                int count;
211
212                inp->inp_flags |= INP_ANONPORT;
213
214                if (inp->inp_flags & INP_HIGHPORT) {
215                        first = ipport_hifirstauto;     /* sysctl */
216                        last  = ipport_hilastauto;
217                        lastport = &inp->inp_pcbinfo->lasthi;
218                } else if (inp->inp_flags & INP_LOWPORT) {
219                        if ((error = suser(p->p_ucred, &p->p_acflag)))
220                                return (EACCES);
221                        first = ipport_lowfirstauto;    /* 1023 */
222                        last  = ipport_lowlastauto;     /* 600 */
223                        lastport = &inp->inp_pcbinfo->lastlow;
224                } else {
225                        first = ipport_firstauto;       /* sysctl */
226                        last  = ipport_lastauto;
227                        lastport = &inp->inp_pcbinfo->lastport;
228                }
229                /*
230                 * Simple check to ensure all ports are not used up causing
231                 * a deadlock here.
232                 *
233                 * We split the two cases (up and down) so that the direction
234                 * is not being tested on each round of the loop.
235                 */
236                if (first > last) {
237                        /*
238                         * counting down
239                         */
240                        count = first - last;
241
242                        do {
243                                if (count-- <= 0)       /* completely used? */
244                                        return (EADDRNOTAVAIL);
245                                --*lastport;
246                                if (*lastport > first || *lastport < last)
247                                        *lastport = first;
248                                lport = htons(*lastport);
249                        } while (in_pcblookup(inp->inp_pcbinfo,
250                                 zeroin_addr, 0, inp->inp_laddr, lport, wild));
251                } else {
252                        /*
253                         * counting up
254                         */
255                        count = last - first;
256
257                        do {
258                                if (count-- <= 0)       /* completely used? */
259                                        return (EADDRNOTAVAIL);
260                                ++*lastport;
261                                if (*lastport < first || *lastport > last)
262                                        *lastport = first;
263                                lport = htons(*lastport);
264                        } while (in_pcblookup(inp->inp_pcbinfo,
265                                 zeroin_addr, 0, inp->inp_laddr, lport, wild));
266                }
267        }
268        inp->inp_lport = lport;
269        in_pcbrehash(inp);
270        return (0);
271}
272
273/*
274 *   Transform old in_pcbconnect() into an inner subroutine for new
275 *   in_pcbconnect(): Do some validity-checking on the remote
276 *   address (in mbuf 'nam') and then determine local host address
277 *   (i.e., which interface) to use to access that remote host.
278 *
279 *   This preserves definition of in_pcbconnect(), while supporting a
280 *   slightly different version for T/TCP.  (This is more than
281 *   a bit of a kludge, but cleaning up the internal interfaces would
282 *   have forced minor changes in every protocol).
283 */
284
285int
286in_pcbladdr(inp, nam, plocal_sin)
287        register struct inpcb *inp;
288        struct mbuf *nam;
289        struct sockaddr_in **plocal_sin;
290{
291        struct in_ifaddr *ia;
292        register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
293
294        if (nam->m_len != sizeof (*sin))
295                return (EINVAL);
296        if (sin->sin_family != AF_INET)
297                return (EAFNOSUPPORT);
298        if (sin->sin_port == 0)
299                return (EADDRNOTAVAIL);
300        if (in_ifaddr) {
301                /*
302                 * If the destination address is INADDR_ANY,
303                 * use the primary local address.
304                 * If the supplied address is INADDR_BROADCAST,
305                 * and the primary interface supports broadcast,
306                 * choose the broadcast address for that interface.
307                 */
308#define satosin(sa)     ((struct sockaddr_in *)(sa))
309#define sintosa(sin)    ((struct sockaddr *)(sin))
310#define ifatoia(ifa)    ((struct in_ifaddr *)(ifa))
311                if (sin->sin_addr.s_addr == INADDR_ANY)
312                    sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
313                else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
314                  (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
315                    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
316        }
317        if (inp->inp_laddr.s_addr == INADDR_ANY) {
318                register struct route *ro;
319
320                ia = (struct in_ifaddr *)0;
321                /*
322                 * If route is known or can be allocated now,
323                 * our src addr is taken from the i/f, else punt.
324                 */
325                ro = &inp->inp_route;
326                if (ro->ro_rt &&
327                    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
328                        sin->sin_addr.s_addr ||
329                    inp->inp_socket->so_options & SO_DONTROUTE)) {
330                        RTFREE(ro->ro_rt);
331                        ro->ro_rt = (struct rtentry *)0;
332                }
333                if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
334                    (ro->ro_rt == (struct rtentry *)0 ||
335                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
336                        /* No route yet, so try to acquire one */
337                        ro->ro_dst.sa_family = AF_INET;
338                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
339                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
340                                sin->sin_addr;
341                        rtalloc(ro);
342                }
343                /*
344                 * If we found a route, use the address
345                 * corresponding to the outgoing interface
346                 * unless it is the loopback (in case a route
347                 * to our address on another net goes to loopback).
348                 */
349                if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
350                        ia = ifatoia(ro->ro_rt->rt_ifa);
351                if (ia == 0) {
352                        u_short fport = sin->sin_port;
353
354                        sin->sin_port = 0;
355                        ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
356                        if (ia == 0)
357                                ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
358                        sin->sin_port = fport;
359                        if (ia == 0)
360                                ia = in_ifaddr;
361                        if (ia == 0)
362                                return (EADDRNOTAVAIL);
363                }
364                /*
365                 * If the destination address is multicast and an outgoing
366                 * interface has been set as a multicast option, use the
367                 * address of that interface as our source address.
368                 */
369                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
370                    inp->inp_moptions != NULL) {
371                        struct ip_moptions *imo;
372                        struct ifnet *ifp;
373
374                        imo = inp->inp_moptions;
375                        if (imo->imo_multicast_ifp != NULL) {
376                                ifp = imo->imo_multicast_ifp;
377                                for (ia = in_ifaddr; ia; ia = ia->ia_next)
378                                        if (ia->ia_ifp == ifp)
379                                                break;
380                                if (ia == 0)
381                                        return (EADDRNOTAVAIL);
382                        }
383                }
384        /*
385         * Don't do pcblookup call here; return interface in plocal_sin
386         * and exit to caller, that will do the lookup.
387         */
388                *plocal_sin = &ia->ia_addr;
389
390        }
391        return(0);
392}
393
394/*
395 * Outer subroutine:
396 * Connect from a socket to a specified address.
397 * Both address and port must be specified in argument sin.
398 * If don't have a local address for this socket yet,
399 * then pick one.
400 */
401int
402in_pcbconnect(inp, nam)
403        register struct inpcb *inp;
404        struct mbuf *nam;
405{
406        struct sockaddr_in *ifaddr;
407        register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
408        int error;
409
410        /*
411         *   Call inner routine, to assign local interface address.
412         */
413        if ((error = in_pcbladdr(inp, nam, &ifaddr)))
414                return(error);
415
416        if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
417            inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
418            inp->inp_lport, 0) != NULL)
419                return (EADDRINUSE);
420        if (inp->inp_laddr.s_addr == INADDR_ANY) {
421                if (inp->inp_lport == 0)
422                        (void)in_pcbbind(inp, (struct mbuf *)0);
423                inp->inp_laddr = ifaddr->sin_addr;
424        }
425        inp->inp_faddr = sin->sin_addr;
426        inp->inp_fport = sin->sin_port;
427        in_pcbrehash(inp);
428        return (0);
429}
430
431void
432in_pcbdisconnect(inp)
433        struct inpcb *inp;
434{
435
436        inp->inp_faddr.s_addr = INADDR_ANY;
437        inp->inp_fport = 0;
438        in_pcbrehash(inp);
439        if (inp->inp_socket->so_state & SS_NOFDREF)
440                in_pcbdetach(inp);
441}
442
443void
444in_pcbdetach(inp)
445        struct inpcb *inp;
446{
447        struct socket *so = inp->inp_socket;
448        int s;
449
450        so->so_pcb = 0;
451        sofree(so);
452        if (inp->inp_options)
453                (void)m_free(inp->inp_options);
454        if (inp->inp_route.ro_rt)
455                rtfree(inp->inp_route.ro_rt);
456        ip_freemoptions(inp->inp_moptions);
457        s = splnet();
458        LIST_REMOVE(inp, inp_hash);
459        LIST_REMOVE(inp, inp_list);
460        splx(s);
461        FREE(inp, M_PCB);
462}
463
464void
465in_setsockaddr(inp, nam)
466        register struct inpcb *inp;
467        struct mbuf *nam;
468{
469        register struct sockaddr_in *sin;
470
471        nam->m_len = sizeof (*sin);
472        sin = mtod(nam, struct sockaddr_in *);
473        bzero((caddr_t)sin, sizeof (*sin));
474        sin->sin_family = AF_INET;
475        sin->sin_len = sizeof(*sin);
476        sin->sin_port = inp->inp_lport;
477        sin->sin_addr = inp->inp_laddr;
478}
479
480void
481in_setpeeraddr(inp, nam)
482        struct inpcb *inp;
483        struct mbuf *nam;
484{
485        register struct sockaddr_in *sin;
486
487        nam->m_len = sizeof (*sin);
488        sin = mtod(nam, struct sockaddr_in *);
489        bzero((caddr_t)sin, sizeof (*sin));
490        sin->sin_family = AF_INET;
491        sin->sin_len = sizeof(*sin);
492        sin->sin_port = inp->inp_fport;
493        sin->sin_addr = inp->inp_faddr;
494}
495
496/*
497 * Pass some notification to all connections of a protocol
498 * associated with address dst.  The local address and/or port numbers
499 * may be specified to limit the search.  The "usual action" will be
500 * taken, depending on the ctlinput cmd.  The caller must filter any
501 * cmds that are uninteresting (e.g., no error in the map).
502 * Call the protocol specific routine (if any) to report
503 * any errors for each matching socket.
504 *
505 * Must be called at splnet.
506 */
507void
508in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
509        struct inpcbhead *head;
510        struct sockaddr *dst;
511        u_int fport_arg, lport_arg;
512        struct in_addr laddr;
513        int cmd;
514        void (*notify) __P((struct inpcb *, int));
515{
516        register struct inpcb *inp, *oinp;
517        struct in_addr faddr;
518        u_short fport = fport_arg, lport = lport_arg;
519        int errnum, s;
520
521        if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
522                return;
523        faddr = ((struct sockaddr_in *)dst)->sin_addr;
524        if (faddr.s_addr == INADDR_ANY)
525                return;
526
527        /*
528         * Redirects go to all references to the destination,
529         * and use in_rtchange to invalidate the route cache.
530         * Dead host indications: notify all references to the destination.
531         * Otherwise, if we have knowledge of the local port and address,
532         * deliver only to that socket.
533         */
534        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
535                fport = 0;
536                lport = 0;
537                laddr.s_addr = 0;
538                if (cmd != PRC_HOSTDEAD)
539                        notify = in_rtchange;
540        }
541        errnum = inetctlerrmap[cmd];
542        s = splnet();
543        for (inp = head->lh_first; inp != NULL;) {
544                if (inp->inp_faddr.s_addr != faddr.s_addr ||
545                    inp->inp_socket == 0 ||
546                    (lport && inp->inp_lport != lport) ||
547                    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
548                    (fport && inp->inp_fport != fport)) {
549                        inp = inp->inp_list.le_next;
550                        continue;
551                }
552                oinp = inp;
553                inp = inp->inp_list.le_next;
554                if (notify)
555                        (*notify)(oinp, errnum);
556        }
557        splx(s);
558}
559
560/*
561 * Check for alternatives when higher level complains
562 * about service problems.  For now, invalidate cached
563 * routing information.  If the route was created dynamically
564 * (by a redirect), time to try a default gateway again.
565 */
566void
567in_losing(inp)
568        struct inpcb *inp;
569{
570        register struct rtentry *rt;
571        struct rt_addrinfo info;
572
573        if ((rt = inp->inp_route.ro_rt)) {
574                inp->inp_route.ro_rt = 0;
575                bzero((caddr_t)&info, sizeof(info));
576                info.rti_info[RTAX_DST] =
577                        (struct sockaddr *)&inp->inp_route.ro_dst;
578                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
579                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
580                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
581                if (rt->rt_flags & RTF_DYNAMIC)
582                        (void) rtrequest(RTM_DELETE, rt_key(rt),
583                                rt->rt_gateway, rt_mask(rt), rt->rt_flags,
584                                (struct rtentry **)0);
585                else
586                /*
587                 * A new route can be allocated
588                 * the next time output is attempted.
589                 */
590                        rtfree(rt);
591        }
592}
593
594/*
595 * After a routing change, flush old routing
596 * and allocate a (hopefully) better one.
597 */
598static void
599in_rtchange(inp, errnum)
600        register struct inpcb *inp;
601        int errnum;
602{
603        if (inp->inp_route.ro_rt) {
604                rtfree(inp->inp_route.ro_rt);
605                inp->inp_route.ro_rt = 0;
606                /*
607                 * A new route can be allocated the next time
608                 * output is attempted.
609                 */
610        }
611}
612
613struct inpcb *
614in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay)
615        struct inpcbinfo *pcbinfo;
616        struct in_addr faddr, laddr;
617        u_int fport_arg, lport_arg;
618        int wild_okay;
619{
620        register struct inpcb *inp, *match = NULL;
621        int matchwild = 3, wildcard;
622        u_short fport = fport_arg, lport = lport_arg;
623        int s;
624
625        s = splnet();
626
627        for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
628                if (inp->inp_lport != lport)
629                        continue;
630                wildcard = 0;
631                if (inp->inp_faddr.s_addr != INADDR_ANY) {
632                        if (faddr.s_addr == INADDR_ANY)
633                                wildcard++;
634                        else if (inp->inp_faddr.s_addr != faddr.s_addr ||
635                            inp->inp_fport != fport)
636                                continue;
637                } else {
638                        if (faddr.s_addr != INADDR_ANY)
639                                wildcard++;
640                }
641                if (inp->inp_laddr.s_addr != INADDR_ANY) {
642                        if (laddr.s_addr == INADDR_ANY)
643                                wildcard++;
644                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
645                                continue;
646                } else {
647                        if (laddr.s_addr != INADDR_ANY)
648                                wildcard++;
649                }
650                if (wildcard && wild_okay == 0)
651                        continue;
652                if (wildcard < matchwild) {
653                        match = inp;
654                        matchwild = wildcard;
655                        if (matchwild == 0) {
656                                break;
657                        }
658                }
659        }
660        splx(s);
661        return (match);
662}
663
664/*
665 * Lookup PCB in hash list.
666 */
667struct inpcb *
668in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
669        struct inpcbinfo *pcbinfo;
670        struct in_addr faddr, laddr;
671        u_int fport_arg, lport_arg;
672        int wildcard;
673{
674        struct inpcbhead *head;
675        register struct inpcb *inp;
676        u_short fport = fport_arg, lport = lport_arg;
677        int s;
678
679        s = splnet();
680        /*
681         * First look for an exact match.
682         */
683        head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
684        for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
685                if (inp->inp_faddr.s_addr == faddr.s_addr &&
686                    inp->inp_laddr.s_addr == laddr.s_addr &&
687                    inp->inp_fport == fport &&
688                    inp->inp_lport == lport)
689                        goto found;
690        }
691        if (wildcard) {
692                struct inpcb *local_wild = NULL;
693
694                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
695                for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
696                        if (inp->inp_faddr.s_addr == INADDR_ANY &&
697                            inp->inp_fport == 0 && inp->inp_lport == lport) {
698                                if (inp->inp_laddr.s_addr == laddr.s_addr)
699                                        goto found;
700                                else if (inp->inp_laddr.s_addr == INADDR_ANY)
701                                        local_wild = inp;
702                        }
703                }
704                if (local_wild != NULL) {
705                        inp = local_wild;
706                        goto found;
707                }
708        }
709        splx(s);
710        return (NULL);
711
712found:
713        /*
714         * Move PCB to head of this hash chain so that it can be
715         * found more quickly in the future.
716         * XXX - this is a pessimization on machines with few
717         * concurrent connections.
718         */
719        if (inp != head->lh_first) {
720                LIST_REMOVE(inp, inp_hash);
721                LIST_INSERT_HEAD(head, inp, inp_hash);
722        }
723        splx(s);
724        return (inp);
725}
726
727/*
728 * Insert PCB into hash chain. Must be called at splnet.
729 */
730static void
731in_pcbinshash(inp)
732        struct inpcb *inp;
733{
734        struct inpcbhead *head;
735
736        head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
737                 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
738
739        LIST_INSERT_HEAD(head, inp, inp_hash);
740}
741
742void
743in_pcbrehash(inp)
744        struct inpcb *inp;
745{
746        struct inpcbhead *head;
747        int s;
748
749        s = splnet();
750        LIST_REMOVE(inp, inp_hash);
751
752        head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
753                inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
754
755        LIST_INSERT_HEAD(head, inp, inp_hash);
756        splx(s);
757}
Note: See TracBrowser for help on using the repository browser.