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

Subversion Repositories openrisc_me

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

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      sys/netinet/in_pcb.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: in_pcb.c,v 1.36 1999/12/08 11:36:40 angelos Exp $     */
34
/*      $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $     */
35
 
36
/*
37
 * Copyright (c) 1982, 1986, 1991, 1993
38
 *      The Regents of the University of California.  All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. All advertising materials mentioning features or use of this software
49
 *    must display the following acknowledgement:
50
 *      This product includes software developed by the University of
51
 *      California, Berkeley and its contributors.
52
 * 4. Neither the name of the University nor the names of its contributors
53
 *    may be used to endorse or promote products derived from this software
54
 *    without specific prior written permission.
55
 *
56
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66
 * SUCH DAMAGE.
67
 *
68
 *      @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
69
 */
70
 
71
/*
72
%%% portions-copyright-nrl-95
73
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
74
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
75
Reserved. All rights under this copyright have been assigned to the US
76
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
77
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
78
software.
79
You should have received a copy of the license with this software. If you
80
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
81
*/
82
 
83
#include <sys/param.h>
84
#ifndef __ECOS
85
#include <sys/systm.h>
86
#endif
87
#include <sys/malloc.h>
88
#include <sys/mbuf.h>
89
#include <sys/protosw.h>
90
#include <sys/socket.h>
91
#include <sys/socketvar.h>
92
#include <sys/ioctl.h>
93
#include <sys/errno.h>
94
#ifdef __ECOS
95
#undef errno
96
#endif
97
#include <sys/time.h>
98
#ifndef __ECOS
99
#include <sys/proc.h>
100
#endif
101
#include <sys/domain.h>
102
 
103
#include <net/if.h>
104
#include <net/route.h>
105
 
106
#include <netinet/in.h>
107
#include <netinet/in_systm.h>
108
#include <netinet/ip.h>
109
#include <netinet/in_pcb.h>
110
#include <netinet/in_var.h>
111
#include <netinet/ip_var.h>
112
#ifndef __ECOS
113
#include <dev/rndvar.h>
114
#endif
115
 
116
#ifdef INET6
117
#include <netinet6/ip6_var.h>
118
#endif /* INET6 */
119
 
120
#ifdef IPSEC
121
#include <netinet/ip_ipsp.h>
122
 
123
extern int      check_ipsec_policy  __P((struct inpcb *, u_int32_t));
124
#endif
125
 
126
#if 0 /*KAME IPSEC*/
127
#include <netinet6/ipsec.h>
128
#include <netkey/key.h>
129
#include <netkey/key_debug.h>
130
#endif /* IPSEC */
131
 
132
struct  in_addr zeroin_addr;
133
 
134
extern int ipsec_auth_default_level;
135
extern int ipsec_esp_trans_default_level;
136
extern int ipsec_esp_network_default_level;
137
 
138
/*
139
 * These configure the range of local port addresses assigned to
140
 * "unspecified" outgoing connections/packets/whatever.
141
 */
142
int ipport_firstauto = IPPORT_RESERVED;         /* 1024 */
143
int ipport_lastauto = IPPORT_USERRESERVED;      /* 5000 */
144
int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;    /* 40000 */
145
int ipport_hilastauto = IPPORT_HILASTAUTO;      /* 44999 */
146
 
147
#define INPCBHASH(table, faddr, fport, laddr, lport) \
148
        &(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + \
149
        ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)]
150
 
151
#define IN6PCBHASH(table, faddr, fport, laddr, lport) \
152
        &(table)->inpt_hashtbl[(ntohl((faddr)->s6_addr32[0] ^ \
153
        (faddr)->s6_addr32[3]) + ntohs((fport)) + ntohs((lport))) & \
154
        (table->inpt_hash)]
155
 
156
void
157
in_pcbinit(table, hashsize)
158
        struct inpcbtable *table;
159
        int hashsize;
160
{
161
 
162
        CIRCLEQ_INIT(&table->inpt_queue);
163
        table->inpt_hashtbl = hashinit(hashsize, M_PCB, M_WAITOK, &table->inpt_hash);
164
        table->inpt_lastport = 0;
165
}
166
 
167
struct baddynamicports baddynamicports;
168
 
169
/*
170
 * Check if the specified port is invalid for dynamic allocation.
171
 */
172
int
173
in_baddynamic(port, proto)
174
        u_int16_t port;
175
        u_int16_t proto;
176
{
177
 
178
        if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
179
                return(0);
180
 
181
        switch (proto) {
182
        case IPPROTO_TCP:
183
                return (DP_ISSET(baddynamicports.tcp, port));
184
        case IPPROTO_UDP:
185
                return (DP_ISSET(baddynamicports.udp, port));
186
        default:
187
                return (0);
188
        }
189
}
190
 
