OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet/] [in_pcb.c] - Blame information for rev 307

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet/in_pcb.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*
23
 * Copyright (c) 1982, 1986, 1991, 1993, 1995
24
 *      The Regents of the University of California.  All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. All advertising materials mentioning features or use of this software
35
 *    must display the following acknowledgement:
36
 *      This product includes software developed by the University of
37
 *      California, Berkeley and its contributors.
38
 * 4. Neither the name of the University nor the names of its contributors
39
 *    may be used to endorse or promote products derived from this software
40
 *    without specific prior written permission.
41
 *
42
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52
 * SUCH DAMAGE.
53
 *
54
 *      @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
55
 * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.59.2.17 2001/08/13 16:26:17 ume Exp $
56
 */
57
 
58
#include <sys/param.h>
59
#include <sys/malloc.h>
60
#include <sys/mbuf.h>
61
#include <sys/domain.h>
62
#include <sys/protosw.h>
63
#include <sys/socket.h>
64
#include <sys/socketvar.h>
65
 
66
#include <net/if.h>
67
#include <net/if_types.h>
68
#include <net/route.h>
69
 
70
#include <netinet/in.h>
71
#include <netinet/in_pcb.h>
72
#include <netinet/in_var.h>
73
#include <netinet/ip_var.h>
74
#ifdef INET6
75
#include <netinet/ip6.h>
76
#include <netinet6/ip6_var.h>
77
#endif /* INET6 */
78
 
79
#ifdef IPSEC
80
#include <netinet6/ipsec.h>
81
#include <netkey/key.h>
82
#endif /* IPSEC */
83
 
84
struct  in_addr zeroin_addr;
85
 
86
/*
87
 * These configure the range of local port addresses assigned to
88
 * "unspecified" outgoing connections/packets/whatever.
89
 */
90
int     ipport_lowfirstauto  = IPPORT_RESERVED - 1;     /* 1023 */
91
int     ipport_lowlastauto = IPPORT_RESERVEDSTART;      /* 600 */
92
int     ipport_firstauto = IPPORT_RESERVED;             /* 1024 */
93
int     ipport_lastauto  = IPPORT_USERRESERVED;         /* 5000 */
94
int     ipport_hifirstauto = IPPORT_HIFIRSTAUTO;        /* 49152 */
95
int     ipport_hilastauto  = IPPORT_HILASTAUTO;         /* 65535 */
96
 
97
 
98
/*
99
 * in_pcb.c: manage the Protocol Control Blocks.
100
 *
101
 * NOTE: It is assumed that most of these functions will be called at
102
 * splnet(). XXX - There are, unfortunately, a few exceptions to this
103
 * rule that should be fixed.
104
 */
105
 
106
/*
107
 * Allocate a PCB and associate it with the socket.
108
 */
109
int
110
in_pcballoc(so, pcbinfo, p)
111
        struct socket *so;
112
        struct inpcbinfo *pcbinfo;
113
        struct proc *p;
114
{
115
        register struct inpcb *inp;
116
#ifdef IPSEC
117
        int error;
118
#endif
119
 
120
        inp = zalloci(pcbinfo->ipi_zone);
121
        if (inp == NULL)
122
                return (ENOBUFS);
123
        bzero((caddr_t)inp, sizeof(*inp));
124
        inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
125
        inp->inp_pcbinfo = pcbinfo;
126
        inp->inp_socket = so;
127
#ifdef IPSEC
128
        error = ipsec_init_policy(so, &inp->inp_sp);
129
        if (error != 0) {
130
                zfreei(pcbinfo->ipi_zone, inp);
131
                return error;
132
        }
133
#endif /*IPSEC*/
134
#if defined(INET6)
135
        if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on)
136
                inp->inp_flags |= IN6P_IPV6_V6ONLY;
137
#endif
138
        LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
139
        pcbinfo->ipi_count++;
140
        so->so_pcb = (caddr_t)inp;
141
#ifdef INET6
142
        if (ip6_auto_flowlabel)
