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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet/ip_output.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, 1988, 1990, 1993
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
 *      @(#)ip_output.c 8.3 (Berkeley) 1/21/94
55
 * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.16 2001/07/19 06:37:26 kris Exp $
56
 */
57
 
58
#define _IP_VHL
59
 
60
#include <sys/param.h>
61
#include <sys/malloc.h>
62
#include <sys/mbuf.h>
63
#include <sys/protosw.h>
64
#include <sys/socket.h>
65
#include <sys/socketvar.h>
66
 
67
#include <net/if.h>
68
#include <net/route.h>
69
 
70
#include <netinet/in.h>
71
#include <netinet/in_systm.h>
72
#include <netinet/ip.h>
73
#include <netinet/in_pcb.h>
74
#include <netinet/in_var.h>
75
#include <netinet/ip_var.h>
76
 
77
#ifdef IPSEC
78
#include <netinet6/ipsec.h>
79
#include <netkey/key.h>
80
#ifdef IPSEC_DEBUG
81
#include <netkey/key_debug.h>
82
#else
83
#define KEYDEBUG(lev,arg)
84
#endif
85
#endif /*IPSEC*/
86
 
87
#include <netinet/ip_fw.h>
88
 
89
#ifdef DUMMYNET
90
#include <netinet/ip_dummynet.h>
91
#endif
92
 
93
#ifdef IPFIREWALL_FORWARD_DEBUG
94
#define print_ip(a)      printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
95
                                                  (ntohl(a.s_addr)>>16)&0xFF,\
96
                                                  (ntohl(a.s_addr)>>8)&0xFF,\
97
                                                  (ntohl(a.s_addr))&0xFF);
98
#endif
99
 
100
u_short ip_id;
101
 
102
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
103
static struct ifnet *ip_multicast_if __P((struct in_addr *, int *));
104
static void     ip_mloopback
105
        __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
106
static int      ip_getmoptions
107
        __P((struct sockopt *, struct ip_moptions *));
108
static int      ip_pcbopts __P((int, struct mbuf **, struct mbuf *));
109
static int      ip_setmoptions
110
        __P((struct sockopt *, struct ip_moptions **));
111
 
112
int     ip_optcopy __P((struct ip *, struct ip *));
113
extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
114
 
115
 
116
extern  struct protosw inetsw[];
117
 
118
/*
119
 * IP output.  The packet in mbuf chain m contains a skeletal IP
120
 * header (with len, off, ttl, proto, tos, src, dst).
121
 * The mbuf chain containing the packet will be freed.
122
 * The mbuf opt, if present, will not be freed.
123
 */
124
int
125
ip_output(m0, opt, ro, flags, imo)
126
        struct mbuf *m0;
127
        struct mbuf *opt;
128
        struct route *ro;
129
        int flags;
130
        struct ip_moptions *imo;
131
{
132
        struct ip *ip, *mhip;
133
        struct ifnet *ifp;
134
        struct mbuf *m = m0;
135
        int hlen = sizeof (struct ip);
136
        int len, off, error = 0;
137
        struct sockaddr_in *dst;
138
        struct in_ifaddr *ia = NULL;
139
        int isbroadcast, sw_csum;
140
#ifdef IPSEC
141
        struct route iproute;
142
        struct socket *so = NULL;
143
        struct secpolicy *sp = NULL;
144
#endif
145
        u_int16_t divert_cookie;                /* firewall cookie */
146
#ifdef IPFIREWALL_FORWARD
147
        int fwd_rewrite_src = 0;
148
#endif
149
        struct ip_fw_chain *rule = NULL;
150
 
151
#ifdef IPDIVERT
152
        /* Get and reset firewall cookie */
153
        divert_cookie = ip_divert_cookie;
154
        ip_divert_cookie = 0;
155
#else
156
        divert_cookie = 0;
157
#endif
158
 
159
#if defined(IPFIREWALL) && defined(DUMMYNET)
160
        /*
161
         * dummynet packet are prepended a vestigial mbuf with
162
         * m_type = MT_DUMMYNET and m_data pointing to the matching
163
         * rule.
164
         */
165
        if (m->m_type == MT_DUMMYNET) {
166
            /*
167
             * the packet was already tagged, so part of the
168
             * processing was already done, and we need to go down.
169
             * Get parameters from the header.
170
             */
171
            rule = (struct ip_fw_chain *)(m->m_data) ;
172
            opt = NULL ;
173
            ro = & ( ((struct dn_pkt *)m)->ro ) ;
174
            imo = NULL ;
175
            dst = ((struct dn_pkt *)m)->dn_dst ;
176
            ifp = ((struct dn_pkt *)m)->ifp ;
177
            flags = ((struct dn_pkt *)m)->flags ;
178
 
179
            m0 = m = m->m_next ;
180
#ifdef IPSEC
181
            so = ipsec_getsocket(m);
182
            (void)ipsec_setsocket(m, NULL);
183
#endif
184
            ip = mtod(m, struct ip *);
185
            hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
186
            if (ro->ro_rt != NULL)
187
                ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
188
            goto sendit;
189
        } else
190
            rule = NULL ;
191
#endif
192
#ifdef IPSEC
193
        so = ipsec_getsocket(m);
194
        (void)ipsec_setsocket(m, NULL);
195
#endif
196
 
197
#ifdef  DIAGNOSTIC
198
        if ((m->m_flags & M_PKTHDR) == 0)
199
                panic("ip_output no HDR");
200
        if (!ro)
201
                panic("ip_output no route, proto = %d",
202
                      mtod(m, struct ip *)->ip_p);
203
#endif
204
        if (opt) {
205
                m = ip_insertoptions(m, opt, &len);
206
                hlen = len;
207
        }
208
        ip = mtod(m, struct ip *);
209
        /*
210
         * Fill in IP header.
211
         */
212
        if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
213
                ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2);
214
                ip->ip_off &= IP_DF;
215
#ifdef RANDOM_IP_ID
216
                ip->ip_id = ip_randomid();
217
#else
218
                ip->ip_id = htons(ip_id++);
219
#endif
220
                ipstat.ips_localout++;
221
        } else {
222
                hlen = IP_VHL_HL(ip->ip_vhl) << 2;
223
        }
224
 
225
        dst = (struct sockaddr_in *)&ro->ro_dst;
226
        /*
227
         * If there is a cached route,
228
         * check that it is to the same destination
229
         * and is still up.  If not, free it and try again.
230
         */
231
        if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
232
           dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
233
                RTFREE(ro->ro_rt);
234
                ro->ro_rt = (struct rtentry *)0;
235
        }
236
        if (ro->ro_rt == 0) {
237
                dst->sin_family = AF_INET;
238
                dst->sin_len = sizeof(*dst);
239
                dst->sin_addr = ip->ip_dst;
240
        }
241
        /*
242
         * If routing to interface only,
243
         * short circuit routing lookup.
244
         */
245
#define ifatoia(ifa)    ((struct in_ifaddr *)(ifa))
246
#define sintosa(sin)    ((struct sockaddr *)(sin))
247
        if (flags & IP_ROUTETOIF) {
248
                if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
249
                    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
250
                        ipstat.ips_noroute++;
251
                        error = ENETUNREACH;
252
                        goto bad;
253
                }
254
                ifp = ia->ia_ifp;
255
                ip->ip_ttl = 1;
256
                isbroadcast = in_broadcast(dst->sin_addr, ifp);
257
        } else {
258
                /*
259
                 * If this is the case, we probably don't want to allocate
260
                 * a protocol-cloned route since we didn't get one from the
261
                 * ULP.  This lets TCP do its thing, while not burdening
262
                 * forwarding or ICMP with the overhead of cloning a route.
263
                 * Of course, we still want to do any cloning requested by
264
                 * the link layer, as this is probably required in all cases
265
                 * for correct operation (as it is for ARP).
266
                 */
267
                if (ro->ro_rt == 0)
268
                        rtalloc_ign(ro, RTF_PRCLONING);
269
                if (ro->ro_rt == 0) {
270
                        ipstat.ips_noroute++;
271
                        error = EHOSTUNREACH;
272
                        goto bad;
273
                }
274
                ia = ifatoia(ro->ro_rt->rt_ifa);
275
                ifp = ro->ro_rt->rt_ifp;
276
                ro->ro_rt->rt_use++;
277
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
278
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
279
                if (ro->ro_rt->rt_flags & RTF_HOST)
280
                        isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
281
                else
282
                        isbroadcast = in_broadcast(dst->sin_addr, ifp);
283
        }
284
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
285
                struct in_multi *inm;