191
int
192
in_pcballoc(so, v)
193
        struct socket *so;
194
        void *v;
195
{
196
        struct inpcbtable *table = v;
197
        register struct inpcb *inp;
198
        int s;
199
 
200
        MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT);
201
        if (inp == NULL)
202
                return (ENOBUFS);
203
        bzero((caddr_t)inp, sizeof(*inp));
204
        inp->inp_table = table;
205
        inp->inp_socket = so;
206
        inp->inp_seclevel[SL_AUTH] = ipsec_auth_default_level;
207
        inp->inp_seclevel[SL_ESP_TRANS] = ipsec_esp_trans_default_level;
208
        inp->inp_seclevel[SL_ESP_NETWORK] = ipsec_esp_network_default_level;
209
        s = splnet();
210
        CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
211
        LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport,
212
            &inp->inp_laddr, inp->inp_lport), inp, inp_hash);
213
        splx(s);
214
        so->so_pcb = inp;
215
        inp->inp_hops = -1;
216
 
217
#ifdef INET6
218
        /*
219
         * Small change in this function to set the INP_IPV6 flag so routines
220
         * outside pcb-specific routines don't need to use sotopf(), and all
221
         * of it's pointer chasing, later.
222
         */
223
        if (sotopf(so) == PF_INET6)
224
                inp->inp_flags = INP_IPV6;
225
        inp->inp_csumoffset = -1;
226
#endif /* INET6 */
227
        return (0);
228
}
229
 
230
int
231
in_pcbbind(v, nam)
232
        register void *v;
233
        struct mbuf *nam;
234
{
235
        register struct inpcb *inp = v;
236
        register struct socket *so = inp->inp_socket;
237
        register struct inpcbtable *table = inp->inp_table;
238
        u_int16_t *lastport = &inp->inp_table->inpt_lastport;
239
        register struct sockaddr_in *sin;
240
#ifndef __ECOS
241
        struct proc *p = curproc;               /* XXX */
242
        int error;
243
#endif
244
        u_int16_t lport = 0;
245
        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
246
 
247
#ifdef INET6
248
        if (sotopf(so) == PF_INET6)
249
                return in6_pcbbind(inp, nam);
250
#endif /* INET6 */
251
 
252
        if (in_ifaddr.tqh_first == 0)
253
                return (EADDRNOTAVAIL);
254
        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
255
                return (EINVAL);
256
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
257
            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
258
             (so->so_options & SO_ACCEPTCONN) == 0))
259
                wild = INPLOOKUP_WILDCARD;
260
        if (nam) {
261
                sin = mtod(nam, struct sockaddr_in *);
262
                if (nam->m_len != sizeof (*sin))
263
                        return (EINVAL);
264
#ifdef notdef
265
                /*
266
                 * We should check the family, but old programs
267
                 * incorrectly fail to initialize it.
268
                 */
269
                if (sin->sin_family != AF_INET)
270
                        return (EAFNOSUPPORT);
271
#endif
272
                lport = sin->sin_port;
273
                if (IN_MULTICAST(sin->sin_addr.s_addr)) {
274
                        /*
275
                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
276
                         * allow complete duplication of binding if
277
                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
278
                         * and a multicast address is bound on both
279
                         * new and duplicated sockets.
280
                         */
281
                        if (so->so_options & SO_REUSEADDR)
282
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
283
                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
284
                        sin->sin_port = 0;               /* yech... */
285
                        if (in_iawithaddr(sin->sin_addr, NULL) == 0)
286
                                return (EADDRNOTAVAIL);
287
                }
288
                if (lport) {
289
                        struct inpcb *t;
290
 
291
                        /* GROSS */
292
#ifndef __ECOS
293
                        if (ntohs(lport) < IPPORT_RESERVED &&
294
                            (error = suser(p->p_ucred, &p->p_acflag)))
295
                                return (EACCES);
296
#endif
297
                        if (so->so_euid) {
298
                                t = in_pcblookup(table, &zeroin_addr, 0,
299
                                    &sin->sin_addr, lport, INPLOOKUP_WILDCARD);
300
                                if (t && (so->so_euid != t->inp_socket->so_euid))
301
                                        return (EADDRINUSE);
302
                        }
303
                        t = in_pcblookup(table, &zeroin_addr, 0,
304
                            &sin->sin_addr, lport, wild);
305
                        if (t && (reuseport & t->inp_socket->so_options) == 0)
306
                                return (EADDRINUSE);
307
                }
308
                inp->inp_laddr = sin->sin_addr;
309
        }