143
                inp->inp_flags |= IN6P_AUTOFLOWLABEL;
144
#endif
145
        return (0);
146
}
147
 
148
int
149
in_pcbbind(inp, nam, p)
150
        register struct inpcb *inp;
151
        struct sockaddr *nam;
152
        struct proc *p;
153
{
154
        register struct socket *so = inp->inp_socket;
155
        unsigned short *lastport;
156
        struct sockaddr_in *sin;
157
        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
158
        u_short lport = 0;
159
        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
160
 
161
        if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
162
                return (EADDRNOTAVAIL);
163
        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
164
                return (EINVAL);
165
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
166
                wild = 1;
167
        if (nam) {
168
                sin = (struct sockaddr_in *)nam;
169
        // HACK
170
        if (nam->sa_len == 0) nam->sa_len = sizeof(*sin);
171
        // HACK
172
                if (nam->sa_len != sizeof (*sin))
173
                        return (EINVAL);
174
#ifdef notdef
175
                /*
176
                 * We should check the family, but old programs
177
                 * incorrectly fail to initialize it.
178
                 */
179
                if (sin->sin_family != AF_INET)
180
                        return (EAFNOSUPPORT);
181
#endif
182
                lport = sin->sin_port;
183
                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
184
                        /*
185
                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
186
                         * allow complete duplication of binding if
187
                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
188
                         * and a multicast address is bound on both
189
                         * new and duplicated sockets.
190
                         */
191
                        if (so->so_options & SO_REUSEADDR)
192
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
193
                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
194
                        sin->sin_port = 0;               /* yech... */
195
                        if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
196
                                return (EADDRNOTAVAIL);
197
                }
198
                if (lport) {
199
                        struct inpcb *t;
200
 
201
                        /* GROSS */
202
                        t = in_pcblookup_local(pcbinfo, sin->sin_addr, lport, wild);
203
                        if (t &&
204
                            (reuseport & t->inp_socket->so_options) == 0) {
205
#if defined(INET6)
206
                                if (ntohl(sin->sin_addr.s_addr) !=
207
                                    INADDR_ANY ||
208
                                    ntohl(t->inp_laddr.s_addr) !=
209
                                    INADDR_ANY ||
210
                                    INP_SOCKAF(so) ==
211
                                    INP_SOCKAF(t->inp_socket))
212
#endif /* defined(INET6) */
213
                                return (EADDRINUSE);
214
                        }
215
                }
216
                inp->inp_laddr = sin->sin_addr;
217
        }
218
        if (lport == 0) {
219
                u_short first, last;
220
                int count;
221
 
222
                inp->inp_flags |= INP_ANONPORT;
223
 
224
                if (inp->inp_flags & INP_HIGHPORT) {
225
                        first = ipport_hifirstauto;     /* sysctl */
226
                        last  = ipport_hilastauto;
227
                        lastport = &pcbinfo->lasthi;
228
                } else if (inp->inp_flags & INP_LOWPORT) {
229
                        first = ipport_lowfirstauto;    /* 1023 */
230
                        last  = ipport_lowlastauto;     /* 600 */
231
                        lastport = &pcbinfo->lastlow;
232
                } else {
233
                        first = ipport_firstauto;       /* sysctl */
234
                        last  = ipport_lastauto;
235
                        lastport = &pcbinfo->lastport;
236
                }
237
                /*
238
                 * Simple check to ensure all ports are not used up causing
239
                 * a deadlock here.
240
                 *
241
                 * We split the two cases (up and down) so that the direction
242
                 * is not being tested on each round of the loop.
243
                 */
244
                if (first > last) {
245
                        /*
246
                         * counting down
247
                         */
248
                        count = first - last;
249
 
250
                        do {
251
                                if (count-- < 0) {       /* completely used? */
252
                                        inp->inp_laddr.s_addr = INADDR_ANY;
253
                                        return (EADDRNOTAVAIL);
254
                                }
255
                                --*lastport;
256
                                if (*lastport > first || *lastport < last)
257
                                        *lastport = first;
258
                                lport = htons(*lastport);
259
                        } while (in_pcblookup_local(pcbinfo,
260
                                 inp->inp_laddr, lport, wild));
261
                } else {
262
                        /*
263
                         * counting up
264
                         */
265
                        count = last - first;
266
 
267
                        do {
268
                                if (count-- < 0) {       /* completely used? */
269
                                        inp->inp_laddr.s_addr = INADDR_ANY;
270
                                        return (EADDRNOTAVAIL);
271
                                }
272
                                ++*lastport;
273
                                if (*lastport < first || *lastport > last)
274
                                        *lastport = first;
275
                                lport = htons(*lastport);
276
                        } while (in_pcblookup_local(pcbinfo,
277
                                 inp->inp_laddr, lport, wild));
278
                }
279
        }