286
 
287
                m->m_flags |= M_MCAST;
288
                /*
289
                 * IP destination address is multicast.  Make sure "dst"
290
                 * still points to the address in "ro".  (It may have been
291
                 * changed to point to a gateway address, above.)
292
                 */
293
                dst = (struct sockaddr_in *)&ro->ro_dst;
294
                /*
295
                 * See if the caller provided any multicast options
296
                 */
297
                if (imo != NULL) {
298
                        ip->ip_ttl = imo->imo_multicast_ttl;
299
                        if (imo->imo_multicast_ifp != NULL)
300
                                ifp = imo->imo_multicast_ifp;
301
                        if (imo->imo_multicast_vif != -1)
302
                                ip->ip_src.s_addr =
303
                                    ip_mcast_src(imo->imo_multicast_vif);
304
                } else
305
                        ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
306
                /*
307
                 * Confirm that the outgoing interface supports multicast.
308
                 */
309
                if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
310
                        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
311
                                ipstat.ips_noroute++;
312
                                error = ENETUNREACH;
313
                                goto bad;
314
                        }
315
                }
316
                /*
317
                 * If source address not specified yet, use address
318
                 * of outgoing interface.
319
                 */
320
                if (ip->ip_src.s_addr == INADDR_ANY) {
321
                        register struct in_ifaddr *ia1;
322
 
323
                        TAILQ_FOREACH(ia1, &in_ifaddrhead, ia_link)
324
                                if (ia1->ia_ifp == ifp) {
325
                                        ip->ip_src = IA_SIN(ia1)->sin_addr;
326
                                        break;
327
                                }
328
                }
329
 
330
                IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
331
                if (inm != NULL &&
332
                   (imo == NULL || imo->imo_multicast_loop)) {
333
                        /*
334
                         * If we belong to the destination multicast group
335
                         * on the outgoing interface, and the caller did not
336
                         * forbid loopback, loop back a copy.
337
                         */
338
                        ip_mloopback(ifp, m, dst, hlen);
339
                }
340
                else {
341
                        /*
342
                         * If we are acting as a multicast router, perform
343
                         * multicast forwarding as if the packet had just
344
                         * arrived on the interface to which we are about
345
                         * to send.  The multicast forwarding function
346
                         * recursively calls this function, using the
347
                         * IP_FORWARDING flag to prevent infinite recursion.
348
                         *
349
                         * Multicasts that are looped back by ip_mloopback(),
350
                         * above, will be forwarded by the ip_input() routine,
351
                         * if necessary.
352
                         */
353
                        if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
354
                                /*
355
                                 * Check if rsvp daemon is running. If not, don't
356
                                 * set ip_moptions. This ensures that the packet
357
                                 * is multicast and not just sent down one link
358
                                 * as prescribed by rsvpd.
359
                                 */
360
                                if (!rsvp_on)
361
                                  imo = NULL;
362
                                if (ip_mforward(ip, ifp, m, imo) != 0) {
363
                                        m_freem(m);
364
                                        goto done;
365
                                }
366
                        }
367
                }
368
 
369
                /*
370
                 * Multicasts with a time-to-live of zero may be looped-
371
                 * back, above, but must not be transmitted on a network.
372
                 * Also, multicasts addressed to the loopback interface
373
                 * are not sent -- the above call to ip_mloopback() will
374
                 * loop back a copy if this host actually belongs to the
375
                 * destination group on the loopback interface.
376
                 */
377
                if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
378
                        m_freem(m);
379
                        goto done;
380
                }
381
 
382
                goto sendit;
383
        }
384
#ifndef notdef
385
        /*
386
         * If source address not specified yet, use address
387
         * of outgoing interface.
388
         */
389
        if (ip->ip_src.s_addr == INADDR_ANY) {
390
                ip->ip_src = IA_SIN(ia)->sin_addr;
391
#ifdef IPFIREWALL_FORWARD
392
                /* Keep note that we did this - if the firewall changes
393
                 * the next-hop, our interface may change, changing the
394
                 * default source IP. It's a shame so much effort happens
395
                 * twice. Oh well.
396
                 */
397
                fwd_rewrite_src++;
398
#endif /* IPFIREWALL_FORWARD */
399
        }
400
#endif /* notdef */
401
#ifdef ALTQ
402
        /*
403
         * disable packet drop hack.
404
         * packetdrop should be done by queueing.
405
         */
406
#else /* !ALTQ */
407
        /*
408
         * Verify that we have any chance at all of being able to queue
409
         *      the packet or packet fragments
410
         */
411
        if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
412
                ifp->if_snd.ifq_maxlen) {
413
                        error = ENOBUFS;
414
                        goto bad;
415
        }
416
#endif /* !ALTQ */
417
 
418
        /*
419
         * Look for broadcast address and
420
         * and verify user is allowed to send
421
         * such a packet.
422
         */
423
        if (isbroadcast) {
424
                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
425
                        error = EADDRNOTAVAIL;
426
                        goto bad;
427
                }
428
                if ((flags & IP_ALLOWBROADCAST) == 0) {
429
                        error = EACCES;
430
                        goto bad;
431
                }
432
                /* don't allow broadcast messages to be fragmented */
433
                if ((u_short)ip->ip_len > ifp->if_mtu) {
434
                        error = EMSGSIZE;
435
                        goto bad;
436
                }
437
                m->m_flags |= M_BCAST;
438
        } else {
439
                m->m_flags &= ~M_BCAST;
440
        }
441
 
442
sendit:
443
#ifdef IPSEC
444
        /* get SP for this packet */
445
        if (so == NULL)
446
                sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error);
447
        else
448
                sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
449
 
450
        if (sp == NULL) {
451
                ipsecstat.out_inval++;
452
                goto bad;
453
        }
454
 
455
        error = 0;
456
 
457
        /* check policy */
458
        switch (sp->policy) {
459
        case IPSEC_POLICY_DISCARD:
460
                /*
461
                 * This packet is just discarded.
462
                 */
463
                ipsecstat.out_polvio++;
464
                goto bad;
465
 
466
        case IPSEC_POLICY_BYPASS:
467
        case IPSEC_POLICY_NONE:
468
                /* no need to do IPsec. */
469
                goto skip_ipsec;
470
 
471
        case IPSEC_POLICY_IPSEC:
472
                if (sp->req == NULL) {
473
                        /* acquire a policy */
474
                        error = key_spdacquire(sp);
475
                        goto bad;
476
                }
477
                break;
478
 
479
        case IPSEC_POLICY_ENTRUST:
480
        default:
481
                printf("ip_output: Invalid policy found. %d\n", sp->policy);
482
        }
483
    {
484
        struct ipsec_output_state state;
485
        bzero(&state, sizeof(state));
486
        state.m = m;
487
        if (flags & IP_ROUTETOIF) {
488
                state.ro = &iproute;
489
                bzero(&iproute, sizeof(iproute));
490
        } else
491
                state.ro = ro;
492
        state.dst = (struct sockaddr *)dst;
493
 
494
        ip->ip_sum = 0;
495
 
496
        /*
497
         * XXX
498
         * delayed checksums are not currently compatible with IPsec
499
         */
500
        if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
501
                in_delayed_cksum(m);
502
                m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
503
        }
504
 
505
        HTONS(ip->ip_len);
506
        HTONS(ip->ip_off);
507
 
508
        error = ipsec4_output(&state, sp, flags);
509
 
510
        m = state.m;
511
        if (flags & IP_ROUTETOIF) {
512
                /*
513
                 * if we have tunnel mode SA, we may need to ignore
514
                 * IP_ROUTETOIF.
515
                 */
516
                if (state.ro != &iproute || state.ro->ro_rt != NULL) {
517
                        flags &= ~IP_ROUTETOIF;
518
                        ro = state.ro;
519
                }
520
        } else
521
                ro = state.ro;
522
        dst = (struct sockaddr_in *)state.dst;
523
        if (error) {
524
                /* mbuf is already reclaimed in ipsec4_output. */
525
                m0 = NULL;
526
                switch (error) {
527
                case EHOSTUNREACH:
528
                case ENETUNREACH:
529
                case EMSGSIZE:
530
                case ENOBUFS:
531
                case ENOMEM:
532
                        break;
533
                default:
534
                        printf("ip4_output (ipsec): error code %d\n", error);
535
                        /*fall through*/
536
                case ENOENT:
537
                        /* don't show these error codes to the user */
538
                        error = 0;
539
                        break;
540
                }
541
                goto bad;
542
        }
543
 