310
        if (lport == 0) {
311
                u_int16_t first, last, old = 0;
312
                int count;
313
                int loopcount = 0;
314
 
315
                if (inp->inp_flags & INP_HIGHPORT) {
316
                        first = ipport_hifirstauto;     /* sysctl */
317
                        last = ipport_hilastauto;
318
                } else if (inp->inp_flags & INP_LOWPORT) {
319
#ifndef __ECOS
320
                        if ((error = suser(p->p_ucred, &p->p_acflag)))
321
                                return (EACCES);
322
#endif
323
                        first = IPPORT_RESERVED-1; /* 1023 */
324
                        last = 600;                /* not IPPORT_RESERVED/2 */
325
                } else {
326
                        first = ipport_firstauto;       /* sysctl */
327
                        last  = ipport_lastauto;
328
                }
329
 
330
                /*
331
                 * Simple check to ensure all ports are not used up causing
332
                 * a deadlock here.
333
                 *
334
                 * We split the two cases (up and down) so that the direction
335
                 * is not being tested on each round of the loop.
336
                 */
337
 
338
portloop:
339
                if (first > last) {
340
                        /*
341
                         * counting down
342
                         */
343
                        if (loopcount == 0) {    /* only do this once. */
344
                                old = first;
345
                                first -= (arc4random() % (first - last));
346
                        }
347
                        count = first - last;
348
                        *lastport = first;              /* restart each time */
349
 
350
                        do {
351
                                if (count-- <= 0) {      /* completely used? */
352
                                        if (loopcount == 0) {
353
                                                last = old;
354
                                                loopcount++;
355
                                                goto portloop;
356
                                        }
357
                                        return (EADDRNOTAVAIL);
358
                                }
359
                                --*lastport;
360
                                if (*lastport > first || *lastport < last)
361
                                        *lastport = first;
362
                                lport = htons(*lastport);
363
                        } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
364
                            in_pcblookup(table, &zeroin_addr, 0,
365
                            &inp->inp_laddr, lport, wild));
366
                } else {
367
                        /*
368
                         * counting up
369
                         */
370
                        if (loopcount == 0) {    /* only do this once. */
371
                                old = first;
372
                                first += (arc4random() % (last - first));
373
                        }
374
                        count = last - first;
375
                        *lastport = first;              /* restart each time */
376
 
377
                        do {
378
                                if (count-- <= 0) {      /* completely used? */
379
                                        if (loopcount == 0) {
380
                                                first = old;
381
                                                loopcount++;
382
                                                goto portloop;
383
                                        }
384
                                        return (EADDRNOTAVAIL);
385
                                }
386
                                ++*lastport;
387
                                if (*lastport < first || *lastport > last)
388
                                        *lastport = first;
389
                                lport = htons(*lastport);
390
                        } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
391
                            in_pcblookup(table, &zeroin_addr, 0,
392
                            &inp->inp_laddr, lport, wild));
393
                }
394
        }
395
        inp->inp_lport = lport;
396
        in_pcbrehash(inp);
397
        return (0);
398
}
399
 
400
/*
401
 * Connect from a socket to a specified address.
402
 * Both address and port must be specified in argument sin.
403
 * If don't have a local address for this socket yet,
404
 * then pick one.
405
 */
406
int
407
in_pcbconnect(v, nam)
408
        register void *v;
409
        struct mbuf *nam;