280
        inp->inp_lport = lport;
281
        if (in_pcbinshash(inp) != 0) {
282
                inp->inp_laddr.s_addr = INADDR_ANY;
283
                inp->inp_lport = 0;
284
                return (EAGAIN);
285
        }
286
        return (0);
287
}
288
 
289
/*
290
 *   Transform old in_pcbconnect() into an inner subroutine for new
291
 *   in_pcbconnect(): Do some validity-checking on the remote
292
 *   address (in mbuf 'nam') and then determine local host address
293
 *   (i.e., which interface) to use to access that remote host.
294
 *
295
 *   This preserves definition of in_pcbconnect(), while supporting a
296
 *   slightly different version for T/TCP.  (This is more than
297
 *   a bit of a kludge, but cleaning up the internal interfaces would
298
 *   have forced minor changes in every protocol).
299
 */
300
 
301
int
302
in_pcbladdr(inp, nam, plocal_sin)
303
        register struct inpcb *inp;
304
        struct sockaddr *nam;
305
        struct sockaddr_in **plocal_sin;
306
{
307
        struct in_ifaddr *ia;
308
        register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
309
 
310
        if (nam->sa_len != sizeof (*sin))
311
                return (EINVAL);
312
        if (sin->sin_family != AF_INET)
313
                return (EAFNOSUPPORT);
314
        if (sin->sin_port == 0)
315
                return (EADDRNOTAVAIL);
316
        if (!TAILQ_EMPTY(&in_ifaddrhead)) {
317
                /*
318
                 * If the destination address is INADDR_ANY,
319
                 * use the primary local address.
320
                 * If the supplied address is INADDR_BROADCAST,
321
                 * and the primary interface supports broadcast,
322
                 * choose the broadcast address for that interface.
323
                 */
324
#define satosin(sa)     ((struct sockaddr_in *)(sa))
325
#define sintosa(sin)    ((struct sockaddr *)(sin))
326
#define ifatoia(ifa)    ((struct in_ifaddr *)(ifa))
327
                if (sin->sin_addr.s_addr == INADDR_ANY)
328
                    sin->sin_addr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
329
                else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
330
                  (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST))
331
                    sin->sin_addr = satosin(&TAILQ_FIRST(&in_ifaddrhead)->ia_broadaddr)->sin_addr;
332
        }
333
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
334
                register struct route *ro;
335
 
336
                ia = (struct in_ifaddr *)0;
337
                /*
338
                 * If route is known or can be allocated now,
339
                 * our src addr is taken from the i/f, else punt.
340
                 */
341
                ro = &inp->inp_route;
342
                if (ro->ro_rt &&
343
                    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
344
                        sin->sin_addr.s_addr ||
345
                    inp->inp_socket->so_options & SO_DONTROUTE)) {
346
                        RTFREE(ro->ro_rt);
347
                        ro->ro_rt = (struct rtentry *)0;
348
                }
349
                if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
350
                    (ro->ro_rt == (struct rtentry *)0 ||
351
                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
352
                        /* No route yet, so try to acquire one */
353
                        ro->ro_dst.sa_family = AF_INET;
354
                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
355
                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
356
                                sin->sin_addr;
357
                        rtalloc(ro);
358
                }