544
        /* be sure to update variables that are affected by ipsec4_output() */
545
        ip = mtod(m, struct ip *);
546
#ifdef _IP_VHL
547
        hlen = IP_VHL_HL(ip->ip_vhl) << 2;
548
#else
549
        hlen = ip->ip_hl << 2;
550
#endif
551
        if (ro->ro_rt == NULL) {
552
                if ((flags & IP_ROUTETOIF) == 0) {
553
                        printf("ip_output: "
554
                                "can't update route after IPsec processing\n");
555
                        error = EHOSTUNREACH;   /*XXX*/
556
                        goto bad;
557
                }
558
        } else {
559
                if (state.encap) {
560
                        ia = ifatoia(ro->ro_rt->rt_ifa);
561
                        ifp = ro->ro_rt->rt_ifp;
562
                }
563
        }
564
    }
565
 
566
        /* make it flipped, again. */
567
        NTOHS(ip->ip_len);
568
        NTOHS(ip->ip_off);
569
skip_ipsec:
570
#endif /*IPSEC*/
571
 
572
        /*
573
         * IpHack's section.
574
         * - Xlate: translate packet's addr/port (NAT).
575
         * - Firewall: deny/allow/etc.
576
         * - Wrap: fake packet's addr/port <unimpl.>
577
         * - Encapsulate: put it in another IP and send out. <unimp.>
578
         */
579
        if (fr_checkp) {
580
                struct  mbuf    *m1 = m;
581
 
582
                if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1)
583
                        goto done;
584
                ip = mtod(m = m1, struct ip *);
585
        }
586
 
587
        /*
588
         * Check with the firewall...
589
         */
590
        if (fw_enable && ip_fw_chk_ptr) {
591
                struct sockaddr_in *old = dst;
592
 
593
                off = (*ip_fw_chk_ptr)(&ip,
594
                    hlen, ifp, &divert_cookie, &m, &rule, &dst);
595
                /*
596
                 * On return we must do the following:
597
                 * IP_FW_PORT_DENY_FLAG         -> drop the pkt (XXX new)
598
                 * 1<=off<= 0xffff   -> DIVERT
599
                 * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe
600
                 * (off & IP_FW_PORT_TEE_FLAG)  -> TEE the packet
601
                 * dst != old        -> IPFIREWALL_FORWARD
602
                 * off==0, dst==old  -> accept
603
                 * If some of the above modules is not compiled in, then
604
                 * we should't have to check the corresponding condition
605
                 * (because the ipfw control socket should not accept
606
                 * unsupported rules), but better play safe and drop
607
                 * packets in case of doubt.
608
                 */
609
                if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
610
                        if (m)
611
                                m_freem(m);
612
                        error = EACCES ;
613
                        goto done ;
614
                }
615
                ip = mtod(m, struct ip *);
616
                if (off == 0 && dst == old) /* common case */
617
                        goto pass ;
618
#ifdef DUMMYNET
619
                if ((off & IP_FW_PORT_DYNT_FLAG) != 0) {
620
                    /*
621
                     * pass the pkt to dummynet. Need to include
622
                     * pipe number, m, ifp, ro, dst because these are
623
                     * not recomputed in the next pass.
624
                     * All other parameters have been already used and
625
                     * so they are not needed anymore.
626
                     * XXX note: if the ifp or ro entry are deleted
627
                     * while a pkt is in dummynet, we are in trouble!
628
                     */
629
                    error = dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,
630
                                ifp,ro,dst,rule, flags);
631
                    goto done;
632
                }
633
#endif   
634
#ifdef IPDIVERT
635
                if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
636
                        struct mbuf *clone = NULL;
637
 
638
                        /* Clone packet if we're doing a 'tee' */
639
                        if ((off & IP_FW_PORT_TEE_FLAG) != 0)
640
                                clone = m_dup(m, M_DONTWAIT);
641
 
642
                        /*
643
                         * XXX
644
                         * delayed checksums are not currently compatible
645
                         * with divert sockets.
646
                         */
647
                        if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
648
                                in_delayed_cksum(m);
649
                                m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
650
                        }
651
 
652
                        /* Restore packet header fields to original values */
653
                        HTONS(ip->ip_len);
654
                        HTONS(ip->ip_off);
655
 
656
                        /* Deliver packet to divert input routine */
657
                        ip_divert_cookie = divert_cookie;
658
                        divert_packet(m, 0, off & 0xffff);
659
 
660
                        /* If 'tee', continue with original packet */
661
                        if (clone != NULL) {
662
                                m = clone;
663
                                ip = mtod(m, struct ip *);
664
                                goto pass;
665
                        }
666
                        goto done;
667
                }
668
#endif
669
 
670
#ifdef IPFIREWALL_FORWARD
671
                /* Here we check dst to make sure it's directly reachable on the
672
                 * interface we previously thought it was.
673
                 * If it isn't (which may be likely in some situations) we have
674
                 * to re-route it (ie, find a route for the next-hop and the
675
                 * associated interface) and set them here. This is nested
676
                 * forwarding which in most cases is undesirable, except where
677
                 * such control is nigh impossible. So we do it here.
678
                 * And I'm babbling.
679
                 */
680
                if (off == 0 && old != dst) {
681
                        struct in_ifaddr *ia;
682
 
683
                        /* It's changed... */
684
                        /* There must be a better way to do this next line... */
685
                        static struct route sro_fwd, *ro_fwd = &sro_fwd;
686
#ifdef IPFIREWALL_FORWARD_DEBUG
687
                        printf("IPFIREWALL_FORWARD: New dst ip: ");
688
                        print_ip(dst->sin_addr);
689
                        printf("\n");
690
#endif
691
                        /*
692
                         * We need to figure out if we have been forwarded
693
                         * to a local socket. If so then we should somehow
694
                         * "loop back" to ip_input, and get directed to the
695
                         * PCB as if we had received this packet. This is
696
                         * because it may be dificult to identify the packets
697
                         * you want to forward until they are being output
698
                         * and have selected an interface. (e.g. locally
699
                         * initiated packets) If we used the loopback inteface,
700
                         * we would not be able to control what happens
701
                         * as the packet runs through ip_input() as
702
                         * it is done through a ISR.
703
                         */
704
                        TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
705
                                /*
706
                                 * If the addr to forward to is one
707
                                 * of ours, we pretend to
708
                                 * be the destination for this packet.
709
                                 */
710
                                if (IA_SIN(ia)->sin_addr.s_addr ==
711
                                                 dst->sin_addr.s_addr)
712
                                        break;
713
                        }
714
                        if (ia) {
715
                                /* tell ip_input "dont filter" */
716
                                ip_fw_fwd_addr = dst;
717
                                if (m->m_pkthdr.rcvif == NULL)
718
                                        m->m_pkthdr.rcvif = ifunit("lo0");
719
                                if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
720
                                        m->m_pkthdr.csum_flags |=
721
                                            CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
722
                                        m0->m_pkthdr.csum_data = 0xffff;
723
                                }
724
                                m->m_pkthdr.csum_flags |=
725
                                    CSUM_IP_CHECKED | CSUM_IP_VALID;
726
                                HTONS(ip->ip_len);
727
                                HTONS(ip->ip_off);
728
                                ip_input(m);
729
                                goto done;
730
                        }
731
                        /* Some of the logic for this was
732
                         * nicked from above.
733
                         *
734
                         * This rewrites the cached route in a local PCB.
735
                         * Is this what we want to do?
736
                         */
737
                        bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
738
 
739
                        ro_fwd->ro_rt = 0;
740
                        rtalloc_ign(ro_fwd, RTF_PRCLONING);
741
 
742
                        if (ro_fwd->ro_rt == 0) {
743
                                ipstat.ips_noroute++;
744
                                error = EHOSTUNREACH;
745
                                goto bad;
746
                        }
747
 
748
                        ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
749
                        ifp = ro_fwd->ro_rt->rt_ifp;
750
                        ro_fwd->ro_rt->rt_use++;
751
                        if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
752
                                dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
753
                        if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
754
                                isbroadcast =
755
                                    (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
756
                        else
757
                                isbroadcast = in_broadcast(dst->sin_addr, ifp);
758
                        RTFREE(ro->ro_rt);
759
                        ro->ro_rt = ro_fwd->ro_rt;
760
                        dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
761
 
762
                        /*
763
                         * If we added a default src ip earlier,
764
                         * which would have been gotten from the-then
765
                         * interface, do it again, from the new one.
766
                         */
767
                        if (fwd_rewrite_src)
768
                                ip->ip_src = IA_SIN(ia)->sin_addr;
769
                        goto pass ;
770
                }
