source: rtems/cpukit/libnetworking/netinet/ip_output.c @ 387cc207

4.104.114.84.9
Last change on this file since 387cc207 was 387cc207, checked in by Ralf Corsepius <ralf.corsepius@…>, on Mar 28, 2007 at 5:36:38 AM

Use uint32_t optlen.

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