359
                /*
360
                 * If we found a route, use the address
361
                 * corresponding to the outgoing interface
362
                 * unless it is the loopback (in case a route
363
                 * to our address on another net goes to loopback).
364
                 */
365
                if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
366
                        ia = ifatoia(ro->ro_rt->rt_ifa);
367
                if (ia == 0) {
368
                        u_short fport = sin->sin_port;
369
 
370
                        sin->sin_port = 0;
371
                        ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
372
                        if (ia == 0)
373
                                ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
374
                        sin->sin_port = fport;
375
                        if (ia == 0)
376
                                ia = TAILQ_FIRST(&in_ifaddrhead);
377
                        if (ia == 0)
378
                                return (EADDRNOTAVAIL);
379
                }
380
                /*
381
                 * If the destination address is multicast and an outgoing
382
                 * interface has been set as a multicast option, use the
383
                 * address of that interface as our source address.
384
                 */
385
                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
386
                    inp->inp_moptions != NULL) {
387
                        struct ip_moptions *imo;
388
                        struct ifnet *ifp;
389
 
390
                        imo = inp->inp_moptions;
391
                        if (imo->imo_multicast_ifp != NULL) {
392
                                ifp = imo->imo_multicast_ifp;
393
                                TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
394
                                        if (ia->ia_ifp == ifp)
395
                                                break;
396
                                if (ia == 0)
397
                                        return (EADDRNOTAVAIL);
398
                        }
399
                }
400
        /*
401
         * Don't do pcblookup call here; return interface in plocal_sin
402
         * and exit to caller, that will do the lookup.
403
         */
404
                *plocal_sin = &ia->ia_addr;
405
 
406
        }
407
        return(0);
408
}
409
 
410
/*
411
 * Outer subroutine:
412
 * Connect from a socket to a specified address.
413
 * Both address and port must be specified in argument sin.
414
 * If don't have a local address for this socket yet,
415
 * then pick one.
416
 */
417
int
418
in_pcbconnect(inp, nam, p)
419
        register struct inpcb *inp;
420
        struct sockaddr *nam;
421
        struct proc *p;
422
{
423
        struct sockaddr_in *ifaddr;
424
        struct sockaddr_in *sin = (struct sockaddr_in *)nam;
425
        int error;
426
 
427
        /*
428
         *   Call inner routine, to assign local interface address.
429
         */
430
        if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
431
                return(error);
432
 
433
        if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
434
            inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
435
            inp->inp_lport, 0, NULL) != NULL) {
436
                return (EADDRINUSE);
437
        }
438
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
439
                if (inp->inp_lport == 0) {
440
                        error = in_pcbbind(inp, (struct sockaddr *)0, p);
441
                        if (error)
442
                            return (error);
443
                }
444
                inp->inp_laddr = ifaddr->sin_addr;
445
        }
446
        inp->inp_faddr = sin->sin_addr;
447
        inp->inp_fport = sin->sin_port;
448
        in_pcbrehash(inp);
449
#ifdef IPSEC
450
        if (inp->inp_socket->so_type == SOCK_STREAM)
451
                ipsec_pcbconn(inp->inp_sp);
452
#endif
453
        return (0);
454
}
455
 
456
void
457
in_pcbdisconnect(inp)
458
        struct inpcb *inp;
459
{
460
 
461
        inp->inp_faddr.s_addr = INADDR_ANY;
462
        inp->inp_fport = 0;
463
        in_pcbrehash(inp);
464
        if (inp->inp_socket->so_state & SS_NOFDREF)
465
                in_pcbdetach(inp);
466
#ifdef IPSEC
467
        ipsec_pcbdisconn(inp->inp_sp);
468
#endif
469
}
470
 
471
void
472
in_pcbdetach(inp)
473
        struct inpcb *inp;