771
#endif /* IPFIREWALL_FORWARD */
772
                /*
773
                 * if we get here, none of the above matches, and
774
                 * we have to drop the pkt
775
                 */
776
                m_freem(m);
777
                error = EACCES; /* not sure this is the right error msg */
778
                goto done;
779
        }
780
 
781
pass:
782
        m->m_pkthdr.csum_flags |= CSUM_IP;
783
        sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
784
        if (sw_csum & CSUM_DELAY_DATA) {
785
                in_delayed_cksum(m);
786
                sw_csum &= ~CSUM_DELAY_DATA;
787
        }
788
        m->m_pkthdr.csum_flags &= ifp->if_hwassist;
789
 
790
        /*
791
         * If small enough for interface, or the interface will take
792
         * care of the fragmentation for us, can just send directly.
793
         */
794
        if ((u_short)ip->ip_len <= ifp->if_mtu ||
795
            ifp->if_hwassist & CSUM_FRAGMENT) {
796
                HTONS(ip->ip_len);
797
                HTONS(ip->ip_off);
798
                ip->ip_sum = 0;
799
                if (sw_csum & CSUM_DELAY_IP) {
800
                        if (ip->ip_vhl == IP_VHL_BORING) {
801
                                ip->ip_sum = in_cksum_hdr(ip);
802
                        } else {
803
                                ip->ip_sum = in_cksum(m, hlen);
804
                        }
805
                }
806
 
807
                /* Record statistics for this interface address. */
808
                if (!(flags & IP_FORWARDING) && ia != NULL) {
809
                        ia->ia_ifa.if_opackets++;
810
                        ia->ia_ifa.if_obytes += m->m_pkthdr.len;
811
                }
812
 
813
#ifdef IPSEC
814
                /* clean ipsec history once it goes out of the node */
815
                ipsec_delaux(m);
816
#endif
817
 
818
                error = (*ifp->if_output)(ifp, m,
819
                                (struct sockaddr *)dst, ro->ro_rt);
820
                goto done;
821
        }
822
        /*
823
         * Too large for interface; fragment if possible.
824
         * Must be able to put at least 8 bytes per fragment.
825
         */
826
        if (ip->ip_off & IP_DF) {
827
                error = EMSGSIZE;
828
                /*
829
                 * This case can happen if the user changed the MTU
830
                 * of an interface after enabling IP on it.  Because
831
                 * most netifs don't keep track of routes pointing to
832
                 * them, there is no way for one to update all its
833
                 * routes when the MTU is changed.
834
                 */
835
                if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
836
                    && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
837
                    && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
838
                        ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
839
                }
840
                ipstat.ips_cantfrag++;
841
                goto bad;
842
        }
843
        len = (ifp->if_mtu - hlen) &~ 7;
844
        if (len < 8) {
845
                error = EMSGSIZE;
846
                goto bad;
847
        }
848
 
849
        /*
850
         * if the interface will not calculate checksums on
851
         * fragmented packets, then do it here.
852
         */
853
        if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA &&
854
            (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) {
855
                in_delayed_cksum(m);
856
                m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
857
        }
858
 
859
    {
860
        int mhlen, firstlen = len;
861
        struct mbuf **mnext = &m->m_nextpkt;
862
        int nfrags = 1;
863
 
864
        /*
865
         * Loop through length of segment after first fragment,
866
         * make new header and copy data of each part and link onto chain.
867
         */
868
        m0 = m;
869
        mhlen = sizeof (struct ip);
870
        for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
871
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
872
                if (m == 0) {
873
                        error = ENOBUFS;
874
                        ipstat.ips_odropped++;
875
                        goto sendorfree;
876
                }
877
                m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG;
878
                m->m_data += max_linkhdr;
879
                mhip = mtod(m, struct ip *);
880
                *mhip = *ip;
881
                if (hlen > sizeof (struct ip)) {
882
                        mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
883
                        mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
884
                }
885
                m->m_len = mhlen;
886
                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
887
                if (ip->ip_off & IP_MF)
888
                        mhip->ip_off |= IP_MF;
889
                if (off + len >= (u_short)ip->ip_len)
890
                        len = (u_short)ip->ip_len - off;
891
                else
892
                        mhip->ip_off |= IP_MF;
893
                mhip->ip_len = htons((u_short)(len + mhlen));
894
                m->m_next = m_copy(m0, off, len);
895
                if (m->m_next == 0) {
896
                        (void) m_free(m);
897
                        error = ENOBUFS;        /* ??? */
898
                        ipstat.ips_odropped++;
899
                        goto sendorfree;
900
                }
901
                m->m_pkthdr.len = mhlen + len;
902
                m->m_pkthdr.rcvif = (struct ifnet *)0;
903
                m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags;
904
                HTONS(mhip->ip_off);
905
                mhip->ip_sum = 0;
906
                if (sw_csum & CSUM_DELAY_IP) {
907
                        if (mhip->ip_vhl == IP_VHL_BORING) {
908
                                mhip->ip_sum = in_cksum_hdr(mhip);
909
                        } else {
910
                                mhip->ip_sum = in_cksum(m, mhlen);
911
                        }
912
                }
913
                *mnext = m;
914
                mnext = &m->m_nextpkt;
915
                nfrags++;
916
        }
917
        ipstat.ips_ofragments += nfrags;
918
 
919
        /* set first/last markers for fragment chain */
920
        m->m_flags |= M_LASTFRAG;
921
        m0->m_flags |= M_FIRSTFRAG | M_FRAG;
922
        m0->m_pkthdr.csum_data = nfrags;
923
 
924
        /*
925
         * Update first fragment by trimming what's been copied out
926
         * and updating header, then send each fragment (in order).
927
         */
928
        m = m0;
929
        m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
930
        m->m_pkthdr.len = hlen + firstlen;
931
        ip->ip_len = htons((u_short)m->m_pkthdr.len);
932
        ip->ip_off |= IP_MF;
933
        HTONS(ip->ip_off);
934
        ip->ip_sum = 0;
935
        if (sw_csum & CSUM_DELAY_IP) {
936
                if (ip->ip_vhl == IP_VHL_BORING) {
937
                        ip->ip_sum = in_cksum_hdr(ip);
938
                } else {
939
                        ip->ip_sum = in_cksum(m, hlen);
940
                }
941
        }
942
sendorfree:
943
        for (m = m0; m; m = m0) {
944
                m0 = m->m_nextpkt;
945
                m->m_nextpkt = 0;
946
#ifdef IPSEC
947
                /* clean ipsec history once it goes out of the node */
948
                ipsec_delaux(m);
949
#endif
950
                if (error == 0) {
951
                        /* Record statistics for this interface address. */
952
                        if (ia != NULL) {
953
                                ia->ia_ifa.if_opackets++;
954
                                ia->ia_ifa.if_obytes += m->m_pkthdr.len;
955
                        }
956
 
957
                        error = (*ifp->if_output)(ifp, m,
958
                            (struct sockaddr *)dst, ro->ro_rt);
959
                } else
960
                        m_freem(m);
961
        }
962
 
963
        if (error == 0)
964
                ipstat.ips_fragmented++;
965
    }
966
done:
967
#ifdef IPSEC
968
        if (ro == &iproute && ro->ro_rt) {
969
                RTFREE(ro->ro_rt);
970
                ro->ro_rt = NULL;
971
        }
972
        if (sp != NULL) {
973
                KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
974
                        printf("DP ip_output call free SP:%p\n", sp));
975
                key_freesp(sp);
976
        }
977
#endif /* IPSEC */
978
        return (error);
979
bad:
980
        m_freem(m0);
981
        goto done;
982
}
983
 
984
void
985
in_delayed_cksum(struct mbuf *m)
986
{
987
        struct ip *ip;
988
        u_short csum, offset;
989
 
990
        ip = mtod(m, struct ip *);
991
        offset = IP_VHL_HL(ip->ip_vhl) << 2 ;
992
        csum = in_cksum_skip(m, ip->ip_len, offset);
993
        if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0)
994
                csum = 0xffff;
995
        offset += m->m_pkthdr.csum_data;        /* checksum offset */
996
 
997
        if (offset + sizeof(u_short) > m->m_len) {
998
                printf("delayed m_pullup, m->len: %d  off: %d  p: %d\n",
999
                    m->m_len, offset, ip->ip_p);
1000
                /*
1001
                 * XXX
1002
                 * this shouldn't happen, but if it does, the
1003
                 * correct behavior may be to insert the checksum
1004
                 * in the existing chain instead of rearranging it.
1005
                 */
1006
                m = m_pullup(m, offset + sizeof(u_short));
1007
        }
