source: rtems/cpukit/libnetworking/netinet/ip_output.c @ c301570

4.104.114.84.9
Last change on this file since c301570 was c301570, checked in by Ralf Corsepius <ralf.corsepius@…>, on May 10, 2007 at 5:12:54 AM

Include <rtems/bsd/sys/queue.h> instead of <sys/queue.h>.

  • Property mode set to 100644
File size: 31.8 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)ip_output.c 8.3 (Berkeley) 1/21/94
30 * $FreeBSD: src/sys/netinet/ip_output.c,v 1.271 2007/03/23 09:43:36 bms Exp $
31 */
32
33/*
34 *      $Id$
35 */
36
37#define _IP_VHL
38
39#include <sys/param.h>
40#include <rtems/bsd/sys/queue.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/errno.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47#include <sys/socketvar.h>
48
49#include <net/if.h>
50#include <net/route.h>
51
52#include <netinet/in.h>
53#include <netinet/in_systm.h>
54#include <netinet/ip.h>
55#include <netinet/in_pcb.h>
56#include <netinet/in_var.h>
57#include <netinet/ip_var.h>
58
59#include <machine/in_cksum.h>
60
61#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
62#undef COMPAT_IPFW
63#define COMPAT_IPFW 1
64#else
65#undef COMPAT_IPFW
66#endif
67
68u_short ip_id;
69
70static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
71static void     ip_mloopback
72        (struct ifnet *, struct mbuf *, struct sockaddr_in *, int);
73static int      ip_getmoptions
74        (int, struct ip_moptions *, struct mbuf **);
75static int      ip_optcopy(struct ip *, struct ip *);
76static int      ip_pcbopts(struct mbuf **, struct mbuf *);
77static int      ip_setmoptions
78        (int, struct ip_moptions **, struct mbuf *);
79
80extern  struct protosw inetsw[];
81
82/*
83 * IP output.  The packet in mbuf chain m contains a skeletal IP
84 * header (with len, off, ttl, proto, tos, src, dst).
85 * The mbuf chain containing the packet will be freed.
86 * The mbuf opt, if present, will not be freed.
87 */
88int
89ip_output(m0, opt, ro, flags, imo)
90        struct mbuf *m0;
91        struct mbuf *opt;
92        struct route *ro;
93        int flags;
94        struct ip_moptions *imo;
95{
96        struct ip *ip, *mhip;
97        struct ifnet *ifp;
98        struct mbuf *m = m0;
99        int hlen = sizeof (struct ip);
100        int len = 0, off, error = 0;
101        struct sockaddr_in *dst;
102        struct in_ifaddr *ia;
103        int isbroadcast;
104
105#ifdef  DIAGNOSTIC
106        if ((m->m_flags & M_PKTHDR) == 0)
107                panic("ip_output no HDR");
108        if (!ro)
109                panic("ip_output no route, proto = %d",
110                      mtod(m, struct ip *)->ip_p);
111#endif
112        if (opt) {
113                m = ip_insertoptions(m, opt, &len);
114                hlen = len;
115        }
116        ip = mtod(m, struct ip *);
117        /*
118         * Fill in IP header.
119         */
120        if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
121#ifdef _IP_VHL
122                ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2);
123#else
124                ip->ip_v = IPVERSION;
125                ip->ip_hl = hlen >> 2;
126#endif
127                ip->ip_off &= IP_DF;
128                ip->ip_id = htons(ip_id++);
129                ipstat.ips_localout++;
130        } else {
131#ifdef _IP_VHL
132                hlen = IP_VHL_HL(ip->ip_vhl) << 2;
133#else
134                hlen = ip->ip_hl << 2;
135#endif
136        }
137
138        dst = (struct sockaddr_in *)&ro->ro_dst;
139        /*
140         * If there is a cached route,
141         * check that it is to the same destination
142         * and is still up.  If not, free it and try again.
143         */
144        if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
145           dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
146                RTFREE(ro->ro_rt);
147                ro->ro_rt = (struct rtentry *)0;
148        }
149        if (ro->ro_rt == NULL) {
150                dst->sin_family = AF_INET;
151                dst->sin_len = sizeof(*dst);
152                dst->sin_addr = ip->ip_dst;
153        }
154        /*
155         * If routing to interface only,
156         * short circuit routing lookup.
157         */
158#define ifatoia(ifa)    ((struct in_ifaddr *)(ifa))
159#define sintosa(sin)    ((struct sockaddr *)(sin))
160        if (flags & IP_ROUTETOIF) {
161                if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
162                    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
163                        ipstat.ips_noroute++;
164                        error = ENETUNREACH;
165                        goto bad;
166                }
167                ifp = ia->ia_ifp;
168                ip->ip_ttl = 1;
169                isbroadcast = in_broadcast(dst->sin_addr, ifp);
170        } else {
171                /*
172                 * If this is the case, we probably don't want to allocate
173                 * a protocol-cloned route since we didn't get one from the
174                 * ULP.  This lets TCP do its thing, while not burdening
175                 * forwarding or ICMP with the overhead of cloning a route.
176                 * Of course, we still want to do any cloning requested by
177                 * the link layer, as this is probably required in all cases
178                 * for correct operation (as it is for ARP).
179                 */
180                if (ro->ro_rt == 0)
181                        rtalloc_ign(ro, RTF_PRCLONING);
182                if (ro->ro_rt == 0) {
183                        ipstat.ips_noroute++;
184                        error = EHOSTUNREACH;
185                        goto bad;
186                }
187                ia = ifatoia(ro->ro_rt->rt_ifa);
188                ifp = ro->ro_rt->rt_ifp;
189                ro->ro_rt->rt_use++;
190                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
191                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
192                if (ro->ro_rt->rt_flags & RTF_HOST)
193                        isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
194                else
195                        isbroadcast = in_broadcast(dst->sin_addr, ifp);
196        }
197        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
198                struct in_multi *inm;
199
200                m->m_flags |= M_MCAST;
201                /*
202                 * IP destination address is multicast.  Make sure "dst"
203                 * still points to the address in "ro".  (It may have been
204                 * changed to point to a gateway address, above.)
205                 */
206                dst = (struct sockaddr_in *)&ro->ro_dst;
207                /*
208                 * See if the caller provided any multicast options
209                 */
210                if (imo != NULL) {
211                        ip->ip_ttl = imo->imo_multicast_ttl;
212                        if (imo->imo_multicast_ifp != NULL)
213                                ifp = imo->imo_multicast_ifp;
214                        if (imo->imo_multicast_vif != -1)
215                                ip->ip_src.s_addr =
216                                    ip_mcast_src(imo->imo_multicast_vif);
217                } else
218                        ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
219                /*
220                 * Confirm that the outgoing interface supports multicast.
221                 */
222                if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
223                        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
224                                ipstat.ips_noroute++;
225                                error = ENETUNREACH;
226                                goto bad;
227                        }
228                }
229                /*
230                 * If source address not specified yet, use address
231                 * of outgoing interface.
232                 */
233                if (ip->ip_src.s_addr == INADDR_ANY) {
234                        register struct in_ifaddr *ia;
235
236                        for (ia = in_ifaddr; ia; ia = ia->ia_next)
237                                if (ia->ia_ifp == ifp) {
238                                        ip->ip_src = IA_SIN(ia)->sin_addr;
239                                        break;
240                                }
241                }
242
243                IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
244                if (inm != NULL &&
245                   (imo == NULL || imo->imo_multicast_loop)) {
246                        /*
247                         * If we belong to the destination multicast group
248                         * on the outgoing interface, and the caller did not
249                         * forbid loopback, loop back a copy.
250                         */
251                        ip_mloopback(ifp, m, dst, hlen);
252                }
253                else {
254                        /*
255                         * If we are acting as a multicast router, perform
256                         * multicast forwarding as if the packet had just
257                         * arrived on the interface to which we are about
258                         * to send.  The multicast forwarding function
259                         * recursively calls this function, using the
260                         * IP_FORWARDING flag to prevent infinite recursion.
261                         *
262                         * Multicasts that are looped back by ip_mloopback(),
263                         * above, will be forwarded by the ip_input() routine,
264                         * if necessary.
265                         */
266                        if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
267                                /*
268                                 * Check if rsvp daemon is running. If not, don't
269                                 * set ip_moptions. This ensures that the packet
270                                 * is multicast and not just sent down one link
271                                 * as prescribed by rsvpd.
272                                 */
273                                if (!rsvp_on)
274                                  imo = NULL;
275                                if (ip_mforward(ip, ifp, m, imo) != 0) {
276                                        m_freem(m);
277                                        goto done;
278                                }
279                        }
280                }
281
282                /*
283                 * Multicasts with a time-to-live of zero may be looped-
284                 * back, above, but must not be transmitted on a network.
285                 * Also, multicasts addressed to the loopback interface
286                 * are not sent -- the above call to ip_mloopback() will
287                 * loop back a copy if this host actually belongs to the
288                 * destination group on the loopback interface.
289                 */
290                if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
291                        m_freem(m);
292                        goto done;
293                }
294
295                goto sendit;
296        }
297#ifndef notdef
298        /*
299         * If source address not specified yet, use address
300         * of outgoing interface.
301         */
302        if (ip->ip_src.s_addr == INADDR_ANY)
303                ip->ip_src = IA_SIN(ia)->sin_addr;
304#endif
305        /*
306         * Verify that we have any chance at all of being able to queue
307         *      the packet or packet fragments
308         */
309        if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
310                ifp->if_snd.ifq_maxlen) {
311                        error = ENOBUFS;
312                        goto bad;
313        }
314
315        /*
316         * Look for broadcast address and
317         * verify user is allowed to send
318         * such a packet.
319         */
320        if (isbroadcast) {
321                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
322                        error = EADDRNOTAVAIL;
323                        goto bad;
324                }
325                if ((flags & IP_ALLOWBROADCAST) == 0) {
326                        error = EACCES;
327                        goto bad;
328                }
329                /* don't allow broadcast messages to be fragmented */
330                if (ip->ip_len > ifp->if_mtu) {
331                        error = EMSGSIZE;
332                        goto bad;
333                }
334                m->m_flags |= M_BCAST;
335        } else {
336                m->m_flags &= ~M_BCAST;
337        }
338
339sendit:
340        /*
341         * IpHack's section.
342         * - Xlate: translate packet's addr/port (NAT).
343         * - Firewall: deny/allow/etc.
344         * - Wrap: fake packet's addr/port <unimpl.>
345         * - Encapsulate: put it in another IP and send out. <unimp.>
346         */ 
347
348#ifdef COMPAT_IPFW
349        if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) {
350                error = EACCES; 
351                goto done;
352        }
353
354        /*
355         * Check with the firewall...
356         */
357        if (ip_fw_chk_ptr) {
358#ifdef IPDIVERT
359                ip_divert_port = (*ip_fw_chk_ptr)(&ip,
360                    hlen, ifp, ip_divert_ignore, &m);
361                ip_divert_ignore = 0;
362                if (ip_divert_port) {           /* Divert packet */
363                        (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
364                        goto done;
365                }
366#else
367                /* If ipfw says divert, we have to just drop packet */
368                if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, 0, &m)) {
369                        m_freem(m);
370                        goto done;
371                }
372#endif
373                if (!m) {
374                        error = EACCES;
375                        goto done;
376                }
377        }
378#endif /* COMPAT_IPFW */
379
380        /*
381         * If small enough for interface, or the interface will take
382         * care of the fragmentation for us, we can just send directly.
383         */
384        if ((u_short)ip->ip_len <= ifp->if_mtu) {
385                ip->ip_len = htons(ip->ip_len);
386                ip->ip_off = htons(ip->ip_off);
387                ip->ip_sum = 0;
388#ifdef _IP_VHL
389                if (ip->ip_vhl == IP_VHL_BORING) {
390#else
391                if ((ip->ip_hl == 5) && (ip->ip_v = IPVERSION)) {
392#endif
393                        ip->ip_sum = in_cksum_hdr(ip);
394                } else {
395                        ip->ip_sum = in_cksum(m, hlen);
396                }
397                error = (*ifp->if_output)(ifp, m,
398                                (struct sockaddr *)dst, ro->ro_rt);
399                goto done;
400        }
401        /*
402         * Too large for interface; fragment if possible.
403         * Must be able to put at least 8 bytes per fragment.
404         */
405        if (ip->ip_off & IP_DF) {
406                error = EMSGSIZE;
407                /*
408                 * This case can happen if the user changed the MTU
409                 * of an interface after enabling IP on it.  Because
410                 * most netifs don't keep track of routes pointing to
411                 * them, there is no way for one to update all its
412                 * routes when the MTU is changed.
413                 */
414                if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
415                    && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
416                    && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
417                        ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
418                }
419                ipstat.ips_cantfrag++;
420                goto bad;
421        }
422        len = (ifp->if_mtu - hlen) &~ 7;
423        if (len < 8) {
424                error = EMSGSIZE;
425                goto bad;
426        }
427
428    {
429        int mhlen, firstlen = len;
430        struct mbuf **mnext = &m->m_nextpkt;
431
432        /*
433         * Loop through length of segment after first fragment,
434         * make new header and copy data of each part and link onto chain.
435         */
436        m0 = m;
437        mhlen = sizeof (struct ip);
438        for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
439                MGETHDR(m, M_DONTWAIT, MT_HEADER);
440                if (m == 0) {
441                        error = ENOBUFS;
442                        ipstat.ips_odropped++;
443                        goto sendorfree;
444                }
445                m->m_data += max_linkhdr;
446                mhip = mtod(m, struct ip *);
447                *mhip = *ip;
448                if (hlen > sizeof (struct ip)) {
449                        mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
450#ifdef _IP_VHL
451                        mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
452#else
453                        mhip->ip_v = IPVERSION;
454                        mhip->ip_hl = mhlen >> 2;
455#endif
456                }
457                m->m_len = mhlen;
458                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
459                if (ip->ip_off & IP_MF)
460                        mhip->ip_off |= IP_MF;
461                if (off + len >= (u_short)ip->ip_len)
462                        len = (u_short)ip->ip_len - off;
463                else
464                        mhip->ip_off |= IP_MF;
465                mhip->ip_len = htons((u_short)(len + mhlen));
466                m->m_next = m_copy(m0, off, len);
467                if (m->m_next == 0) {
468                        (void) m_free(m);
469                        error = ENOBUFS;        /* ??? */
470                        ipstat.ips_odropped++;
471                        goto sendorfree;
472                }
473                m->m_pkthdr.len = mhlen + len;
474                m->m_pkthdr.rcvif = NULL;
475                mhip->ip_off = htons(mhip->ip_off);
476                mhip->ip_sum = 0;
477#ifdef _IP_VHL
478                if (mhip->ip_vhl == IP_VHL_BORING) {
479#else
480                if ((mhip->ip_hl == 5) && (mhip->ip_v == IPVERSION) ) {
481#endif
482                        mhip->ip_sum = in_cksum_hdr(mhip);
483                } else {
484                        mhip->ip_sum = in_cksum(m, mhlen);
485                }
486                *mnext = m;
487                mnext = &m->m_nextpkt;
488                ipstat.ips_ofragments++;
489        }
490        /*
491         * Update first fragment by trimming what's been copied out
492         * and updating header, then send each fragment (in order).
493         */
494        m = m0;
495        m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
496        m->m_pkthdr.len = hlen + firstlen;
497        ip->ip_len = htons((u_short)m->m_pkthdr.len);
498        ip->ip_off |= IP_MF;
499        ip->ip_off = htons(ip->ip_off);
500        ip->ip_sum = 0;
501#ifdef _IP_VHL
502        if (ip->ip_vhl == IP_VHL_BORING) {
503#else
504        if ((ip->ip_hl == 5) && (ip->ip_v == IPVERSION) ) {
505#endif
506                ip->ip_sum = in_cksum_hdr(ip);
507        } else {
508                ip->ip_sum = in_cksum(m, hlen);
509        }
510sendorfree:
511        for (m = m0; m; m = m0) {
512                m0 = m->m_nextpkt;
513                m->m_nextpkt = 0;
514                if (error == 0)
515                        error = (*ifp->if_output)(ifp, m,
516                            (struct sockaddr *)dst, ro->ro_rt);
517                else
518                        m_freem(m);
519        }
520
521        if (error == 0)
522                ipstat.ips_fragmented++;
523    }
524done:
525        return (error);
526bad:
527        m_freem(m0);
528        goto done;
529}
530
531/*
532 * Insert IP options into preformed packet.
533 * Adjust IP destination as required for IP source routing,
534 * as indicated by a non-zero in_addr at the start of the options.
535 *
536 * XXX This routine assumes that the packet has no options in place.
537 */
538static struct mbuf *
539ip_insertoptions(m, opt, phlen)
540        register struct mbuf *m;
541        struct mbuf *opt;
542        int *phlen;
543{
544        register struct ipoption *p = mtod(opt, struct ipoption *);
545        struct mbuf *n;
546        register struct ip *ip = mtod(m, struct ip *);
547        uint32_t optlen;
548
549        optlen = opt->m_len - sizeof(p->ipopt_dst);
550        if (optlen + ip->ip_len > IP_MAXPACKET)
551                return (m);             /* XXX should fail */
552        if (p->ipopt_dst.s_addr)
553                ip->ip_dst = p->ipopt_dst;
554        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
555                MGETHDR(n, M_DONTWAIT, MT_HEADER);
556                if (n == 0)
557                        return (m);
558                n->m_pkthdr.len = m->m_pkthdr.len + optlen;
559                m->m_len -= sizeof(struct ip);
560                m->m_data += sizeof(struct ip);
561                n->m_next = m;
562                m = n;
563                m->m_len = optlen + sizeof(struct ip);
564                m->m_data += max_linkhdr;
565                (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
566        } else {
567                m->m_data -= optlen;
568                m->m_len += optlen;
569                m->m_pkthdr.len += optlen;
570                ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
571        }
572        ip = mtod(m, struct ip *);
573        bcopy(p->ipopt_list, ip + 1, optlen);
574        *phlen = sizeof(struct ip) + optlen;
575#ifdef _IP_VHL
576        ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2);
577#else
578        ip->ip_v = IPVERSION;
579        ip->ip_hl = *phlen >> 2;
580#endif
581        ip->ip_len += optlen;
582        return (m);
583}
584
585/*
586 * Copy options from ip to jp,
587 * omitting those not copied during fragmentation.
588 */
589static int
590ip_optcopy(ip, jp)
591        struct ip *ip, *jp;
592{
593        register u_char *cp, *dp;
594        int opt, optlen, cnt;
595
596        cp = (u_char *)(ip + 1);
597        dp = (u_char *)(jp + 1);
598#ifdef _IP_VHL
599        cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
600#else
601        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
602#endif
603        for (; cnt > 0; cnt -= optlen, cp += optlen) {
604                opt = cp[0];
605                if (opt == IPOPT_EOL)
606                        break;
607                if (opt == IPOPT_NOP) {
608                        /* Preserve for IP mcast tunnel's LSRR alignment. */
609                        *dp++ = IPOPT_NOP;
610                        optlen = 1;
611                        continue;
612                } else
613                        optlen = cp[IPOPT_OLEN];
614                /* bogus lengths should have been caught by ip_dooptions */
615                if (optlen > cnt)
616                        optlen = cnt;
617                if (IPOPT_COPIED(opt)) {
618                        bcopy(cp, dp, optlen);
619                        dp += optlen;
620                }
621        }
622        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
623                *dp++ = IPOPT_EOL;
624        return (optlen);
625}
626
627/*
628 * IP socket option processing.
629 */
630int
631ip_ctloutput(op, so, level, optname, mp)
632        int op;
633        struct socket *so;
634        int level, optname;
635        struct mbuf **mp;
636{
637        struct  inpcb *inp = sotoinpcb(so);
638        register struct mbuf *m = *mp;
639        register int optval = 0;
640        int error = 0;
641
642        if (level != IPPROTO_IP) {
643                error = EINVAL;
644                if (op == PRCO_SETOPT && *mp)
645                        (void) m_free(*mp);
646        } else switch (op) {
647
648        case PRCO_SETOPT:
649                switch (optname) {
650                case IP_OPTIONS:
651#ifdef notyet
652                case IP_RETOPTS:
653                        return (ip_pcbopts(optname, &inp->inp_options, m));
654#else
655                        return (ip_pcbopts(&inp->inp_options, m));
656#endif
657
658                case IP_TOS:
659                case IP_TTL:
660                case IP_RECVOPTS:
661                case IP_RECVRETOPTS:
662                case IP_RECVDSTADDR:
663                case IP_RECVIF:
664                        if (m == 0 || m->m_len != sizeof(int))
665                                error = EINVAL;
666                        else {
667                                optval = *mtod(m, int *);
668                                switch (optname) {
669
670                                case IP_TOS:
671                                        inp->inp_ip_tos = optval;
672                                        break;
673
674                                case IP_TTL:
675                                        inp->inp_ip_ttl = optval;
676                                        break;
677#define OPTSET(bit) \
678        if (optval) \
679                inp->inp_flags |= bit; \
680        else \
681                inp->inp_flags &= ~bit;
682
683                                case IP_RECVOPTS:
684                                        OPTSET(INP_RECVOPTS);
685                                        break;
686
687                                case IP_RECVRETOPTS:
688                                        OPTSET(INP_RECVRETOPTS);
689                                        break;
690
691                                case IP_RECVDSTADDR:
692                                        OPTSET(INP_RECVDSTADDR);
693                                        break;
694
695                                case IP_RECVIF:
696                                        OPTSET(INP_RECVIF);
697                                        break;
698                                }
699                        }
700                        break;
701#undef OPTSET
702
703                case IP_MULTICAST_IF:
704                case IP_MULTICAST_VIF:
705                case IP_MULTICAST_TTL:
706                case IP_MULTICAST_LOOP:
707                case IP_ADD_MEMBERSHIP:
708                case IP_DROP_MEMBERSHIP:
709                        error = ip_setmoptions(optname, &inp->inp_moptions, m);
710                        break;
711
712                case IP_PORTRANGE:
713                        if (m == 0 || m->m_len != sizeof(int))
714                                error = EINVAL;
715                        else {
716                                optval = *mtod(m, int *);
717
718                                switch (optval) {
719
720                                case IP_PORTRANGE_DEFAULT:
721                                        inp->inp_flags &= ~(INP_LOWPORT);
722                                        inp->inp_flags &= ~(INP_HIGHPORT);
723                                        break;
724
725                                case IP_PORTRANGE_HIGH:
726                                        inp->inp_flags &= ~(INP_LOWPORT);
727                                        inp->inp_flags |= INP_HIGHPORT;
728                                        break;
729
730                                case IP_PORTRANGE_LOW:
731                                        inp->inp_flags &= ~(INP_HIGHPORT);
732                                        inp->inp_flags |= INP_LOWPORT;
733                                        break;
734
735                                default:
736                                        error = EINVAL;
737                                        break;
738                                }
739                        }
740                        break;
741
742                default:
743                        error = ENOPROTOOPT;
744                        break;
745                }
746                if (m)
747                        (void)m_free(m);
748                break;
749
750        case PRCO_GETOPT:
751                switch (optname) {
752                case IP_OPTIONS:
753                case IP_RETOPTS:
754                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
755                        if (inp->inp_options) {
756                                m->m_len = inp->inp_options->m_len;
757                                bcopy(mtod(inp->inp_options, void *),
758                                    mtod(m, void *), m->m_len);
759                        } else
760                                m->m_len = 0;
761                        break;
762
763                case IP_TOS:
764                case IP_TTL:
765                case IP_RECVOPTS:
766                case IP_RECVRETOPTS:
767                case IP_RECVDSTADDR:
768                case IP_RECVIF:
769                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
770                        m->m_len = sizeof(int);
771                        switch (optname) {
772
773                        case IP_TOS:
774                                optval = inp->inp_ip_tos;
775                                break;
776
777                        case IP_TTL:
778                                optval = inp->inp_ip_ttl;
779                                break;
780
781#define OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
782
783                        case IP_RECVOPTS:
784                                optval = OPTBIT(INP_RECVOPTS);
785                                break;
786
787                        case IP_RECVRETOPTS:
788                                optval = OPTBIT(INP_RECVRETOPTS);
789                                break;
790
791                        case IP_RECVDSTADDR:
792                                optval = OPTBIT(INP_RECVDSTADDR);
793                                break;
794
795                        case IP_RECVIF:
796                                optval = OPTBIT(INP_RECVIF);
797                                break;
798                        }
799                        *mtod(m, int *) = optval;
800                        break;
801
802                case IP_MULTICAST_IF:
803                case IP_MULTICAST_VIF:
804                case IP_MULTICAST_TTL:
805                case IP_MULTICAST_LOOP:
806                case IP_ADD_MEMBERSHIP:
807                case IP_DROP_MEMBERSHIP:
808                        error = ip_getmoptions(optname, inp->inp_moptions, mp);
809                        break;
810
811                case IP_PORTRANGE:
812                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
813                        m->m_len = sizeof(int);
814
815                        if (inp->inp_flags & INP_HIGHPORT)
816                                optval = IP_PORTRANGE_HIGH;
817                        else if (inp->inp_flags & INP_LOWPORT)
818                                optval = IP_PORTRANGE_LOW;
819                        else
820                                optval = 0;
821
822                        *mtod(m, int *) = optval;
823                        break;
824
825                default:
826                        error = ENOPROTOOPT;
827                        break;
828                }
829                break;
830        }
831        return (error);
832}
833
834/*
835 * Set up IP options in pcb for insertion in output packets.
836 * Store in mbuf with pointer in pcbopt, adding pseudo-option
837 * with destination address if source routed.
838 */
839static int
840#ifdef notyet
841ip_pcbopts(optname, pcbopt, m)
842        int optname;
843#else
844ip_pcbopts(pcbopt, m)
845#endif
846        struct mbuf **pcbopt;
847        register struct mbuf *m;
848{
849        register int cnt, optlen;
850        register u_char *cp;
851        u_char opt;
852
853        /* turn off any old options */
854        if (*pcbopt)
855                (void)m_free(*pcbopt);
856        *pcbopt = 0;
857        if (m == (struct mbuf *)0 || m->m_len == 0) {
858                /*
859                 * Only turning off any previous options.
860                 */
861                if (m)
862                        (void)m_free(m);
863                return (0);
864        }
865
866#ifndef vax
867        if (m->m_len % sizeof(long))
868                goto bad;
869#endif
870        /*
871         * IP first-hop destination address will be stored before
872         * actual options; move other options back
873         * and clear it when none present.
874         */
875        if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
876                goto bad;
877        cnt = m->m_len;
878        m->m_len += sizeof(struct in_addr);
879        cp = mtod(m, u_char *) + sizeof(struct in_addr);
880        ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
881        bzero(mtod(m, caddr_t), sizeof(struct in_addr));
882
883        for (; cnt > 0; cnt -= optlen, cp += optlen) {
884                opt = cp[IPOPT_OPTVAL];
885                if (opt == IPOPT_EOL)
886                        break;
887                if (opt == IPOPT_NOP)
888                        optlen = 1;
889                else {
890                        optlen = cp[IPOPT_OLEN];
891                        if (optlen <= IPOPT_OLEN || optlen > cnt)
892                                goto bad;
893                }
894                switch (opt) {
895
896                default:
897                        break;
898
899                case IPOPT_LSRR:
900                case IPOPT_SSRR:
901                        /*
902                         * user process specifies route as:
903                         *      ->A->B->C->D
904                         * D must be our final destination (but we can't
905                         * check that since we may not have connected yet).
906                         * A is first hop destination, which doesn't appear in
907                         * actual IP option, but is stored before the options.
908                         */
909                        if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
910                                goto bad;
911                        m->m_len -= sizeof(struct in_addr);
912                        cnt -= sizeof(struct in_addr);
913                        optlen -= sizeof(struct in_addr);
914                        cp[IPOPT_OLEN] = optlen;
915                        /*
916                         * Move first hop before start of options.
917                         */
918                        bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
919                            sizeof(struct in_addr));
920                        /*
921                         * Then copy rest of options back
922                         * to close up the deleted entry.
923                         */
924                        ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
925                            sizeof(struct in_addr)),
926                            (caddr_t)&cp[IPOPT_OFFSET+1],
927                            (unsigned)cnt + sizeof(struct in_addr));
928                        break;
929                }
930        }
931        if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
932                goto bad;
933        *pcbopt = m;
934        return (0);
935
936bad:
937        (void)m_free(m);
938        return (EINVAL);
939}
940
941/*
942 * Set the IP multicast options in response to user setsockopt().
943 */
944static int
945ip_setmoptions(optname, imop, m)
946        int optname;
947        struct ip_moptions **imop;
948        struct mbuf *m;
949{
950        int error = 0;
951        u_char loop;
952        int i;
953        struct in_addr addr;
954        struct ip_mreq *mreq;
955        struct ifnet *ifp;
956        struct ip_moptions *imo = *imop;
957        struct route ro;
958        register struct sockaddr_in *dst;
959        int s;
960
961        if (imo == NULL) {
962                /*
963                 * No multicast option buffer attached to the pcb;
964                 * allocate one and initialize to default values.
965                 */
966                imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
967                    M_WAITOK);
968
969                if (imo == NULL)
970                        return (ENOBUFS);
971                *imop = imo;
972                imo->imo_multicast_ifp = NULL;
973                imo->imo_multicast_vif = -1;
974                imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
975                imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
976                imo->imo_num_memberships = 0;
977        }
978
979        switch (optname) {
980        /* store an index number for the vif you wanna use in the send */
981        case IP_MULTICAST_VIF:
982                if (!legal_vif_num) {
983                        error = EOPNOTSUPP;
984                        break;
985                }
986                if (m == NULL || m->m_len != sizeof(int)) {
987                        error = EINVAL;
988                        break;
989                }
990                i = *(mtod(m, int *));
991                if (!legal_vif_num(i) && (i != -1)) {
992                        error = EINVAL;
993                        break;
994                }
995                imo->imo_multicast_vif = i;
996                break;
997
998        case IP_MULTICAST_IF:
999                /*
1000                 * Select the interface for outgoing multicast packets.
1001                 */
1002                if (m == NULL || m->m_len != sizeof(struct in_addr)) {
1003                        error = EINVAL;
1004                        break;
1005                }
1006                addr = *(mtod(m, struct in_addr *));
1007                /*
1008                 * INADDR_ANY is used to remove a previous selection.
1009                 * When no interface is selected, a default one is
1010                 * chosen every time a multicast packet is sent.
1011                 */
1012                if (addr.s_addr == INADDR_ANY) {
1013                        imo->imo_multicast_ifp = NULL;
1014                        break;
1015                }
1016                /*
1017                 * The selected interface is identified by its local
1018                 * IP address.  Find the interface and confirm that
1019                 * it supports multicasting.
1020                 */
1021                s = splimp();
1022                INADDR_TO_IFP(addr, ifp);
1023                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1024                        splx(s);
1025                        error = EADDRNOTAVAIL;
1026                        break;
1027                }
1028                imo->imo_multicast_ifp = ifp;
1029                splx(s);
1030                break;
1031
1032        case IP_MULTICAST_TTL:
1033                /*
1034                 * Set the IP time-to-live for outgoing multicast packets.
1035                 */
1036                if (m == NULL || m->m_len != 1) {
1037                        error = EINVAL;
1038                        break;
1039                }
1040                imo->imo_multicast_ttl = *(mtod(m, u_char *));
1041                break;
1042
1043        case IP_MULTICAST_LOOP:
1044                /*
1045                 * Set the loopback flag for outgoing multicast packets.
1046                 * Must be zero or one.
1047                 */
1048                if (m == NULL || m->m_len != 1 ||
1049                   (loop = *(mtod(m, u_char *))) > 1) {
1050                        error = EINVAL;
1051                        break;
1052                }
1053                imo->imo_multicast_loop = loop;
1054                break;
1055
1056        case IP_ADD_MEMBERSHIP:
1057                /*
1058                 * Add a multicast group membership.
1059                 * Group must be a valid IP multicast address.
1060                 */
1061                if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1062                        error = EINVAL;
1063                        break;
1064                }
1065                mreq = mtod(m, struct ip_mreq *);
1066                if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1067                        error = EINVAL;
1068                        break;
1069                }
1070                s = splimp();
1071                /*
1072                 * If no interface address was provided, use the interface of
1073                 * the route to the given multicast address.
1074                 */
1075                if (mreq->imr_interface.s_addr == INADDR_ANY) {
1076                        bzero((caddr_t)&ro, sizeof(ro));
1077                        dst = (struct sockaddr_in *)&ro.ro_dst;
1078                        dst->sin_len = sizeof(*dst);
1079                        dst->sin_family = AF_INET;
1080                        dst->sin_addr = mreq->imr_multiaddr;
1081                        rtalloc(&ro);
1082                        if (ro.ro_rt == NULL) {
1083                                error = EADDRNOTAVAIL;
1084                                splx(s);
1085                                break;
1086                        }
1087                        ifp = ro.ro_rt->rt_ifp;
1088                        rtfree(ro.ro_rt);
1089                }
1090                else {
1091                        INADDR_TO_IFP(mreq->imr_interface, ifp);
1092                }
1093
1094                /*
1095                 * See if we found an interface, and confirm that it
1096                 * supports multicast.
1097                 */
1098                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1099                        error = EADDRNOTAVAIL;
1100                        splx(s);
1101                        break;
1102                }
1103                /*
1104                 * See if the membership already exists or if all the
1105                 * membership slots are full.
1106                 */
1107                for (i = 0; i < imo->imo_num_memberships; ++i) {
1108                        if (imo->imo_membership[i]->inm_ifp == ifp &&
1109                            imo->imo_membership[i]->inm_addr.s_addr
1110                                                == mreq->imr_multiaddr.s_addr)
1111                                break;
1112                }
1113                if (i < imo->imo_num_memberships) {
1114                        error = EADDRINUSE;
1115                        splx(s);
1116                        break;
1117                }
1118                if (i == IP_MAX_MEMBERSHIPS) {
1119                        error = ETOOMANYREFS;
1120                        splx(s);
1121                        break;
1122                }
1123                /*
1124                 * Everything looks good; add a new record to the multicast
1125                 * address list for the given interface.
1126                 */
1127                if ((imo->imo_membership[i] =
1128                    in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
1129                        error = ENOBUFS;
1130                        splx(s);
1131                        break;
1132                }
1133                ++imo->imo_num_memberships;
1134                splx(s);
1135                break;
1136
1137        case IP_DROP_MEMBERSHIP:
1138                /*
1139                 * Drop a multicast group membership.
1140                 * Group must be a valid IP multicast address.
1141                 */
1142                if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1143                        error = EINVAL;
1144                        break;
1145                }
1146                mreq = mtod(m, struct ip_mreq *);
1147                if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1148                        error = EINVAL;
1149                        break;
1150                }
1151
1152                s = splimp();
1153                /*
1154                 * If an interface address was specified, get a pointer
1155                 * to its ifnet structure.
1156                 */
1157                if (mreq->imr_interface.s_addr == INADDR_ANY)
1158                        ifp = NULL;
1159                else {
1160                        INADDR_TO_IFP(mreq->imr_interface, ifp);
1161                        if (ifp == NULL) {
1162                                error = EADDRNOTAVAIL;
1163                                splx(s);
1164                                break;
1165                        }
1166                }
1167                /*
1168                 * Find the membership in the membership array.
1169                 */
1170                for (i = 0; i < imo->imo_num_memberships; ++i) {
1171                        if ((ifp == NULL ||
1172                             imo->imo_membership[i]->inm_ifp == ifp) &&
1173                             imo->imo_membership[i]->inm_addr.s_addr ==
1174                             mreq->imr_multiaddr.s_addr)
1175                                break;
1176                }
1177                if (i == imo->imo_num_memberships) {
1178                        error = EADDRNOTAVAIL;
1179                        splx(s);
1180                        break;
1181                }
1182                /*
1183                 * Give up the multicast address record to which the
1184                 * membership points.
1185                 */
1186                in_delmulti(imo->imo_membership[i]);
1187                /*
1188                 * Remove the gap in the membership array.
1189                 */
1190                for (++i; i < imo->imo_num_memberships; ++i)
1191                        imo->imo_membership[i-1] = imo->imo_membership[i];
1192                --imo->imo_num_memberships;
1193                splx(s);
1194                break;
1195
1196        default:
1197                error = EOPNOTSUPP;
1198                break;
1199        }
1200
1201        /*
1202         * If all options have default values, no need to keep the mbuf.
1203         */
1204        if (imo->imo_multicast_ifp == NULL &&
1205            imo->imo_multicast_vif == -1 &&
1206            imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1207            imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1208            imo->imo_num_memberships == 0) {
1209                free(*imop, M_IPMOPTS);
1210                *imop = NULL;
1211        }
1212
1213        return (error);
1214}
1215
1216/*
1217 * Return the IP multicast options in response to user getsockopt().
1218 */
1219static int
1220ip_getmoptions(optname, imo, mp)
1221        int optname;
1222        register struct ip_moptions *imo;
1223        register struct mbuf **mp;
1224{
1225        u_char *ttl;
1226        u_char *loop;
1227        struct in_addr *addr;
1228        struct in_ifaddr *ia;
1229
1230        *mp = m_get(M_WAIT, MT_SOOPTS);
1231
1232        switch (optname) {
1233
1234        case IP_MULTICAST_VIF: 
1235                if (imo != NULL)
1236                        *(mtod(*mp, int *)) = imo->imo_multicast_vif;
1237                else
1238                        *(mtod(*mp, int *)) = -1;
1239                (*mp)->m_len = sizeof(int);
1240                return(0);
1241
1242        case IP_MULTICAST_IF:
1243                addr = mtod(*mp, struct in_addr *);
1244                (*mp)->m_len = sizeof(struct in_addr);
1245                if (imo == NULL || imo->imo_multicast_ifp == NULL)
1246                        addr->s_addr = INADDR_ANY;
1247                else {
1248                        IFP_TO_IA(imo->imo_multicast_ifp, ia);
1249                        addr->s_addr = (ia == NULL) ? INADDR_ANY
1250                                        : IA_SIN(ia)->sin_addr.s_addr;
1251                }
1252                return (0);
1253
1254        case IP_MULTICAST_TTL:
1255                ttl = mtod(*mp, u_char *);
1256                (*mp)->m_len = 1;
1257                *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
1258                                     : imo->imo_multicast_ttl;
1259                return (0);
1260
1261        case IP_MULTICAST_LOOP:
1262                loop = mtod(*mp, u_char *);
1263                (*mp)->m_len = 1;
1264                *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
1265                                      : imo->imo_multicast_loop;
1266                return (0);
1267
1268        default:
1269                return (EOPNOTSUPP);
1270        }
1271}
1272
1273/*
1274 * Discard the IP multicast options.
1275 */
1276void
1277ip_freemoptions(imo)
1278        register struct ip_moptions *imo;
1279{
1280        register int i;
1281
1282        if (imo != NULL) {
1283                for (i = 0; i < imo->imo_num_memberships; ++i)
1284                        in_delmulti(imo->imo_membership[i]);
1285                free(imo, M_IPMOPTS);
1286        }
1287}
1288
1289/*
1290 * Routine called from ip_output() to loop back a copy of an IP multicast
1291 * packet to the input queue of a specified interface.  Note that this
1292 * calls the output routine of the loopback "driver", but with an interface
1293 * pointer that might NOT be a loopback interface -- evil, but easier than
1294 * replicating that code here.
1295 */
1296static void
1297ip_mloopback(ifp, m, dst, hlen)
1298        struct ifnet *ifp;
1299        register struct mbuf *m;
1300        register struct sockaddr_in *dst;
1301        int hlen;
1302{
1303        register struct ip *ip;
1304        struct mbuf *copym;
1305
1306        copym = m_copy(m, 0, M_COPYALL);
1307        if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))
1308                copym = m_pullup(copym, hlen);
1309        if (copym != NULL) {
1310                /*
1311                 * We don't bother to fragment if the IP length is greater
1312                 * than the interface's MTU.  Can this possibly matter?
1313                 */
1314                ip = mtod(copym, struct ip *);
1315                ip->ip_len = htons(ip->ip_len);
1316                ip->ip_off = htons(ip->ip_off);
1317                ip->ip_sum = 0;
1318#ifdef _IP_VHL
1319                if (ip->ip_vhl == IP_VHL_BORING) {
1320                        ip->ip_sum = in_cksum_hdr(ip);
1321                } else {
1322                        ip->ip_sum = in_cksum(copym, hlen);
1323                }
1324#else
1325                ip->ip_sum = in_cksum(copym, hlen);
1326#endif
1327                /*
1328                 * NB:
1329                 * It's not clear whether there are any lingering
1330                 * reentrancy problems in other areas which might
1331                 * be exposed by using ip_input directly (in
1332                 * particular, everything which modifies the packet
1333                 * in-place).  Yet another option is using the
1334                 * protosw directly to deliver the looped back
1335                 * packet.  For the moment, we'll err on the side
1336                 * of safety by continuing to abuse looutput().
1337                 */
1338#ifdef notdef
1339                copym->m_pkthdr.rcvif = ifp;
1340                ip_input(copym);
1341#else
1342                (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL);
1343#endif
1344        }
1345}
Note: See TracBrowser for help on using the repository browser.