474
{
475
        struct socket *so = inp->inp_socket;
476
        struct inpcbinfo *ipi = inp->inp_pcbinfo;
477
        struct rtentry *rt  = inp->inp_route.ro_rt;
478
 
479
#ifdef IPSEC
480
        ipsec4_delete_pcbpolicy(inp);
481
#endif /*IPSEC*/
482
        inp->inp_gencnt = ++ipi->ipi_gencnt;
483
        in_pcbremlists(inp);
484
        so->so_pcb = 0;
485
        sofree(so);
486
        if (inp->inp_options)
487
                (void)m_free(inp->inp_options);
488
        if (rt) {
489
                /*
490
                 * route deletion requires reference count to be <= zero
491
                 */
492
                if ((rt->rt_flags & RTF_DELCLONE) &&
493
                    (rt->rt_flags & RTF_WASCLONED) &&
494
                    (rt->rt_refcnt <= 1)) {
495
                        rt->rt_refcnt--;
496
                        rt->rt_flags &= ~RTF_UP;
497
                        rtrequest(RTM_DELETE, rt_key(rt),
498
                                  rt->rt_gateway, rt_mask(rt),
499
                                  rt->rt_flags, (struct rtentry **)0);
500
                }
501
                else
502
                        rtfree(rt);
503
        }
504
        ip_freemoptions(inp->inp_moptions);
505
        inp->inp_vflag = 0;
506
        zfreei(ipi->ipi_zone, inp);
507
}
508
 
509
/*
510
 * The calling convention of in_setsockaddr() and in_setpeeraddr() was
511
 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
512
 * in struct pr_usrreqs, so that protocols can just reference then directly
513
 * without the need for a wrapper function.  The socket must have a valid
514
 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
515
 * except through a kernel programming error, so it is acceptable to panic
516
 * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
517
 * because there actually /is/ a programming error somewhere... XXX)
518
 */
519
int
520
in_setsockaddr(so, nam)
521
        struct socket *so;
522
        struct sockaddr **nam;
523
{
524
        int s;
525
        register struct inpcb *inp;
526
        register struct sockaddr_in *sin;
527
 
528
        /*
529
         * Do the malloc first in case it blocks.
530
         */
531
        MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
532
                M_WAITOK | M_ZERO);
533
        sin->sin_family = AF_INET;
534
        sin->sin_len = sizeof(*sin);
535
 
536
        s = splnet();
537
        inp = sotoinpcb(so);
538
        if (!inp) {
539
                splx(s);
540
                free(sin, M_SONAME);
541
                return ECONNRESET;
542
        }
543
        sin->sin_port = inp->inp_lport;
544
        sin->sin_addr = inp->inp_laddr;
545
        splx(s);
546
 
547
        *nam = (struct sockaddr *)sin;
548
        return 0;
549
}
550
 
551
int
552
in_setpeeraddr(so, nam)
553
        struct socket *so;
554
        struct sockaddr **nam;
555
{
556
        int s;
557
        struct inpcb *inp;
558
        register struct sockaddr_in *sin;
559
 
560
        /*
561
         * Do the malloc first in case it blocks.
562
         */
563
        MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
564
                M_WAITOK | M_ZERO);
565
        sin->sin_family = AF_INET;
566
        sin->sin_len = sizeof(*sin);
567
 
568
        s = splnet();
569
        inp = sotoinpcb(so);
570
        if (!inp) {
571
                splx(s);
572
                free(sin, M_SONAME);
573
                return ECONNRESET;
574
        }
575
        sin->sin_port = inp->inp_fport;
576
        sin->sin_addr = inp->inp_faddr;
577
        splx(s);
578
 
579
        *nam = (struct sockaddr *)sin;
580
        return 0;
581
}
582
 
583
void
584
in_pcbnotifyall(head, faddr, _errno, notify)
585
        struct inpcbhead *head;
586
        struct in_addr faddr;
587
        void (*notify) __P((struct inpcb *, int));