1008
        *(u_short *)(m->m_data + offset) = csum;
1009
}
1010
 
1011
/*
1012
 * Insert IP options into preformed packet.
1013
 * Adjust IP destination as required for IP source routing,
1014
 * as indicated by a non-zero in_addr at the start of the options.
1015
 *
1016
 * XXX This routine assumes that the packet has no options in place.
1017
 */
1018
static struct mbuf *
1019
ip_insertoptions(m, opt, phlen)
1020
        register struct mbuf *m;
1021
        struct mbuf *opt;
1022
        int *phlen;
1023
{
1024
        register struct ipoption *p = mtod(opt, struct ipoption *);
1025
        struct mbuf *n;
1026
        register struct ip *ip = mtod(m, struct ip *);
1027
        unsigned optlen;
1028
 
1029
        optlen = opt->m_len - sizeof(p->ipopt_dst);
1030
        if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
1031
                return (m);             /* XXX should fail */
1032
        if (p->ipopt_dst.s_addr)
1033
                ip->ip_dst = p->ipopt_dst;
1034
        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
1035
                MGETHDR(n, M_DONTWAIT, MT_HEADER);
1036
                if (n == 0)
1037
                        return (m);
1038
                n->m_pkthdr.rcvif = (struct ifnet *)0;
1039
                n->m_pkthdr.len = m->m_pkthdr.len + optlen;
1040
                m->m_len -= sizeof(struct ip);
1041
                m->m_data += sizeof(struct ip);
1042
                n->m_next = m;
1043
                m = n;
1044
                m->m_len = optlen + sizeof(struct ip);
1045
                m->m_data += max_linkhdr;
1046
                (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
1047
        } else {
1048
                m->m_data -= optlen;
1049
                m->m_len += optlen;
1050
                m->m_pkthdr.len += optlen;
1051
                ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
1052
        }
1053
        ip = mtod(m, struct ip *);
1054
        bcopy(p->ipopt_list, ip + 1, optlen);
1055
        *phlen = sizeof(struct ip) + optlen;
1056
        ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2);
1057
        ip->ip_len += optlen;
1058
        return (m);
1059
}
1060
 
1061
/*
1062
 * Copy options from ip to jp,
1063
 * omitting those not copied during fragmentation.
1064
 */
1065
int
1066
ip_optcopy(ip, jp)
1067
        struct ip *ip, *jp;
1068
{
1069
        register u_char *cp, *dp;
1070
        int opt, optlen, cnt;
1071
 
1072
        cp = (u_char *)(ip + 1);
1073
        dp = (u_char *)(jp + 1);
1074
        cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1075
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
1076
                opt = cp[0];
1077
                if (opt == IPOPT_EOL)
1078
                        break;
1079
                if (opt == IPOPT_NOP) {
1080
                        /* Preserve for IP mcast tunnel's LSRR alignment. */
1081
                        *dp++ = IPOPT_NOP;
1082
                        optlen = 1;
1083
                        continue;
1084
                }
1085
#ifdef DIAGNOSTIC
1086
                if (cnt < IPOPT_OLEN + sizeof(*cp))
1087
                        panic("malformed IPv4 option passed to ip_optcopy");
1088
#endif
1089
                optlen = cp[IPOPT_OLEN];
1090
#ifdef DIAGNOSTIC
1091
                if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
1092
                        panic("malformed IPv4 option passed to ip_optcopy");
1093
#endif
1094
                /* bogus lengths should have been caught by ip_dooptions */
1095
                if (optlen > cnt)
1096
                        optlen = cnt;
1097
                if (IPOPT_COPIED(opt)) {
1098
                        bcopy(cp, dp, optlen);
1099
                        dp += optlen;
1100
                }
1101
        }
1102
        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
1103
                *dp++ = IPOPT_EOL;
1104
        return (optlen);
1105
}
1106
 
1107
/*
1108
 * IP socket option processing.
1109
 */
1110
int
1111
ip_ctloutput(so, sopt)
1112
        struct socket *so;
1113
        struct sockopt *sopt;