410
{
411
        register struct inpcb *inp = v;
412
        struct sockaddr_in *ifaddr = NULL;
413
        register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
414
 
415
#ifdef INET6
416
        if (sotopf(inp->inp_socket) == PF_INET6)
417
                return (in6_pcbconnect(inp, nam));
418
#endif /* INET6 */
419
 
420
        if (nam->m_len != sizeof (*sin))
421
                return (EINVAL);
422
        if (sin->sin_family != AF_INET)
423
                return (EAFNOSUPPORT);
424
        if (sin->sin_port == 0)
425
                return (EADDRNOTAVAIL);
426
        if (in_ifaddr.tqh_first != 0) {
427
                /*
428
                 * If the destination address is INADDR_ANY,
429
                 * use the primary local address.
430
                 * If the supplied address is INADDR_BROADCAST,
431
                 * and the primary interface supports broadcast,
432
                 * choose the broadcast address for that interface.
433
                 */
434
                if (sin->sin_addr.s_addr == INADDR_ANY)
435
                        sin->sin_addr = in_ifaddr.tqh_first->ia_addr.sin_addr;
436
                else if (sin->sin_addr.s_addr == INADDR_BROADCAST &&
437
                  (in_ifaddr.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
438
                        sin->sin_addr = in_ifaddr.tqh_first->ia_broadaddr.sin_addr;
439
        }
440
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
441
#if 0
442
                register struct route *ro;
443
                struct sockaddr_in *sin2;
444
                struct in_ifaddr *ia;
445
 
446
                ia = (struct in_ifaddr *)0;
447
                /*
448
                 * If route is known or can be allocated now,
449
                 * our src addr is taken from the i/f, else punt.
450
                 */
451
                ro = &inp->inp_route;
452
                if (ro->ro_rt &&
453
                    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
454
                        sin->sin_addr.s_addr ||
455
                    inp->inp_socket->so_options & SO_DONTROUTE)) {
456
                        RTFREE(ro->ro_rt);
457
                        ro->ro_rt = (struct rtentry *)0;
458
                }
459
                if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
460
                    (ro->ro_rt == (struct rtentry *)0 ||
461
                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
462
                        /* No route yet, so try to acquire one */
463
                        ro->ro_dst.sa_family = AF_INET;
464
                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
465
                        satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
466
                        rtalloc(ro);
467
 
468
                        /*
469
                         * It is important to bzero out the rest of the
470
                         * struct sockaddr_in when mixing v6 & v4!
471
                         */
472
                        sin2 = (struct sockaddr_in *)&ro->ro_dst;
473
                        bzero(sin2->sin_zero, sizeof(sin2->sin_zero));
474
                }
475
                /*
476
                 * If we found a route, use the address
477
                 * corresponding to the outgoing interface
478
                 * unless it is the loopback (in case a route
479
                 * to our address on another net goes to loopback).
480
                 */
481
                if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
482
                        ia = ifatoia(ro->ro_rt->rt_ifa);
483
                if (ia == 0) {
484
                        u_int16_t fport = sin->sin_port;
485
 
486
                        sin->sin_port = 0;
487
                        ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
488
                        if (ia == 0)
489
                                ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
490
                        sin->sin_port = fport;
491
                        if (ia == 0)
492
                                ia = in_ifaddr.tqh_first;
493
                        if (ia == 0)
494
                                return (EADDRNOTAVAIL);
495
                }
496
                /*
497
                 * If the destination address is multicast and an outgoing
498
                 * interface has been set as a multicast option, use the
499
                 * address of that interface as our source address.
500
                 */
501
                if (IN_MULTICAST(sin->sin_addr.s_addr) &&
502
#ifdef INET6
503
                    inp->inp_moptions != NULL &&
504
                    !(inp->inp_flags & INP_IPV6_MCAST))
505
#else
506
                    inp->inp_moptions != NULL)
507
#endif
508
                {
509
                        struct ip_moptions *imo;
510
                        struct ifnet *ifp;
511
 
512
                        imo = inp->inp_moptions;
513
                        if (imo->imo_multicast_ifp != NULL) {
514
                                ifp = imo->imo_multicast_ifp;
515
                                for (ia = in_ifaddr.tqh_first; ia != 0;
516
                                    ia = ia->ia_list.tqe_next)
517
                                        if (ia->ia_ifp == ifp)
518
                                                break;
519
                                if (ia == 0)
520
                                        return (EADDRNOTAVAIL);
521
                        }
522
                }
523
                ifaddr = satosin(&ia->ia_addr);
524
#else
525
                int error;
526
                ifaddr = in_selectsrc(sin, &inp->inp_route,
527
                        inp->inp_socket->so_options, inp->inp_moptions, &error);
528
                if (ifaddr == NULL) {
529
                        if (error == 0)
530
                                error = EADDRNOTAVAIL;
531
                        return error;
532
                }
533
#endif
534
        }
535
        if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
536
            inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
537
            inp->inp_lport) != 0)
538
                return (EADDRINUSE);
539
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
540
                if (inp->inp_lport == 0 &&
541
                    in_pcbbind(inp, (struct mbuf *)0) == EADDRNOTAVAIL)
542
                        return (EADDRNOTAVAIL);
543
                inp->inp_laddr = ifaddr->sin_addr;
544
        }
545
        inp->inp_faddr = sin->sin_addr;
546
        inp->inp_fport = sin->sin_port;
547
        in_pcbrehash(inp);
548
#ifdef IPSEC
549
        return (check_ipsec_policy(inp, 0));
550
#else
551
        return (0);
552
#endif
553
}
554
 
555
void
556
in_pcbdisconnect(v)
557
        void *v;
558
{
559
        struct inpcb *inp = v;
560
 
561
#ifdef INET6
562
        if (sotopf(inp->inp_socket) == PF_INET6) {
563
                inp->inp_faddr6 = in6addr_any;
564
                /* Disconnected AF_INET6 sockets cannot be "v4-mapped" */
565
                inp->inp_flags &= ~INP_IPV6_MAPPED;
566
        } else
567
#endif
568
                inp->inp_faddr.s_addr = INADDR_ANY;
569
 
570
        inp->inp_fport = 0;
571
        in_pcbrehash(inp);
572
        if (inp->inp_socket->so_state & SS_NOFDREF)
573
                in_pcbdetach(inp);
574
}
575
 