588
{
589
        struct inpcb *inp, *ninp;
590
        int s;
591
 
592
        s = splnet();
593
        for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
594
                ninp = LIST_NEXT(inp, inp_list);
595
#ifdef INET6
596
                if ((inp->inp_vflag & INP_IPV4) == 0)
597
                        continue;
598
#endif
599
                if (inp->inp_faddr.s_addr != faddr.s_addr ||
600
                    inp->inp_socket == NULL)
601
                                continue;
602
                (*notify)(inp, _errno);
603
        }
604
        splx(s);
605
}
606
 
607
void
608
in_pcbpurgeif0(head, ifp)
609
        struct inpcb *head;
610
        struct ifnet *ifp;
611
{
612
        struct inpcb *inp;
613
        struct ip_moptions *imo;
614
        int i, gap;
615
 
616
        for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
617
                imo = inp->inp_moptions;
618
                if ((inp->inp_vflag & INP_IPV4) &&
619
                    imo != NULL) {
620
                        /*
621
                         * Unselect the outgoing interface if it is being
622
                         * detached.
623
                         */
624
                        if (imo->imo_multicast_ifp == ifp)
625
                                imo->imo_multicast_ifp = NULL;
626
 
627
                        /*
628
                         * Drop multicast group membership if we joined
629
                         * through the interface being detached.
630
                         */
631
                        for (i = 0, gap = 0; i < imo->imo_num_memberships;
632
                            i++) {
633
                                if (imo->imo_membership[i]->inm_ifp == ifp) {
634
                                        in_delmulti(imo->imo_membership[i]);
635
                                        gap++;
636
                                } else if (gap != 0)
637
                                        imo->imo_membership[i - gap] =
638
                                            imo->imo_membership[i];
639
                        }
640
                        imo->imo_num_memberships -= gap;
641
                }
642
        }
643
}
644
 
645
/*
646
 * Check for alternatives when higher level complains
647
 * about service problems.  For now, invalidate cached
648
 * routing information.  If the route was created dynamically
649
 * (by a redirect), time to try a default gateway again.
650
 */
651
void
652
in_losing(inp)
653
        struct inpcb *inp;
654
{
655
        register struct rtentry *rt;
656
        struct rt_addrinfo info;
657
 
658
        if ((rt = inp->inp_route.ro_rt)) {
659
                bzero((caddr_t)&info, sizeof(info));
660
                info.rti_info[RTAX_DST] =
661
                        (struct sockaddr *)&inp->inp_route.ro_dst;
662
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
663
                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
664
                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
665
                if (rt->rt_flags & RTF_DYNAMIC)
666
                        (void) rtrequest(RTM_DELETE, rt_key(rt),
667
                                rt->rt_gateway, rt_mask(rt), rt->rt_flags,
668
                                (struct rtentry **)0);
669
                inp->inp_route.ro_rt = 0;
670
                rtfree(rt);
671
                /*
672
                 * A new route can be allocated
673
                 * the next time output is attempted.
674
                 */
675
        }
676
}
677
 
678
/*
679
 * After a routing change, flush old routing
680
 * and allocate a (hopefully) better one.
681
 */
682
void
683
in_rtchange(inp, _errno)
684
        register struct inpcb *inp;
685
        int _errno;
686
{
687
        if (inp->inp_route.ro_rt) {
688
                rtfree(inp->inp_route.ro_rt);
689
                inp->inp_route.ro_rt = 0;
690
                /*
691
                 * A new route can be allocated the next time
692
                 * output is attempted.
693
                 */
694
        }
695
}
696
 
697
/*
698
 * Lookup a PCB based on the local address and port.
699
 */
700
struct inpcb *
701
in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
702
        struct inpcbinfo *pcbinfo;
703
        struct in_addr laddr;
704
        u_int lport_arg;
705
        int wild_okay;