1114
{
1115
        struct  inpcb *inp = sotoinpcb(so);
1116
        int     error, optval;
1117
 
1118
        error = optval = 0;
1119
        if (sopt->sopt_level != IPPROTO_IP) {
1120
                return (EINVAL);
1121
        }
1122
 
1123
        switch (sopt->sopt_dir) {
1124
        case SOPT_SET:
1125
                switch (sopt->sopt_name) {
1126
                case IP_OPTIONS:
1127
#ifdef notyet
1128
                case IP_RETOPTS:
1129
#endif
1130
                {
1131
                        struct mbuf *m;
1132
                        if (sopt->sopt_valsize > MLEN) {
1133
                                error = EMSGSIZE;
1134
                                break;
1135
                        }
1136
                        MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
1137
                        if (m == 0) {
1138
                                error = ENOBUFS;
1139
                                break;
1140
                        }
1141
                        m->m_len = sopt->sopt_valsize;
1142
                        error = sooptcopyin(sopt, mtod(m, char *), m->m_len,
1143
                                            m->m_len);
1144
 
1145
                        return (ip_pcbopts(sopt->sopt_name, &inp->inp_options,
1146
                                           m));
1147
                }
1148
 
1149
                case IP_TOS:
1150
                case IP_TTL:
1151
                case IP_RECVOPTS:
1152
                case IP_RECVRETOPTS:
1153
                case IP_RECVDSTADDR:
1154
                case IP_RECVIF:
1155
#if defined(NFAITH) && NFAITH > 0
1156
                case IP_FAITH:
1157
#endif
1158
                        error = sooptcopyin(sopt, &optval, sizeof optval,
1159
                                            sizeof optval);
1160
                        if (error)
1161
                                break;
1162
 
1163
                        switch (sopt->sopt_name) {
1164
                        case IP_TOS:
1165
                                inp->inp_ip_tos = optval;
1166
                                break;
1167
 
1168
                        case IP_TTL:
1169
                                inp->inp_ip_ttl = optval;
1170
                                break;
1171
#define OPTSET(bit) \
1172
        if (optval) \
1173
                inp->inp_flags |= bit; \
1174
        else \
1175
                inp->inp_flags &= ~bit;
1176
 
1177
                        case IP_RECVOPTS:
1178
                                OPTSET(INP_RECVOPTS);
1179
                                break;
1180
 
1181
                        case IP_RECVRETOPTS:
1182
                                OPTSET(INP_RECVRETOPTS);
1183
                                break;
1184
 
1185
                        case IP_RECVDSTADDR:
1186
                                OPTSET(INP_RECVDSTADDR);
1187
                                break;
1188
 
1189
                        case IP_RECVIF:
1190
                                OPTSET(INP_RECVIF);
1191
                                break;
1192
 
1193
#if defined(NFAITH) && NFAITH > 0
1194
                        case IP_FAITH:
1195
                                OPTSET(INP_FAITH);
1196
                                break;
1197
#endif
1198
                        }
1199
                        break;
1200
#undef OPTSET
1201
 
1202
                case IP_MULTICAST_IF:
1203
                case IP_MULTICAST_VIF:
1204
                case IP_MULTICAST_TTL:
1205
                case IP_MULTICAST_LOOP:
1206
                case IP_ADD_MEMBERSHIP:
1207
                case IP_DROP_MEMBERSHIP:
1208
                        error = ip_setmoptions(sopt, &inp->inp_moptions);
1209
                        break;
1210
 
1211
                case IP_PORTRANGE:
1212
                        error = sooptcopyin(sopt, &optval, sizeof optval,
1213
                                            sizeof optval);
1214
                        if (error)
1215
                                break;
1216
 
1217
                        switch (optval) {
1218
                        case IP_PORTRANGE_DEFAULT:
1219
                                inp->inp_flags &= ~(INP_LOWPORT);
1220
                                inp->inp_flags &= ~(INP_HIGHPORT);
1221
                                break;
1222
 
1223
                        case IP_PORTRANGE_HIGH:
1224
                                inp->inp_flags &= ~(INP_LOWPORT);
1225
                                inp->inp_flags |= INP_HIGHPORT;
1226
                                break;
1227
 
1228
                        case IP_PORTRANGE_LOW:
1229
                                inp->inp_flags &= ~(INP_HIGHPORT);
1230
                                inp->inp_flags |= INP_LOWPORT;
1231
                                break;
1232
 
1233
                        default:
1234
                                error = EINVAL;
1235
                                break;
1236
                        }
1237
                        break;
1238
 
1239
#ifdef IPSEC
1240
                case IP_IPSEC_POLICY:
1241
                {
1242
                        caddr_t req;
1243
                        size_t len = 0;
1244
                        int priv;
1245
                        struct mbuf *m;
1246
                        int optname;
1247
 
1248
                        if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
1249
                                break;
1250
                        if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
1251
                                break;
1252
                        priv = (sopt->sopt_p != NULL &&
1253
                                suser(sopt->sopt_p) != 0) ? 0 : 1;
1254
                        req = mtod(m, caddr_t);
1255
                        len = m->m_len;
1256
                        optname = sopt->sopt_name;
1257
                        error = ipsec4_set_policy(inp, optname, req, len, priv);
1258
                        m_freem(m);
1259
                        break;
1260
                }
1261
#endif /*IPSEC*/
1262
 
1263
                default:
1264
                        error = ENOPROTOOPT;
1265
                        break;
1266
                }
1267
                break;
1268
 
1269
        case SOPT_GET:
1270
                switch (sopt->sopt_name) {
1271
                case IP_OPTIONS:
1272
                case IP_RETOPTS:
1273
                        if (inp->inp_options)
1274
                                error = sooptcopyout(sopt,
1275
                                                     mtod(inp->inp_options,
1276
                                                          char *),
1277
                                                     inp->inp_options->m_len);
1278
                        else
1279
                                sopt->sopt_valsize = 0;
1280
                        break;
1281
 
1282
                case IP_TOS:
1283
                case IP_TTL:
1284
                case IP_RECVOPTS:
1285
                case IP_RECVRETOPTS:
1286
                case IP_RECVDSTADDR:
1287
                case IP_RECVIF:
1288
                case IP_PORTRANGE:
1289
#if defined(NFAITH) && NFAITH > 0
1290
                case IP_FAITH:
1291
#endif
1292
                        switch (sopt->sopt_name) {
1293
 
1294
                        case IP_TOS:
1295
                                optval = inp->inp_ip_tos;
1296
                                break;
1297
 
1298
                        case IP_TTL:
1299
                                optval = inp->inp_ip_ttl;
1300
                                break;
1301
 
1302
#define OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
1303
 
1304
                        case IP_RECVOPTS:
1305
                                optval = OPTBIT(INP_RECVOPTS);
1306
                                break;
1307
 
1308
                        case IP_RECVRETOPTS:
1309
                                optval = OPTBIT(INP_RECVRETOPTS);
1310
                                break;
1311
 
1312
                        case IP_RECVDSTADDR:
1313
                                optval = OPTBIT(INP_RECVDSTADDR);
1314
                                break;
1315
 
1316
                        case IP_RECVIF:
1317
                                optval = OPTBIT(INP_RECVIF);
1318
                                break;
1319
 
1320
                        case IP_PORTRANGE:
1321
                                if (inp->inp_flags & INP_HIGHPORT)
1322
                                        optval = IP_PORTRANGE_HIGH;
1323
                                else if (inp->inp_flags & INP_LOWPORT)
1324
                                        optval = IP_PORTRANGE_LOW;
1325
                                else
1326
                                        optval = 0;
1327
                                break;
1328
 
1329
#if defined(NFAITH) && NFAITH > 0
1330
                        case IP_FAITH:
1331
                                optval = OPTBIT(INP_FAITH);
1332
                                break;
1333
#endif
1334
                        }
1335
                        error = sooptcopyout(sopt, &optval, sizeof optval);
1336
                        break;
1337
 
1338
                case IP_MULTICAST_IF:
1339
                case IP_MULTICAST_VIF:
1340
                case IP_MULTICAST_TTL:
1341
                case IP_MULTICAST_LOOP:
1342
                case IP_ADD_MEMBERSHIP:
1343
                case IP_DROP_MEMBERSHIP:
1344
                        error = ip_getmoptions(sopt, inp->inp_moptions);
1345
                        break;
1346
 
1347
#ifdef IPSEC
1348
                case IP_IPSEC_POLICY:
1349
                {
1350
                        struct mbuf *m = NULL;
1351
                        caddr_t req = NULL;
1352
                        size_t len = 0;
1353
 
1354
                        if (m != 0) {
1355
                                req = mtod(m, caddr_t);
1356
                                len = m->m_len;
1357
                        }
1358
                        error = ipsec4_get_policy(sotoinpcb(so), req, len, &m);
1359
                        if (error == 0)
1360
                                error = soopt_mcopyout(sopt, m); /* XXX */
1361
                        if (error == 0)
1362
                                m_freem(m);
1363
                        break;
1364
                }
1365
#endif /*IPSEC*/
1366
 
1367
                default:
1368
                        error = ENOPROTOOPT;
1369
                        break;
1370
                }
1371
                break;
1372
        }
1373
        return (error);
1374
}
1375
 
1376
/*
1377
 * Set up IP options in pcb for insertion in output packets.
1378
 * Store in mbuf with pointer in pcbopt, adding pseudo-option
1379
 * with destination address if source routed.
1380
 */
1381
static int
1382
ip_pcbopts(optname, pcbopt, m)
1383
        int optname;
1384
        struct mbuf **pcbopt;
1385
        register struct mbuf *m;
1386
{
1387
        register int cnt, optlen;
1388
        register u_char *cp;
1389
        u_char opt;
1390
 
1391
        /* turn off any old options */
1392
        if (*pcbopt)
1393
                (void)m_free(*pcbopt);
1394
        *pcbopt = 0;
1395
        if (m == (struct mbuf *)0 || m->m_len == 0) {
1396
                /*
1397
                 * Only turning off any previous options.
1398
                 */
1399
                if (m)
1400
                        (void)m_free(m);
1401
                return (0);
1402
        }
1403
 
1404
#ifndef vax
1405
        if (m->m_len % sizeof(int32_t))
1406
                goto bad;
1407
#endif
1408
        /*
1409
         * IP first-hop destination address will be stored before
1410
         * actual options; move other options back
1411
         * and clear it when none present.
1412
         */
1413
        if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
1414
                goto bad;
1415
        cnt = m->m_len;
1416
        m->m_len += sizeof(struct in_addr);
1417
        cp = mtod(m, u_char *) + sizeof(struct in_addr);
1418
        ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
1419
        bzero(mtod(m, caddr_t), sizeof(struct in_addr));
1420
 
1421
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
1422
                opt = cp[IPOPT_OPTVAL];
1423
                if (opt == IPOPT_EOL)
1424
                        break;
1425
                if (opt == IPOPT_NOP)
1426
                        optlen = 1;
1427
                else {
1428
                        if (cnt < IPOPT_OLEN + sizeof(*cp))
1429
                                goto bad;
1430
                        optlen = cp[IPOPT_OLEN];
1431
                        if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
1432
                                goto bad;
1433
                }
1434
                switch (opt) {
1435
 
1436
                default:
1437
                        break;
1438
 
1439
                case IPOPT_LSRR:
1440
                case IPOPT_SSRR:
1441
                        /*
1442
                         * user process specifies route as:
1443
                         *      ->A->B->C->D
1444
                         * D must be our final destination (but we can't
1445
                         * check that since we may not have connected yet).
1446
                         * A is first hop destination, which doesn't appear in
1447
                         * actual IP option, but is stored before the options.
1448
                         */
1449
                        if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
1450
                                goto bad;
1451
                        m->m_len -= sizeof(struct in_addr);
1452
                        cnt -= sizeof(struct in_addr);
1453
                        optlen -= sizeof(struct in_addr);
1454
                        cp[IPOPT_OLEN] = optlen;
1455
                        /*
1456
                         * Move first hop before start of options.
1457
                         */
1458
                        bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
1459
                            sizeof(struct in_addr));
1460
                        /*
1461
                         * Then copy rest of options back
1462
                         * to close up the deleted entry.
1463
                         */
1464
                        ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
1465
                            sizeof(struct in_addr)),
1466
                            (caddr_t)&cp[IPOPT_OFFSET+1],
1467
                            (unsigned)cnt + sizeof(struct in_addr));
1468
                        break;
1469
                }
1470
        }
1471
        if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
1472
                goto bad;
1473
        *pcbopt = m;
1474
        return (0);
1475
 
1476
bad:
1477
        (void)m_free(m);
1478
        return (EINVAL);
1479
}
1480
 
1481
/*
1482
 * XXX
1483
 * The whole multicast option thing needs to be re-thought.
1484
 * Several of these options are equally applicable to non-multicast
1485
 * transmission, and one (IP_MULTICAST_TTL) totally duplicates a
1486
 * standard option (IP_TTL).
1487
 */