576
void
577
in_pcbdetach(v)
578
        void *v;
579
{
580
        struct inpcb *inp = v;
581
        struct socket *so = inp->inp_socket;
582
        int s;
583
 
584
#if 0 /*KAME IPSEC*/
585
        if (so->so_pcb) {
586
                KEYDEBUG(KEYDEBUG_KEY_STAMP,
587
                        printf("DP call free SO=%p from in_pcbdetach\n", so));
588
                key_freeso(so);
589
        }
590
        ipsec4_delete_pcbpolicy(inp);
591
#endif /*IPSEC*/
592
        so->so_pcb = 0;
593
        sofree(so);
594
        if (inp->inp_options)
595
                (void)m_freem(inp->inp_options);
596
        if (inp->inp_route.ro_rt)
597
                rtfree(inp->inp_route.ro_rt);
598
#ifdef INET6
599
        if (inp->inp_flags & INP_IPV6)
600
                ip6_freemoptions(inp->inp_moptions6);
601
        else
602
#endif
603
                ip_freemoptions(inp->inp_moptions);
604
#ifdef IPSEC
605
        /* XXX IPsec cleanup here */
606
        s = spltdb();
607
        if (inp->inp_tdb)
608
                TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next);
609
        splx(s);
610
#endif
611
        s = splnet();
612
        LIST_REMOVE(inp, inp_hash);
613
        CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
614
        splx(s);
615
        FREE(inp, M_PCB);
616
}
617
 
618
void
619
in_setsockaddr(inp, nam)
620
        register struct inpcb *inp;
621
        struct mbuf *nam;
622
{
623
        register struct sockaddr_in *sin;
624
 
625
        nam->m_len = sizeof (*sin);
626
        sin = mtod(nam, struct sockaddr_in *);
627
        bzero((caddr_t)sin, sizeof (*sin));
628
        sin->sin_family = AF_INET;
629
        sin->sin_len = sizeof(*sin);
630
        sin->sin_port = inp->inp_lport;
631
        sin->sin_addr = inp->inp_laddr;
632
}
633
 
634
void
635
in_setpeeraddr(inp, nam)
636
        struct inpcb *inp;
637
        struct mbuf *nam;
638
{
639
        register struct sockaddr_in *sin;
640
 
641
#ifdef INET6
642
        if (sotopf(inp->inp_socket) == PF_INET6)
643
                in6_setpeeraddr(inp, nam);
644
#endif /* INET6 */
645
 
646
        nam->m_len = sizeof (*sin);
647
        sin = mtod(nam, struct sockaddr_in *);
648
        bzero((caddr_t)sin, sizeof (*sin));
649
        sin->sin_family = AF_INET;
650
        sin->sin_len = sizeof(*sin);
651
        sin->sin_port = inp->inp_fport;
652
        sin->sin_addr = inp->inp_faddr;
653
}
654
 
655
/*
656
 * Pass some notification to all connections of a protocol
657
 * associated with address dst.  The local address and/or port numbers
658
 * may be specified to limit the search.  The "usual action" will be
659
 * taken, depending on the ctlinput cmd.  The caller must filter any
660
 * cmds that are uninteresting (e.g., no error in the map).
661
 * Call the protocol specific routine (if any) to report
662
 * any errors for each matching socket.
663
 *
664
 * Must be called at splsoftnet.
665
 */
666
void
667
in_pcbnotify(table, dst, fport_arg, laddr, lport_arg, errno, notify)
668
        struct inpcbtable *table;
669
        struct sockaddr *dst;
670
        u_int fport_arg, lport_arg;
671
        struct in_addr laddr;
672
        int errno;
673
        void (*notify) __P((struct inpcb *, int));
674
{
675
        register struct inpcb *inp, *oinp;
676
        struct in_addr faddr;
677
        u_int16_t fport = fport_arg, lport = lport_arg;
678
 
679
#ifdef INET6
680
        /*
681
         * See in6_pcbnotify() for IPv6 codepath.  By the time this
682
         * gets called, the addresses passed are either definitely IPv4 or
683
         * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses.
684
         */
685
#endif /* INET6 */
686
 
687
        if (dst->sa_family != AF_INET)
688
                return;
689
        faddr = satosin(dst)->sin_addr;
690
        if (faddr.s_addr == INADDR_ANY)
691
                return;
692
 
693
        for (inp = table->inpt_queue.cqh_first;
694
            inp != (struct inpcb *)&table->inpt_queue;) {
695
                if (inp->inp_faddr.s_addr != faddr.s_addr ||
696
                    inp->inp_socket == 0 ||
697
                    inp->inp_fport != fport ||
698
                    inp->inp_lport != lport ||
699
                    inp->inp_laddr.s_addr != laddr.s_addr) {
700
                        inp = inp->inp_queue.cqe_next;
701
                        continue;
702
                }
703
                oinp = inp;
704
                inp = inp->inp_queue.cqe_next;
705
                if (notify)
706
                        (*notify)(oinp, errno);
707
        }
708
}
709
 