706
{
707
        register struct inpcb *inp;
708
        int matchwild = 3, wildcard;
709
        u_short lport = lport_arg;
710
 
711
        if (!wild_okay) {
712
                struct inpcbhead *head;
713
                /*
714
                 * Look for an unconnected (wildcard foreign addr) PCB that
715
                 * matches the local address and port we're looking for.
716
                 */
717
                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
718
                LIST_FOREACH(inp, head, inp_hash) {
719
#ifdef INET6
720
                        if ((inp->inp_vflag & INP_IPV4) == 0)
721
                                continue;
722
#endif
723
                        if (inp->inp_faddr.s_addr == INADDR_ANY &&
724
                            inp->inp_laddr.s_addr == laddr.s_addr &&
725
                            inp->inp_lport == lport) {
726
                                /*
727
                                 * Found.
728
                                 */
729
                                return (inp);
730
                        }
731
                }
732
                /*
733
                 * Not found.
734
                 */
735
                return (NULL);
736
        } else {
737
                struct inpcbporthead *porthash;
738
                struct inpcbport *phd;
739
                struct inpcb *match = NULL;
740
                /*
741
                 * Best fit PCB lookup.
742
                 *
743
                 * First see if this local port is in use by looking on the
744
                 * port hash list.
745
                 */
746
                porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
747
                    pcbinfo->porthashmask)];
748
                LIST_FOREACH(phd, porthash, phd_hash) {
749
                        if (phd->phd_port == lport)
750
                                break;
751
                }
752
                if (phd != NULL) {
753
                        /*
754
                         * Port is in use by one or more PCBs. Look for best
755
                         * fit.
756
                         */
757
                        LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
758
                                wildcard = 0;
759
#ifdef INET6
760
                                if ((inp->inp_vflag & INP_IPV4) == 0)
761
                                        continue;
762
#endif
763
                                if (inp->inp_faddr.s_addr != INADDR_ANY)
764
                                        wildcard++;
765
                                if (inp->inp_laddr.s_addr != INADDR_ANY) {
766
                                        if (laddr.s_addr == INADDR_ANY)
767
                                                wildcard++;
768
                                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
769
                                                continue;
770
                                } else {
771
                                        if (laddr.s_addr != INADDR_ANY)
772
                                                wildcard++;
773
                                }
774
                                if (wildcard < matchwild) {
775
                                        match = inp;
776
                                        matchwild = wildcard;
777
                                        if (matchwild == 0) {
778
                                                break;
779
                                        }
780
                                }
781
                        }
782
                }
783
                return (match);
784
        }
785
}
786
 
787
/*
788
 * Lookup PCB in hash list.
789
 */
790
struct inpcb *
791
in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
792
                  ifp)
793
        struct inpcbinfo *pcbinfo;
794
        struct in_addr faddr, laddr;
795
        u_int fport_arg, lport_arg;
796
        int wildcard;
797
        struct ifnet *ifp;
798
{
799
        struct inpcbhead *head;
800
        register struct inpcb *inp;
801
        u_short fport = fport_arg, lport = lport_arg;
802
 
803
        /*
804
         * First look for an exact match.
805
         */
806
        head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
807
        LIST_FOREACH(inp, head, inp_hash) {
808
#ifdef INET6
809
                if ((inp->inp_vflag & INP_IPV4) == 0)
810
                        continue;
811
#endif
812
                if (inp->inp_faddr.s_addr == faddr.s_addr &&
813
                    inp->inp_laddr.s_addr == laddr.s_addr &&
814
                    inp->inp_fport == fport &&
815
                    inp->inp_lport == lport) {
816
                        /*
817
                         * Found.
818
                         */
819
                        return (inp);
820
                }
821
        }
822
        if (wildcard) {
823
                struct inpcb *local_wild = NULL;
824
#if defined(INET6)
825
                struct inpcb *local_wild_mapped = NULL;
826
#endif /* defined(INET6) */
827
 
828
                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
829
                LIST_FOREACH(inp, head, inp_hash) {
830
#ifdef INET6
831
                        if ((inp->inp_vflag & INP_IPV4) == 0)
832
                                continue;
833
#endif
834
                        if (inp->inp_faddr.s_addr == INADDR_ANY &&
835
                            inp->inp_lport == lport) {
836
#if defined(NFAITH) && NFAITH > 0
837
                                if (ifp && ifp->if_type == IFT_FAITH &&
838
                                    (inp->inp_flags & INP_FAITH) == 0)
839
                                        continue;
840
#endif
841
                                if (inp->inp_laddr.s_addr == laddr.s_addr)
842
                                        return (inp);
843
                                else if (inp->inp_laddr.s_addr == INADDR_ANY) {
844
#if defined(INET6)
845
                                        if (INP_CHECK_SOCKAF(inp->inp_socket,
846
                                                             AF_INET6))
847
                                                local_wild_mapped = inp;
848
                                        else
849
#endif /* defined(INET6) */
850
                                        local_wild = inp;
851
                                }
852
                        }
853
                }
854
#if defined(INET6)
855
                if (local_wild == NULL)
856
                        return (local_wild_mapped);
857
#endif /* defined(INET6) */
858
                return (local_wild);
859
        }
860
 
861
        /*
862
         * Not found.
863
         */
864
        return (NULL);
865
}
866
 