1488
 
1489
/*
1490
 * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
1491
 */
1492
static struct ifnet *
1493
ip_multicast_if(a, ifindexp)
1494
        struct in_addr *a;
1495
        int *ifindexp;
1496
{
1497
        int ifindex;
1498
        struct ifnet *ifp;
1499
 
1500
        if (ifindexp)
1501
                *ifindexp = 0;
1502
        if (ntohl(a->s_addr) >> 24 == 0) {
1503
                ifindex = ntohl(a->s_addr) & 0xffffff;
1504
                if (ifindex < 0 || if_index < ifindex)
1505
                        return NULL;
1506
                ifp = ifindex2ifnet[ifindex];
1507
                if (ifindexp)
1508
                        *ifindexp = ifindex;
1509
        } else {
1510
                INADDR_TO_IFP(*a, ifp);
1511
        }
1512
        return ifp;
1513
}
1514
 
1515
/*
1516
 * Set the IP multicast options in response to user setsockopt().
1517
 */
1518
static int
1519
ip_setmoptions(sopt, imop)
1520
        struct sockopt *sopt;
1521
        struct ip_moptions **imop;
1522
{
1523
        int error = 0;
1524
        int i;
1525
        struct in_addr addr;
1526
        struct ip_mreq mreq;
1527
        struct ifnet *ifp;
1528
        struct ip_moptions *imo = *imop;
1529
        struct route ro;
1530
        struct sockaddr_in *dst;
1531
        int ifindex;
1532
        int s;
1533
 
1534
        if (imo == NULL) {
1535
                /*
1536
                 * No multicast option buffer attached to the pcb;
1537
                 * allocate one and initialize to default values.
1538
                 */
1539
                imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
1540
                    M_WAITOK);
1541
 
1542
                if (imo == NULL)
1543
                        return (ENOBUFS);
1544
                *imop = imo;
1545
                imo->imo_multicast_ifp = NULL;
1546
                imo->imo_multicast_addr.s_addr = INADDR_ANY;
1547
                imo->imo_multicast_vif = -1;
1548
                imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1549
                imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
1550
                imo->imo_num_memberships = 0;
1551
        }
1552
 
1553
        switch (sopt->sopt_name) {
1554
        /* store an index number for the vif you wanna use in the send */
1555
        case IP_MULTICAST_VIF:
1556
                if (legal_vif_num == 0) {
1557
                        error = EOPNOTSUPP;
1558
                        break;
1559
                }
1560
                error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
1561
                if (error)
1562
                        break;
1563
                if (!legal_vif_num(i) && (i != -1)) {
1564
                        error = EINVAL;
1565
                        break;
1566
                }
1567
                imo->imo_multicast_vif = i;
1568
                break;
1569
 
1570
        case IP_MULTICAST_IF:
1571
                /*
1572
                 * Select the interface for outgoing multicast packets.
1573
                 */
1574
                error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr);
1575
                if (error)
1576
                        break;
1577
                /*
1578
                 * INADDR_ANY is used to remove a previous selection.
1579
                 * When no interface is selected, a default one is
1580
                 * chosen every time a multicast packet is sent.
1581
                 */
1582
                if (addr.s_addr == INADDR_ANY) {
1583
                        imo->imo_multicast_ifp = NULL;
1584
                        break;
1585
                }
1586
                /*
1587
                 * The selected interface is identified by its local
1588
                 * IP address.  Find the interface and confirm that
1589
                 * it supports multicasting.
1590
                 */
1591
                s = splimp();
1592
                ifp = ip_multicast_if(&addr, &ifindex);
1593
                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1594
                        splx(s);
1595
                        error = EADDRNOTAVAIL;
1596
                        break;
1597
                }
1598
                imo->imo_multicast_ifp = ifp;
1599
                if (ifindex)
1600
                        imo->imo_multicast_addr = addr;
1601
                else
1602
                        imo->imo_multicast_addr.s_addr = INADDR_ANY;
1603
                splx(s);
1604
                break;
1605
 
1606
        case IP_MULTICAST_TTL:
1607
                /*
1608
                 * Set the IP time-to-live for outgoing multicast packets.
1609
                 * The original multicast API required a char argument,
1610
                 * which is inconsistent with the rest of the socket API.
1611
                 * We allow either a char or an int.
1612
                 */
1613
                if (sopt->sopt_valsize == 1) {
1614
                        u_char ttl;
1615
                        error = sooptcopyin(sopt, &ttl, 1, 1);
1616
                        if (error)
1617
                                break;
1618
                        imo->imo_multicast_ttl = ttl;
1619
                } else {
1620
                        u_int ttl;
1621
                        error = sooptcopyin(sopt, &ttl, sizeof ttl,
1622
                                            sizeof ttl);
1623
                        if (error)
1624
                                break;
1625
                        if (ttl > 255)
1626
                                error = EINVAL;
1627
                        else
1628
                                imo->imo_multicast_ttl = ttl;
1629
                }
1630
                break;
1631
 
1632
        case IP_MULTICAST_LOOP:
1633
                /*
1634
                 * Set the loopback flag for outgoing multicast packets.
1635
                 * Must be zero or one.  The original multicast API required a
1636
                 * char argument, which is inconsistent with the rest
1637
                 * of the socket API.  We allow either a char or an int.
1638
                 */
1639
                if (sopt->sopt_valsize == 1) {
1640
                        u_char loop;
1641
                        error = sooptcopyin(sopt, &loop, 1, 1);
1642
                        if (error)
1643
                                break;
1644
                        imo->imo_multicast_loop = !!loop;
1645
                } else {
1646
                        u_int loop;
1647
                        error = sooptcopyin(sopt, &loop, sizeof loop,
1648
                                            sizeof loop);
1649
                        if (error)
1650
                                break;
1651
                        imo->imo_multicast_loop = !!loop;
1652
                }
1653
                break;
1654
 
1655
        case IP_ADD_MEMBERSHIP:
1656
                /*
1657
                 * Add a multicast group membership.
1658
                 * Group must be a valid IP multicast address.
1659
                 */
1660
                error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1661
                if (error)
1662
                        break;
1663
 
1664
                if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1665
                        error = EINVAL;
1666
                        break;
1667
                }
1668
                s = splimp();
1669
                /*
1670
                 * If no interface address was provided, use the interface of
1671
                 * the route to the given multicast address.
1672
                 */
1673
                if (mreq.imr_interface.s_addr == INADDR_ANY) {
1674
                        bzero((caddr_t)&ro, sizeof(ro));
1675
                        dst = (struct sockaddr_in *)&ro.ro_dst;
1676
                        dst->sin_len = sizeof(*dst);
1677
                        dst->sin_family = AF_INET;
1678
                        dst->sin_addr = mreq.imr_multiaddr;
1679
                        rtalloc(&ro);
1680
                        if (ro.ro_rt == NULL) {
1681
                                error = EADDRNOTAVAIL;
1682
                                splx(s);
1683
                                break;
1684
                        }
1685
                        ifp = ro.ro_rt->rt_ifp;
1686
                        rtfree(ro.ro_rt);
1687
                }
1688
                else {
1689
                        ifp = ip_multicast_if(&mreq.imr_interface, NULL);
1690
                }
1691
 
1692
                /*
1693
                 * See if we found an interface, and confirm that it
1694
                 * supports multicast.
1695
                 */
1696
                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1697
                        error = EADDRNOTAVAIL;
1698
                        splx(s);
1699
                        break;
1700
                }
1701
                /*
1702
                 * See if the membership already exists or if all the
1703
                 * membership slots are full.
1704
                 */
1705
                for (i = 0; i < imo->imo_num_memberships; ++i) {
1706
                        if (imo->imo_membership[i]->inm_ifp == ifp &&
1707
                            imo->imo_membership[i]->inm_addr.s_addr
1708
                                                == mreq.imr_multiaddr.s_addr)
1709
                                break;
1710
                }
1711
                if (i < imo->imo_num_memberships) {
1712
                        error = EADDRINUSE;
1713
                        splx(s);
1714
                        break;
1715
                }
1716
                if (i == IP_MAX_MEMBERSHIPS) {
1717
                        error = ETOOMANYREFS;
1718
                        splx(s);
1719
                        break;
1720
                }
1721
                /*
1722
                 * Everything looks good; add a new record to the multicast
1723
                 * address list for the given interface.
1724
                 */