710
void
711
in_pcbnotifyall(table, dst, errno, notify)
712
        struct inpcbtable *table;
713
        struct sockaddr *dst;
714
        int errno;
715
        void (*notify) __P((struct inpcb *, int));
716
{
717
        register struct inpcb *inp, *oinp;
718
        struct in_addr faddr;
719
 
720
#ifdef INET6
721
        /*
722
         * See in6_pcbnotify() for IPv6 codepath.  By the time this
723
         * gets called, the addresses passed are either definitely IPv4 or
724
         * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses.
725
         */
726
#endif /* INET6 */
727
 
728
        if (dst->sa_family != AF_INET)
729
                return;
730
        faddr = satosin(dst)->sin_addr;
731
        if (faddr.s_addr == INADDR_ANY)
732
                return;
733
 
734
        for (inp = table->inpt_queue.cqh_first;
735
            inp != (struct inpcb *)&table->inpt_queue;) {
736
                if (inp->inp_faddr.s_addr != faddr.s_addr ||
737
                    inp->inp_socket == 0) {
738
                        inp = inp->inp_queue.cqe_next;
739
                        continue;
740
                }
741
                oinp = inp;
742
                inp = inp->inp_queue.cqe_next;
743
                if (notify)
744
                        (*notify)(oinp, errno);
745
        }
746
}
747
 
748
/*
749
 * Check for alternatives when higher level complains
750
 * about service problems.  For now, invalidate cached
751
 * routing information.  If the route was created dynamically
752
 * (by a redirect), time to try a default gateway again.
753
 */
754
void
755
in_losing(inp)
756
        struct inpcb *inp;
757
{
758
        register struct rtentry *rt;
759
        struct rt_addrinfo info;
760
 
761
        if ((rt = inp->inp_route.ro_rt)) {
762
                inp->inp_route.ro_rt = 0;
763
                bzero((caddr_t)&info, sizeof(info));
764
                info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst;
765
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
766
                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
767
                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
768
                if (rt->rt_flags & RTF_DYNAMIC)
769
                        (void) rtrequest(RTM_DELETE, rt_key(rt),
770
                                rt->rt_gateway, rt_mask(rt), rt->rt_flags,
771
                                (struct rtentry **)0);
772
                else
773
                /*
774
                 * A new route can be allocated
775
                 * the next time output is attempted.
776
                 */
777
                        rtfree(rt);
778
        }
779
}
780
 
781
/*
782
 * After a routing change, flush old routing
783
 * and allocate a (hopefully) better one.
784
 */
785
void
786
in_rtchange(inp, errno)
787
        register struct inpcb *inp;
788
        int errno;
789
{
790
        if (inp->inp_route.ro_rt) {
791
                rtfree(inp->inp_route.ro_rt);
792
                inp->inp_route.ro_rt = 0;
793
                /*
794
                 * A new route can be allocated the next time
795
                 * output is attempted.
796
                 */
797
        }
798
}
799
 
800
struct inpcb *
801
in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags)
802
        struct inpcbtable *table;
803
        void *faddrp, *laddrp;
804
        u_int fport_arg, lport_arg;
805
        int flags;
806
{
807
        register struct inpcb *inp, *match = 0;
808
        int matchwild = 3, wildcard;
809
        u_int16_t fport = fport_arg, lport = lport_arg;
810
        struct in_addr faddr = *(struct in_addr *)faddrp;
811
        struct in_addr laddr = *(struct in_addr *)laddrp;
812
 
813
        for (inp = table->inpt_queue.cqh_first;
814
            inp != (struct inpcb *)&table->inpt_queue;
815
            inp = inp->inp_queue.cqe_next) {
816
                if (inp->inp_lport != lport)
817
                        continue;
818
                wildcard = 0;
819
#ifdef INET6
820
                if (flags & INPLOOKUP_IPV6) {
821
                        struct in6_addr *laddr6 = (struct in6_addr *)laddrp;
822
                        struct in6_addr *faddr6 = (struct in6_addr *)faddrp;
823
 
824
                        /*
825
                         * Always skip AF_INET sockets when looking
826
                         * for AF_INET6 addresses.  The only problem
827
                         * with this comes if the PF_INET6 addresses
828
                         * are v4-mapped addresses.  From what I've
829
                         * been able to see, none of the callers cause
830
                         * such a situation to occur.  If such a
831
                         * situation DID occur, then it is possible to
832
                         * miss a matching PCB.
833
                         */
834
                        if (!(inp->inp_flags & INP_IPV6))
835
                                continue;
836
 
837
                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
838
                                if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
839
                                        wildcard++;
840
                                else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6))
841
                                        continue;
842
                        } else {
843
                                if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
844
                                        wildcard++;
845
                        }