867
/*
868
 * Insert PCB onto various hash lists.
869
 */
870
int
871
in_pcbinshash(inp)
872
        struct inpcb *inp;
873
{
874
        struct inpcbhead *pcbhash;
875
        struct inpcbporthead *pcbporthash;
876
        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
877
        struct inpcbport *phd;
878
        u_int32_t hashkey_faddr;
879
 
880
#ifdef INET6
881
        if (inp->inp_vflag & INP_IPV6)
882
                hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
883
        else
884
#endif /* INET6 */
885
        hashkey_faddr = inp->inp_faddr.s_addr;
886
 
887
        pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
888
                 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
889
 
890
        pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
891
            pcbinfo->porthashmask)];
892
 
893
        /*
894
         * Go through port list and look for a head for this lport.
895
         */
896
        LIST_FOREACH(phd, pcbporthash, phd_hash) {
897
                if (phd->phd_port == inp->inp_lport)
898
                        break;
899
        }
900
        /*
901
         * If none exists, malloc one and tack it on.
902
         */
903
        if (phd == NULL) {
904
                MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
905
                if (phd == NULL) {
906
                        return (ENOBUFS); /* XXX */
907
                }
908
                phd->phd_port = inp->inp_lport;
909
                LIST_INIT(&phd->phd_pcblist);
910
                LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
911
        }
912
        inp->inp_phd = phd;
913
        LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
914
        LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
915
        return (0);
916
}
917
 
918
/*
919
 * Move PCB to the proper hash bucket when { faddr, fport } have  been
920
 * changed. NOTE: This does not handle the case of the lport changing (the
921
 * hashed port list would have to be updated as well), so the lport must
922
 * not change after in_pcbinshash() has been called.
923
 */
924
void
925
in_pcbrehash(inp)
926
        struct inpcb *inp;
927
{
928
        struct inpcbhead *head;
929
        u_int32_t hashkey_faddr;
930
 
931
#ifdef INET6
932
        if (inp->inp_vflag & INP_IPV6)
933
                hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
934
        else
935
#endif /* INET6 */
936
        hashkey_faddr = inp->inp_faddr.s_addr;
937
 
938
        head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
939
                inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
940
 
941
        LIST_REMOVE(inp, inp_hash);
942
        LIST_INSERT_HEAD(head, inp, inp_hash);
943
}
944
 
945
/*
946
 * Remove PCB from various lists.
947
 */
948
void
949
in_pcbremlists(inp)
950
        struct inpcb *inp;
951
{
952
        inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
953
        if (inp->inp_lport) {
954
                struct inpcbport *phd = inp->inp_phd;
955
 
956
                LIST_REMOVE(inp, inp_hash);
957
                LIST_REMOVE(inp, inp_portlist);
958
                if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
959
                        LIST_REMOVE(phd, phd_hash);
960
                        free(phd, M_PCB);
961
                }
962
        }
963
        LIST_REMOVE(inp, inp_list);
964
        inp->inp_pcbinfo->ipi_count--;
965
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.