1725
                if ((imo->imo_membership[i] =
1726
                    in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) {
1727
                        error = ENOBUFS;
1728
                        splx(s);
1729
                        break;
1730
                }
1731
                ++imo->imo_num_memberships;
1732
                splx(s);
1733
                break;
1734
 
1735
        case IP_DROP_MEMBERSHIP:
1736
                /*
1737
                 * Drop a multicast group membership.
1738
                 * Group must be a valid IP multicast address.
1739
                 */
1740
                error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1741
                if (error)
1742
                        break;
1743
 
1744
                if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1745
                        error = EINVAL;
1746
                        break;
1747
                }
1748
 
1749
                s = splimp();
1750
                /*
1751
                 * If an interface address was specified, get a pointer
1752
                 * to its ifnet structure.
1753
                 */
1754
                if (mreq.imr_interface.s_addr == INADDR_ANY)
1755
                        ifp = NULL;
1756
                else {
1757
                        ifp = ip_multicast_if(&mreq.imr_interface, NULL);
1758
                        if (ifp == NULL) {
1759
                                error = EADDRNOTAVAIL;
1760
                                splx(s);
1761
                                break;
1762
                        }
1763
                }
1764
                /*
1765
                 * Find the membership in the membership array.
1766
                 */
1767
                for (i = 0; i < imo->imo_num_memberships; ++i) {
1768
                        if ((ifp == NULL ||
1769
                             imo->imo_membership[i]->inm_ifp == ifp) &&
1770
                             imo->imo_membership[i]->inm_addr.s_addr ==
1771
                             mreq.imr_multiaddr.s_addr)
1772
                                break;
1773
                }
1774
                if (i == imo->imo_num_memberships) {
1775
                        error = EADDRNOTAVAIL;
1776
                        splx(s);
1777
                        break;
1778
                }
1779
                /*
1780
                 * Give up the multicast address record to which the
1781
                 * membership points.
1782
                 */
1783
                in_delmulti(imo->imo_membership[i]);
1784
                /*
1785
                 * Remove the gap in the membership array.
1786
                 */
1787
                for (++i; i < imo->imo_num_memberships; ++i)
1788
                        imo->imo_membership[i-1] = imo->imo_membership[i];
1789
                --imo->imo_num_memberships;
1790
                splx(s);
1791
                break;
1792
 
1793
        default:
1794
                error = EOPNOTSUPP;
1795
                break;
1796
        }
1797
 
1798
        /*
1799
         * If all options have default values, no need to keep the mbuf.
1800
         */
1801
        if (imo->imo_multicast_ifp == NULL &&
1802
            imo->imo_multicast_vif == -1 &&
1803
            imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1804
            imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1805
            imo->imo_num_memberships == 0) {
1806
                free(*imop, M_IPMOPTS);
1807
                *imop = NULL;
1808
        }
1809
 
1810
        return (error);
1811
}
1812
 
1813
/*
1814
 * Return the IP multicast options in response to user getsockopt().
1815
 */
1816
static int
1817
ip_getmoptions(sopt, imo)
1818
        struct sockopt *sopt;
1819
        register struct ip_moptions *imo;
1820
{
1821
        struct in_addr addr;
1822
        struct in_ifaddr *ia;
1823
        int error, optval;
1824
        u_char coptval;
1825
 
1826
        error = 0;
1827
        switch (sopt->sopt_name) {
1828
        case IP_MULTICAST_VIF:
1829
                if (imo != NULL)
1830
                        optval = imo->imo_multicast_vif;
1831
                else
1832
                        optval = -1;
1833
                error = sooptcopyout(sopt, &optval, sizeof optval);
1834
                break;
1835
 
1836
        case IP_MULTICAST_IF:
1837
                if (imo == NULL || imo->imo_multicast_ifp == NULL)
1838
                        addr.s_addr = INADDR_ANY;
1839
                else if (imo->imo_multicast_addr.s_addr) {
1840
                        /* return the value user has set */
1841
                        addr = imo->imo_multicast_addr;
1842
                } else {
1843
                        IFP_TO_IA(imo->imo_multicast_ifp, ia);
1844
                        addr.s_addr = (ia == NULL) ? INADDR_ANY
1845
                                : IA_SIN(ia)->sin_addr.s_addr;
1846
                }
1847
                error = sooptcopyout(sopt, &addr, sizeof addr);
1848
                break;
1849
 
1850
        case IP_MULTICAST_TTL:
1851
                if (imo == 0)
1852
                        optval = coptval = IP_DEFAULT_MULTICAST_TTL;
1853
                else
1854
                        optval = coptval = imo->imo_multicast_ttl;
1855
                if (sopt->sopt_valsize == 1)
1856
                        error = sooptcopyout(sopt, &coptval, 1);
1857
                else
1858
                        error = sooptcopyout(sopt, &optval, sizeof optval);
1859
                break;
1860
 
1861
        case IP_MULTICAST_LOOP:
1862
                if (imo == 0)
1863
                        optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
1864
                else
1865
                        optval = coptval = imo->imo_multicast_loop;
1866
                if (sopt->sopt_valsize == 1)
1867
                        error = sooptcopyout(sopt, &coptval, 1);
1868
                else
1869
                        error = sooptcopyout(sopt, &optval, sizeof optval);
1870
                break;
1871
 
1872
        default:
1873
                error = ENOPROTOOPT;
1874
                break;
1875
        }
1876
        return (error);
1877
}
1878
 
1879
/*
1880
 * Discard the IP multicast options.
1881
 */
1882
void
1883
ip_freemoptions(imo)
1884
        register struct ip_moptions *imo;
1885
{
1886
        register int i;
1887
 
1888
        if (imo != NULL) {
1889
                for (i = 0; i < imo->imo_num_memberships; ++i)
1890
                        in_delmulti(imo->imo_membership[i]);
1891
                free(imo, M_IPMOPTS);
1892
        }
1893
}
1894
 
1895
/*
1896
 * Routine called from ip_output() to loop back a copy of an IP multicast
1897
 * packet to the input queue of a specified interface.  Note that this
1898
 * calls the output routine of the loopback "driver", but with an interface
1899
 * pointer that might NOT be a loopback interface -- evil, but easier than
1900
 * replicating that code here.
1901
 */
1902
static void
1903
ip_mloopback(ifp, m, dst, hlen)
1904
        struct ifnet *ifp;
1905
        register struct mbuf *m;
1906
        register struct sockaddr_in *dst;
1907
        int hlen;
1908
{
1909
        register struct ip *ip;
1910
        struct mbuf *copym;
1911
 
1912
        copym = m_copy(m, 0, M_COPYALL);
1913
        if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))
1914
                copym = m_pullup(copym, hlen);
1915
        if (copym != NULL) {
1916
                /*
1917
                 * We don't bother to fragment if the IP length is greater
1918
                 * than the interface's MTU.  Can this possibly matter?
1919
                 */
1920
                ip = mtod(copym, struct ip *);
1921
                HTONS(ip->ip_len);
1922
                HTONS(ip->ip_off);
1923
                ip->ip_sum = 0;
1924
                if (ip->ip_vhl == IP_VHL_BORING) {
1925
                        ip->ip_sum = in_cksum_hdr(ip);
1926
                } else {
1927
                        ip->ip_sum = in_cksum(copym, hlen);
1928
                }
1929
                /*
1930
                 * NB:
1931
                 * It's not clear whether there are any lingering
1932
                 * reentrancy problems in other areas which might
1933
                 * be exposed by using ip_input directly (in
1934
                 * particular, everything which modifies the packet
1935
                 * in-place).  Yet another option is using the
1936
                 * protosw directly to deliver the looped back
1937
                 * packet.  For the moment, we'll err on the side
1938
                 * of safety by using if_simloop().
1939
                 */
1940
#if 1 /* XXX */
1941
                if (dst->sin_family != AF_INET) {
1942
                        printf("ip_mloopback: bad address family %d\n",
1943
                                                dst->sin_family);
1944
                        dst->sin_family = AF_INET;
1945
                }
1946
#endif
1947
 
1948
#ifdef notdef
1949
                copym->m_pkthdr.rcvif = ifp;
1950
                ip_input(copym);
1951
#else
1952
                /* if the checksum hasn't been computed, mark it as valid */
1953
                if (copym->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
1954
                        copym->m_pkthdr.csum_flags |=
1955
                            CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
1956
                        copym->m_pkthdr.csum_data = 0xffff;
1957
                }
1958
                if_simloop(ifp, copym, dst->sin_family, 0);
1959
#endif
1960
        }
1961
}

powered by: WebSVN 2.1.0

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