846
 
847
                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
848
                                if (IN6_IS_ADDR_UNSPECIFIED(faddr6))
849
                                        wildcard++;
850
                                else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
851
                                    faddr6) || inp->inp_fport != fport)
852
                                        continue;
853
                        } else {
854
                                if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
855
                                        wildcard++;
856
                        }
857
                } else
858
#endif /* INET6 */
859
                {
860
                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
861
                                if (faddr.s_addr == INADDR_ANY)
862
                                        wildcard++;
863
                                else if (inp->inp_faddr.s_addr != faddr.s_addr ||
864
                                    inp->inp_fport != fport)
865
                                        continue;
866
                        } else {
867
                                if (faddr.s_addr != INADDR_ANY)
868
                                        wildcard++;
869
                        }
870
                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
871
                                if (laddr.s_addr == INADDR_ANY)
872
                                        wildcard++;
873
                                else if (inp->inp_laddr.s_addr != laddr.s_addr)
874
                                        continue;
875
                        } else {
876
                                if (laddr.s_addr != INADDR_ANY)
877
                                        wildcard++;
878
                        }
879
                }
880
                if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) &&
881
                    wildcard < matchwild) {
882
                        match = inp;
883
                        if ((matchwild = wildcard) == 0)
884
                                break;
885
                }
886
        }
887
        return (match);
888
}
889
 
890
struct sockaddr_in *
891
in_selectsrc(sin, ro, soopts, mopts, errorp)
892
        struct sockaddr_in *sin;
893
        struct route *ro;
894
        int soopts;
895
        struct ip_moptions *mopts;
896
        int *errorp;
897
{
898
        struct sockaddr_in *sin2;
899
        struct in_ifaddr *ia;
900
 
901
        ia = (struct in_ifaddr *)0;
902
        /*
903
         * If route is known or can be allocated now,
904
         * our src addr is taken from the i/f, else punt.
905
         */
906
        if (ro->ro_rt &&
907
            (satosin(&ro->ro_dst)->sin_addr.s_addr !=
908
                sin->sin_addr.s_addr ||
909
            soopts & SO_DONTROUTE)) {
910
                RTFREE(ro->ro_rt);
911
                ro->ro_rt = (struct rtentry *)0;
912
        }
913
        if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/
914
            (ro->ro_rt == (struct rtentry *)0 ||
915
            ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
916
                /* No route yet, so try to acquire one */
917
                ro->ro_dst.sa_family = AF_INET;
918
                ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
919
                satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
920
                rtalloc(ro);
921
 
922
                /*
923
                 * It is important to bzero out the rest of the
924
                 * struct sockaddr_in when mixing v6 & v4!
925
                 */
926
                sin2 = (struct sockaddr_in *)&ro->ro_dst;
927
                bzero(sin2->sin_zero, sizeof(sin2->sin_zero));
928
        }
929
        /*
930
         * If we found a route, use the address
931
         * corresponding to the outgoing interface
932
         * unless it is the loopback (in case a route
933
         * to our address on another net goes to loopback).
934
         */
935
        if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
936
                ia = ifatoia(ro->ro_rt->rt_ifa);
937
        if (ia == 0) {
938
                u_int16_t fport = sin->sin_port;
939
 
940
                sin->sin_port = 0;
941
                ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
942
                if (ia == 0)
943
                        ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
944
                sin->sin_port = fport;
945
                if (ia == 0)
946
                        ia = in_ifaddr.tqh_first;
947
                if (ia == 0) {
948
                        *errorp = EADDRNOTAVAIL;
949
                        return NULL;
950
                }
951
        }
952
        /*
953
         * If the destination address is multicast and an outgoing
954
         * interface has been set as a multicast option, use the
955
         * address of that interface as our source address.
956
         */
957
        if (IN_MULTICAST(sin->sin_addr.s_addr) &&
958
#if 0 /*def INET6*/
959
            mopts != NULL &&
960
            !(inp->inp_flags & INP_IPV6_MCAST))
961
#else
962
            mopts != NULL)
963
#endif
964
        {
965
                struct ip_moptions *imo;
966
                struct ifnet *ifp;
967
 
968
                imo = mopts;
969
                if (imo->imo_multicast_ifp != NULL) {
970
                        ifp = imo->imo_multicast_ifp;
971
                        for (ia = in_ifaddr.tqh_first; ia != 0;
972
                            ia = ia->ia_list.tqe_next)
973
                                if (ia->ia_ifp == ifp)
974
                                        break;
975
                        if (ia == 0) {
976
                                *errorp = EADDRNOTAVAIL;
977
                                return NULL;
978
                        }
979
                }
980
        }
981
        return satosin(&ia->ia_addr);
982
}
983
 
984
void
985
in_pcbrehash(inp)
986
        struct inpcb *inp;
987
{
988
        struct inpcbtable *table = inp->inp_table;
989
        int s;
990
 
991
        s = splnet();
992
        LIST_REMOVE(inp, inp_hash);
993
#ifdef INET6
994
        if (inp->inp_flags & INP_IPV6) {
995
                LIST_INSERT_HEAD(IN6PCBHASH(table, &inp->inp_faddr6,
996
                    inp->inp_fport, &inp->inp_laddr6, inp->inp_lport),
997
                    inp, inp_hash);
998
        } else {
999
#endif /* INET6 */
1000
                LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr,
1001
                    inp->inp_fport, &inp->inp_laddr, inp->inp_lport),
1002
                    inp, inp_hash);
1003
#ifdef INET6
1004
        }
1005
#endif /* INET6 */
1006
        splx(s);
1007
}
1008
 
1009
#ifdef DIAGNOSTIC
1010
int     in_pcbnotifymiss = 0;
1011
#endif
1012
 
1013
struct inpcb *
1014
in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
1015
        struct inpcbtable *table;
1016
        struct in_addr faddr, laddr;
1017
        u_int fport_arg, lport_arg;
1018
{
1019
        struct inpcbhead *head;
1020
        register struct inpcb *inp;
1021
        u_int16_t fport = fport_arg, lport = lport_arg;
1022
 
1023
        head = INPCBHASH(table, &faddr, fport, &laddr, lport);
1024
        for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1025
                if (inp->inp_faddr.s_addr == faddr.s_addr &&
1026
                    inp->inp_fport == fport &&
1027
                    inp->inp_lport == lport &&
1028
                    inp->inp_laddr.s_addr == laddr.s_addr) {
1029
                        /*
1030
                         * Move this PCB to the head of hash chain so that
1031
                         * repeated accesses are quicker.  This is analogous to
1032
                         * the historic single-entry PCB cache.
1033
                         */
1034
                        if (inp != head->lh_first) {
1035
                                LIST_REMOVE(inp, inp_hash);
1036
                                LIST_INSERT_HEAD(head, inp, inp_hash);
1037
                        }
1038
                        break;
1039
                }
1040
        }
1041
#ifdef DIAGNOSTIC
1042
        if (inp == NULL && in_pcbnotifymiss) {
1043
                printf("in_pcbhashlookup: faddr=%08x fport=%d laddr=%08x lport=%d\n",
1044
                    ntohl(faddr.s_addr), ntohs(fport),
1045
                    ntohl(laddr.s_addr), ntohs(lport));
1046
        }
1047
#endif
1048
        return (inp);
1049
}
1050
 
1051
#ifdef INET6
1052
struct inpcb *
1053
in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
1054
        struct inpcbtable *table;
1055
        struct in6_addr *faddr, *laddr;
1056
        u_int fport_arg, lport_arg;
1057
{
1058
        struct inpcbhead *head;
1059
        register struct inpcb *inp;
1060
        u_int16_t fport = fport_arg, lport = lport_arg;
1061
 
1062
        head = IN6PCBHASH(table, faddr, fport, laddr, lport);
1063
        for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1064
                if (!(inp->inp_flags & INP_IPV6))
1065
                        continue;
1066
                if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) &&
1067
                    inp->inp_fport == fport && inp->inp_lport == lport &&
1068
                    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr)) {
1069
                        /*
1070
                         * Move this PCB to the head of hash chain so that
1071
                         * repeated accesses are quicker.  This is analogous to
1072
                         * the historic single-entry PCB cache.
1073
                         */
1074
                        if (inp != head->lh_first) {
1075
                                LIST_REMOVE(inp, inp_hash);
1076
                                LIST_INSERT_HEAD(head, inp, inp_hash);
1077
                        }
1078
                        break;
1079
                }
1080
        }
1081
#ifdef DIAGNOSTIC
1082
        if (inp == NULL && in_pcbnotifymiss) {
1083
                printf("in6_pcblookup_connect: faddr=");
1084
                printf(" fport=%d laddr=", ntohs(fport));
1085
                printf(" lport=%d\n", ntohs(lport));
1086
        }
1087
#endif
1088
        return (inp);
1089
}
1090
#endif /* INET6 */
1091
 
1092
 

powered by: WebSVN 2.1.0

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