|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1982, 1986, 1988, 1990, 1993
24: * The Regents of the University of California. All rights reserved.
25: *
26: * Redistribution and use in source and binary forms, with or without
27: * modification, are permitted provided that the following conditions
28: * are met:
29: * 1. Redistributions of source code must retain the above copyright
30: * notice, this list of conditions and the following disclaimer.
31: * 2. Redistributions in binary form must reproduce the above copyright
32: * notice, this list of conditions and the following disclaimer in the
33: * documentation and/or other materials provided with the distribution.
34: * 3. All advertising materials mentioning features or use of this software
35: * must display the following acknowledgement:
36: * This product includes software developed by the University of
37: * California, Berkeley and its contributors.
38: * 4. Neither the name of the University nor the names of its contributors
39: * may be used to endorse or promote products derived from this software
40: * without specific prior written permission.
41: *
42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52: * SUCH DAMAGE.
53: *
54: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
55: */
56:
57: #define _IP_VHL
58:
59: #if ISFB31
60: #include "opt_ipfw.h"
61: #include "opt_ipdn.h"
62: #include "opt_ipdivert.h"
63: #include "opt_ipfilter.h"
64: #endif
65:
66: #include <sys/param.h>
67: #include <sys/systm.h>
68: #include <sys/kernel.h>
69: #include <sys/malloc.h>
70: #include <sys/mbuf.h>
71: #include <sys/protosw.h>
72: #include <sys/socket.h>
73: #include <sys/socketvar.h>
74:
75: #include <net/if.h>
76: #include <net/route.h>
77:
78: #include <netinet/in.h>
79: #include <netinet/in_systm.h>
80: #include <netinet/ip.h>
81: #include <netinet/in_pcb.h>
82: #include <netinet/in_var.h>
83: #include <netinet/ip_var.h>
84: #include <net/dlil.h>
85:
86: #ifdef vax
87: #include <machine/mtpr.h>
88: #endif
89:
90: #if ISFB31
91: #include <machine/in_cksum.h>
92:
93: static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
94: #endif
95:
96: #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
97: #undef COMPAT_IPFW
98: #define COMPAT_IPFW 1
99: #else
100: #undef COMPAT_IPFW
101: #endif
102:
103: #if COMPAT_IPFW
104: #include <netinet/ip_fw.h>
105: #endif
106:
107: #if DUMMYNET
108: #include <netinet/ip_dummynet.h>
109: #endif
110:
111: #if IPFIREWALL_FORWARD_DEBUG
112: #define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
113: (ntohl(a.s_addr)>>16)&0xFF,\
114: (ntohl(a.s_addr)>>8)&0xFF,\
115: (ntohl(a.s_addr))&0xFF);
116: #endif
117:
118: u_short ip_id;
119:
120: static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
121: static void ip_mloopback
122: __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int));
123: static int ip_getmoptions
124: __P((struct sockopt *, struct ip_moptions *));
125: static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *));
126: static int ip_setmoptions
127: __P((struct sockopt *, struct ip_moptions **));
128: static u_long lo_dl_tag = 0;
129:
130: #if IPFILTER_LKM || IPFILTER
131: int ip_optcopy __P((struct ip *, struct ip *));
132: extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
133: #else
134: static int ip_optcopy __P((struct ip *, struct ip *));
135: #endif
136:
137:
138: extern struct protosw inetsw[];
139:
140: /*
141: * IP output. The packet in mbuf chain m contains a skeletal IP
142: * header (with len, off, ttl, proto, tos, src, dst).
143: * The mbuf chain containing the packet will be freed.
144: * The mbuf opt, if present, will not be freed.
145: */
146: int
147: ip_output(m0, opt, ro, flags, imo)
148: struct mbuf *m0;
149: struct mbuf *opt;
150: struct route *ro;
151: int flags;
152: struct ip_moptions *imo;
153: {
154: struct ip *ip, *mhip;
155: struct ifnet *ifp;
156: u_long dl_tag;
157: struct mbuf *m = m0;
158: int hlen = sizeof (struct ip);
159: int len, off, error = 0;
160: struct sockaddr_in *dst;
161: struct in_ifaddr *ia;
162: int isbroadcast;
163: #if IPFIREWALL_FORWARD
164: int fwd_rewrite_src = 0;
165: #endif
166:
167: #if !IPDIVERT /* dummy variable for the firewall code to play with */
168: u_short ip_divert_cookie = 0 ;
169: #endif
170: #if COMPAT_IPFW
171: struct ip_fw_chain *rule = NULL ;
172: #endif
173:
174: #if IPFIREWALL && DUMMYNET
175: /*
176: * dummynet packet are prepended a vestigial mbuf with
177: * m_type = MT_DUMMYNET and m_data pointing to the matching
178: * rule.
179: */
180: if (m->m_type == MT_DUMMYNET) {
181: struct mbuf *tmp_m = m ;
182: /*
183: * the packet was already tagged, so part of the
184: * processing was already done, and we need to go down.
185: * opt, flags and imo have already been used, and now
186: * they are used to hold ifp and hlen and NULL, respectively.
187: */
188: rule = (struct ip_fw_chain *)(m->m_data) ;
189: m = m->m_next ;
190: FREE(tmp_m, M_IPFW);
191: ip = mtod(m, struct ip *);
192: dst = (struct sockaddr_in *)&ro->ro_dst;
193: ifp = (struct ifnet *)opt;
194: hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
195: opt = NULL ;
196: flags = 0 ; /* XXX is this correct ? */
197: goto sendit;
198: } else
199: rule = NULL ;
200: #endif
201:
202: #if DIAGNOSTIC
203: if ((m->m_flags & M_PKTHDR) == 0)
204: panic("ip_output no HDR");
205: if (!ro)
206: panic("ip_output no route, proto = %d",
207: mtod(m, struct ip *)->ip_p);
208: #endif
209: if (opt) {
210: m = ip_insertoptions(m, opt, &len);
211: hlen = len;
212: }
213: ip = mtod(m, struct ip *);
214: /*
215: * Fill in IP header.
216: */
217: if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
218: ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2);
219: ip->ip_off &= IP_DF;
220: ip->ip_id = htons(ip_id++);
221: ipstat.ips_localout++;
222: } else {
223: hlen = IP_VHL_HL(ip->ip_vhl) << 2;
224: }
225:
226: dst = (struct sockaddr_in *)&ro->ro_dst;
227: /*
228: * If there is a cached route,
229: * check that it is to the same destination
230: * and is still up. If not, free it and try again.
231: */
232: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
233: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
234: RTFREE(ro->ro_rt);
235: ro->ro_rt = (struct rtentry *)0;
236: }
237: if (ro->ro_rt == 0) {
238: dst->sin_family = AF_INET;
239: dst->sin_len = sizeof(*dst);
240: dst->sin_addr = ip->ip_dst;
241: }
242: /*
243: * If routing to interface only,
244: * short circuit routing lookup.
245: */
246: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
247: #define sintosa(sin) ((struct sockaddr *)(sin))
248: if (flags & IP_ROUTETOIF) {
249: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
250: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
251: ipstat.ips_noroute++;
252: error = ENETUNREACH;
253: goto bad;
254: }
255: ifp = ia->ia_ifp;
256: dl_tag = ia->ia_ifa.ifa_dlt;
257: ip->ip_ttl = 1;
258: isbroadcast = in_broadcast(dst->sin_addr, ifp);
259: } else {
260: /*
261: * If this is the case, we probably don't want to allocate
262: * a protocol-cloned route since we didn't get one from the
263: * ULP. This lets TCP do its thing, while not burdening
264: * forwarding or ICMP with the overhead of cloning a route.
265: * Of course, we still want to do any cloning requested by
266: * the link layer, as this is probably required in all cases
267: * for correct operation (as it is for ARP).
268: */
269: if (ro->ro_rt == 0)
270: rtalloc_ign(ro, RTF_PRCLONING);
271: if (ro->ro_rt == 0) {
272: ipstat.ips_noroute++;
273: error = EHOSTUNREACH;
274: goto bad;
275: }
276: ia = ifatoia(ro->ro_rt->rt_ifa);
277: ifp = ro->ro_rt->rt_ifp;
278: dl_tag = ro->ro_rt->rt_dlt;
279: ro->ro_rt->rt_use++;
280: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
281: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
282: if (ro->ro_rt->rt_flags & RTF_HOST)
283: isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
284: else
285: isbroadcast = in_broadcast(dst->sin_addr, ifp);
286: }
287: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
288: struct in_multi *inm;
289:
290: m->m_flags |= M_MCAST;
291: /*
292: * IP destination address is multicast. Make sure "dst"
293: * still points to the address in "ro". (It may have been
294: * changed to point to a gateway address, above.)
295: */
296: dst = (struct sockaddr_in *)&ro->ro_dst;
297: /*
298: * See if the caller provided any multicast options
299: */
300: if (imo != NULL) {
301: ip->ip_ttl = imo->imo_multicast_ttl;
302: if (imo->imo_multicast_ifp != NULL)
303: ifp = imo->imo_multicast_ifp;
304: if (imo->imo_multicast_vif != -1)
305: ip->ip_src.s_addr =
306: ip_mcast_src(imo->imo_multicast_vif);
307: } else
308: ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
309: /*
310: * Confirm that the outgoing interface supports multicast.
311: */
312: if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
313: if ((ifp->if_flags & IFF_MULTICAST) == 0) {
314: ipstat.ips_noroute++;
315: error = ENETUNREACH;
316: goto bad;
317: }
318: }
319: /*
320: * If source address not specified yet, use address
321: * of outgoing interface.
322: */
323: if (ip->ip_src.s_addr == INADDR_ANY) {
324: register struct in_ifaddr *ia1;
325:
326: for (ia1 = in_ifaddrhead.tqh_first; ia1;
327: ia1 = ia1->ia_link.tqe_next)
328: if (ia1->ia_ifp == ifp) {
329: ip->ip_src = IA_SIN(ia1)->sin_addr;
330: break;
331: }
332: }
333:
334: IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
335: if (inm != NULL &&
336: (imo == NULL || imo->imo_multicast_loop)) {
337: /*
338: * If we belong to the destination multicast group
339: * on the outgoing interface, and the caller did not
340: * forbid loopback, loop back a copy.
341: */
342: ip_mloopback(ifp, m, dst, hlen);
343: }
344: else {
345: /*
346: * If we are acting as a multicast router, perform
347: * multicast forwarding as if the packet had just
348: * arrived on the interface to which we are about
349: * to send. The multicast forwarding function
350: * recursively calls this function, using the
351: * IP_FORWARDING flag to prevent infinite recursion.
352: *
353: * Multicasts that are looped back by ip_mloopback(),
354: * above, will be forwarded by the ip_input() routine,
355: * if necessary.
356: */
357: if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
358: /*
359: * Check if rsvp daemon is running. If not, don't
360: * set ip_moptions. This ensures that the packet
361: * is multicast and not just sent down one link
362: * as prescribed by rsvpd.
363: */
364: if (!rsvp_on)
365: imo = NULL;
366: if (ip_mforward(ip, ifp, m, imo) != 0) {
367: m_freem(m);
368: goto done;
369: }
370: }
371: }
372:
373: /*
374: * Multicasts with a time-to-live of zero may be looped-
375: * back, above, but must not be transmitted on a network.
376: * Also, multicasts addressed to the loopback interface
377: * are not sent -- the above call to ip_mloopback() will
378: * loop back a copy if this host actually belongs to the
379: * destination group on the loopback interface.
380: */
381: if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
382: m_freem(m);
383: goto done;
384: }
385:
386: goto sendit;
387: }
388: #ifndef notdef
389: /*
390: * If source address not specified yet, use address
391: * of outgoing interface.
392: */
393: if (ip->ip_src.s_addr == INADDR_ANY) {
394: ip->ip_src = IA_SIN(ia)->sin_addr;
395: #if IPFIREWALL_FORWARD
396: /* Keep note that we did this - if the firewall changes
397: * the next-hop, our interface may change, changing the
398: * default source IP. It's a shame so much effort happens
399: * twice. Oh well.
400: */
401: fwd_rewrite_src++;
402: #endif /* IPFIREWALL_FORWARD */
403: }
404: #endif /* notdef */
405: /*
406: * Verify that we have any chance at all of being able to queue
407: * the packet or packet fragments
408: */
409: if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
410: ifp->if_snd.ifq_maxlen) {
411: error = ENOBUFS;
412: goto bad;
413: }
414:
415: /*
416: * Look for broadcast address and
417: * and verify user is allowed to send
418: * such a packet.
419: */
420: if (isbroadcast) {
421: if ((ifp->if_flags & IFF_BROADCAST) == 0) {
422: error = EADDRNOTAVAIL;
423: goto bad;
424: }
425: if ((flags & IP_ALLOWBROADCAST) == 0) {
426: error = EACCES;
427: goto bad;
428: }
429: /* don't allow broadcast messages to be fragmented */
430: if ((u_short)ip->ip_len > ifp->if_mtu) {
431: error = EMSGSIZE;
432: goto bad;
433: }
434: m->m_flags |= M_BCAST;
435: } else {
436: m->m_flags &= ~M_BCAST;
437: }
438:
439: sendit:
440: /*
441: * IpHack's section.
442: * - Xlate: translate packet's addr/port (NAT).
443: * - Firewall: deny/allow/etc.
444: * - Wrap: fake packet's addr/port <unimpl.>
445: * - Encapsulate: put it in another IP and send out. <unimp.>
446: */
447: #if IPFILTER || IPFILTER_LKM
448: if (fr_checkp) {
449: struct mbuf *m1 = m;
450:
451: if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1)
452: goto done;
453: ip = mtod(m = m1, struct ip *);
454: }
455: #endif
456:
457: #if COMPAT_IPFW
458: if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) {
459: error = EACCES;
460: goto done;
461: }
462:
463: /*
464: * Check with the firewall...
465: */
466: if (ip_fw_chk_ptr) {
467: struct sockaddr_in *old = dst;
468:
469: off = (*ip_fw_chk_ptr)(&ip,
470: hlen, ifp, &ip_divert_cookie, &m, &rule, &dst);
471: /*
472: * On return we must do the following:
473: * m == NULL -> drop the pkt
474: * 1<=off<= 0xffff -> DIVERT
475: * (off & 0x10000) -> send to a DUMMYNET pipe
476: * dst != old -> IPFIREWALL_FORWARD
477: * off==0, dst==old -> accept
478: * If some of the above modules is not compiled in, then
479: * we should't have to check the corresponding condition
480: * (because the ipfw control socket should not accept
481: * unsupported rules), but better play safe and drop
482: * packets in case of doubt.
483: */
484: if (!m) { /* firewall said to reject */
485: error = EACCES;
486: goto done;
487: }
488: if (off == 0 && dst == old) /* common case */
489: goto pass ;
490: #if DUMMYNET
491: if (off & 0x10000) {
492: /*
493: * pass the pkt to dummynet. Need to include
494: * pipe number, m, ifp, ro, hlen because these are
495: * not recomputed in the next pass.
496: * All other parameters have been already used and
497: * so they are not needed anymore.
498: * XXX note: if the ifp or ro entry are deleted
499: * while a pkt is in dummynet, we are in trouble!
500: */
501: dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule);
502: goto done;
503: }
504: #endif
505: #if IPDIVERT
506: if (off > 0 && off < 0x10000) { /* Divert packet */
507: ip_divert_port = off & 0xffff ;
508: (*ip_protox[IPPROTO_DIVERT]->pr_input)(m, 0);
509: goto done;
510: }
511: #endif
512:
513: #if IPFIREWALL_FORWARD
514: /* Here we check dst to make sure it's directly reachable on the
515: * interface we previously thought it was.
516: * If it isn't (which may be likely in some situations) we have
517: * to re-route it (ie, find a route for the next-hop and the
518: * associated interface) and set them here. This is nested
519: * forwarding which in most cases is undesirable, except where
520: * such control is nigh impossible. So we do it here.
521: * And I'm babbling.
522: */
523: if (off == 0 && old != dst) {
524: struct in_ifaddr *ia;
525:
526: /* It's changed... */
527: /* There must be a better way to do this next line... */
528: static struct route sro_fwd, *ro_fwd = &sro_fwd;
529: #if IPFIREWALL_FORWARD_DEBUG
530: printf("IPFIREWALL_FORWARD: New dst ip: ");
531: print_ip(dst->sin_addr);
532: printf("\n");
533: #endif
534: /*
535: * We need to figure out if we have been forwarded
536: * to a local socket. If so then we should somehow
537: * "loop back" to ip_input, and get directed to the
538: * PCB as if we had received this packet. This is
539: * because it may be dificult to identify the packets
540: * you want to forward until they are being output
541: * and have selected an interface. (e.g. locally
542: * initiated packets) If we used the loopback inteface,
543: * we would not be able to control what happens
544: * as the packet runs through ip_input() as
545: * it is done through a ISR.
546: */
547: for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
548: ia = TAILQ_NEXT(ia, ia_link)) {
549: /*
550: * If the addr to forward to is one
551: * of ours, we pretend to
552: * be the destination for this packet.
553: */
554: if (IA_SIN(ia)->sin_addr.s_addr ==
555: dst->sin_addr.s_addr)
556: break;
557: }
558: if (ia) {
559: /* tell ip_input "dont filter" */
560: ip_fw_fwd_addr = dst;
561: if (m->m_pkthdr.rcvif == NULL)
562: m->m_pkthdr.rcvif = ifunit("lo0");
563: ip->ip_len = htons((u_short)ip->ip_len);
564: ip->ip_off = htons((u_short)ip->ip_off);
565: ip->ip_sum = 0;
566:
567: ip->ip_sum = in_cksum(m, hlen);
568:
569: ip_input(m);
570: goto done;
571: }
572: /* Some of the logic for this was
573: * nicked from above.
574: *
575: * This rewrites the cached route in a local PCB.
576: * Is this what we want to do?
577: */
578: bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
579:
580: ro_fwd->ro_rt = 0;
581: rtalloc_ign(ro_fwd, RTF_PRCLONING);
582:
583: if (ro_fwd->ro_rt == 0) {
584: ipstat.ips_noroute++;
585: error = EHOSTUNREACH;
586: goto bad;
587: }
588:
589: ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
590: ifp = ro_fwd->ro_rt->rt_ifp;
591: dl_tag = ro->ro_rt->rt_dlt;
592: ro_fwd->ro_rt->rt_use++;
593: if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
594: dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
595: if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
596: isbroadcast =
597: (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
598: else
599: isbroadcast = in_broadcast(dst->sin_addr, ifp);
600: RTFREE(ro->ro_rt);
601: ro->ro_rt = ro_fwd->ro_rt;
602: dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
603:
604: /*
605: * If we added a default src ip earlier,
606: * which would have been gotten from the-then
607: * interface, do it again, from the new one.
608: */
609: if (fwd_rewrite_src)
610: ip->ip_src = IA_SIN(ia)->sin_addr;
611: goto pass ;
612: }
613: #endif /* IPFIREWALL_FORWARD */
614: /*
615: * if we get here, none of the above matches, and
616: * we have to drop the pkt
617: */
618: m_freem(m);
619: error = EACCES; /* not sure this is the right error msg */
620: goto done;
621: }
622: #endif /* COMPAT_IPFW */
623:
624: pass:
625: /*
626: * If small enough for interface, can just send directly.
627: */
628: if ((u_short)ip->ip_len <= ifp->if_mtu) {
629: ip->ip_len = htons((u_short)ip->ip_len);
630: ip->ip_off = htons((u_short)ip->ip_off);
631: ip->ip_sum = 0;
632: ip->ip_sum = in_cksum(m, hlen);
633: error = dlil_output(dl_tag, m, (void *) ro->ro_rt,
634: (struct sockaddr *)dst, 0);
635: goto done;
636: }
637: /*
638: * Too large for interface; fragment if possible.
639: * Must be able to put at least 8 bytes per fragment.
640: */
641: if (ip->ip_off & IP_DF) {
642: error = EMSGSIZE;
643: /*
644: * This case can happen if the user changed the MTU
645: * of an interface after enabling IP on it. Because
646: * most netifs don't keep track of routes pointing to
647: * them, there is no way for one to update all its
648: * routes when the MTU is changed.
649: */
650: if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
651: && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
652: && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
653: ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
654: }
655: ipstat.ips_cantfrag++;
656: goto bad;
657: }
658: len = (ifp->if_mtu - hlen) &~ 7;
659: if (len < 8) {
660: error = EMSGSIZE;
661: goto bad;
662: }
663:
664: {
665: int mhlen, firstlen = len;
666: struct mbuf **mnext = &m->m_nextpkt;
667:
668: /*
669: * Loop through length of segment after first fragment,
670: * make new header and copy data of each part and link onto chain.
671: */
672: m0 = m;
673: mhlen = sizeof (struct ip);
674: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
675: MGETHDR(m, M_DONTWAIT, MT_HEADER);
676: if (m == 0) {
677: error = ENOBUFS;
678: ipstat.ips_odropped++;
679: goto sendorfree;
680: }
681: m->m_flags |= (m0->m_flags & M_MCAST);
682: m->m_data += max_linkhdr;
683: mhip = mtod(m, struct ip *);
684: *mhip = *ip;
685: if (hlen > sizeof (struct ip)) {
686: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
687: mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2);
688: }
689: m->m_len = mhlen;
690: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
691: if (ip->ip_off & IP_MF)
692: mhip->ip_off |= IP_MF;
693: if (off + len >= (u_short)ip->ip_len)
694: len = (u_short)ip->ip_len - off;
695: else
696: mhip->ip_off |= IP_MF;
697: mhip->ip_len = htons((u_short)(len + mhlen));
698: m->m_next = m_copy(m0, off, len);
699: if (m->m_next == 0) {
700: (void) m_free(m);
701: error = ENOBUFS; /* ??? */
702: ipstat.ips_odropped++;
703: goto sendorfree;
704: }
705: m->m_pkthdr.len = mhlen + len;
706: m->m_pkthdr.rcvif = (struct ifnet *)0;
707: mhip->ip_off = htons((u_short)mhip->ip_off);
708: mhip->ip_sum = 0;
709: mhip->ip_sum = in_cksum(m, mhlen);
710: *mnext = m;
711: mnext = &m->m_nextpkt;
712: ipstat.ips_ofragments++;
713: }
714: /*
715: * Update first fragment by trimming what's been copied out
716: * and updating header, then send each fragment (in order).
717: */
718: m = m0;
719: m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
720: m->m_pkthdr.len = hlen + firstlen;
721: ip->ip_len = htons((u_short)m->m_pkthdr.len);
722: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
723: ip->ip_sum = 0;
724: ip->ip_sum = in_cksum(m, hlen);
725:
726: sendorfree:
727: for (m = m0; m; m = m0) {
728: m0 = m->m_nextpkt;
729: m->m_nextpkt = 0;
730: if (error == 0)
731: error = dlil_output(dl_tag, m, (void *) ro->ro_rt,
732: (struct sockaddr *)dst, 0);
733: else
734: m_freem(m);
735: }
736:
737: if (error == 0)
738: ipstat.ips_fragmented++;
739: }
740: done:
741: return (error);
742: bad:
743: m_freem(m0);
744: goto done;
745: }
746:
747: /*
748: * Insert IP options into preformed packet.
749: * Adjust IP destination as required for IP source routing,
750: * as indicated by a non-zero in_addr at the start of the options.
751: *
752: * XXX This routine assumes that the packet has no options in place.
753: */
754: static struct mbuf *
755: ip_insertoptions(m, opt, phlen)
756: register struct mbuf *m;
757: struct mbuf *opt;
758: int *phlen;
759: {
760: register struct ipoption *p = mtod(opt, struct ipoption *);
761: struct mbuf *n;
762: register struct ip *ip = mtod(m, struct ip *);
763: unsigned optlen;
764:
765: optlen = opt->m_len - sizeof(p->ipopt_dst);
766: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
767: return (m); /* XXX should fail */
768: if (p->ipopt_dst.s_addr)
769: ip->ip_dst = p->ipopt_dst;
770: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
771: MGETHDR(n, M_DONTWAIT, MT_HEADER);
772: if (n == 0)
773: return (m);
774: n->m_pkthdr.len = m->m_pkthdr.len + optlen;
775: m->m_len -= sizeof(struct ip);
776: m->m_data += sizeof(struct ip);
777: n->m_next = m;
778: m = n;
779: m->m_len = optlen + sizeof(struct ip);
780: m->m_data += max_linkhdr;
781: (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
782: } else {
783: m->m_data -= optlen;
784: m->m_len += optlen;
785: m->m_pkthdr.len += optlen;
786: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
787: }
788: ip = mtod(m, struct ip *);
789: bcopy(p->ipopt_list, ip + 1, optlen);
790: *phlen = sizeof(struct ip) + optlen;
791: ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2);
792: ip->ip_len += optlen;
793: return (m);
794: }
795:
796: /*
797: * Copy options from ip to jp,
798: * omitting those not copied during fragmentation.
799: */
800: #if !IPFILTER && !IPFILTER_LKM
801: static
802: #endif
803: int
804: ip_optcopy(ip, jp)
805: struct ip *ip, *jp;
806: {
807: register u_char *cp, *dp;
808: int opt, optlen, cnt;
809:
810: cp = (u_char *)(ip + 1);
811: dp = (u_char *)(jp + 1);
812: cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
813: for (; cnt > 0; cnt -= optlen, cp += optlen) {
814: opt = cp[0];
815: if (opt == IPOPT_EOL)
816: break;
817: if (opt == IPOPT_NOP) {
818: /* Preserve for IP mcast tunnel's LSRR alignment. */
819: *dp++ = IPOPT_NOP;
820: optlen = 1;
821: continue;
822: } else
823: optlen = cp[IPOPT_OLEN];
824: /* bogus lengths should have been caught by ip_dooptions */
825: if (optlen > cnt)
826: optlen = cnt;
827: if (IPOPT_COPIED(opt)) {
828: bcopy(cp, dp, optlen);
829: dp += optlen;
830: }
831: }
832: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
833: *dp++ = IPOPT_EOL;
834: return (optlen);
835: }
836:
837: /*
838: * IP socket option processing.
839: */
840: int
841: ip_ctloutput(so, sopt)
842: struct socket *so;
843: struct sockopt *sopt;
844: {
845: struct inpcb *inp = sotoinpcb(so);
846: int error, optval;
847:
848: error = optval = 0;
849: if (sopt->sopt_level != IPPROTO_IP) {
850: return (EINVAL);
851: }
852:
853: switch (sopt->sopt_dir) {
854: case SOPT_SET:
855: switch (sopt->sopt_name) {
856: case IP_OPTIONS:
857: #ifdef notyet
858: case IP_RETOPTS:
859: #endif
860: {
861: struct mbuf *m;
862: if (sopt->sopt_valsize > MLEN) {
863: error = EMSGSIZE;
864: break;
865: }
866: MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
867: if (m == 0) {
868: error = ENOBUFS;
869: break;
870: }
871: m->m_len = sopt->sopt_valsize;
872: error = sooptcopyin(sopt, mtod(m, char *), m->m_len,
873: m->m_len);
874:
875: return (ip_pcbopts(sopt->sopt_name, &inp->inp_options,
876: m));
877: }
878:
879: case IP_TOS:
880: case IP_TTL:
881: case IP_RECVOPTS:
882: case IP_RECVRETOPTS:
883: case IP_RECVDSTADDR:
884: case IP_RECVIF:
885: error = sooptcopyin(sopt, &optval, sizeof optval,
886: sizeof optval);
887: if (error)
888: break;
889:
890: switch (sopt->sopt_name) {
891: case IP_TOS:
892: inp->inp_ip_tos = optval;
893: break;
894:
895: case IP_TTL:
896: inp->inp_ip_ttl = optval;
897: break;
898: #define OPTSET(bit) \
899: if (optval) \
900: inp->inp_flags |= bit; \
901: else \
902: inp->inp_flags &= ~bit;
903:
904: case IP_RECVOPTS:
905: OPTSET(INP_RECVOPTS);
906: break;
907:
908: case IP_RECVRETOPTS:
909: OPTSET(INP_RECVRETOPTS);
910: break;
911:
912: case IP_RECVDSTADDR:
913: OPTSET(INP_RECVDSTADDR);
914: break;
915:
916: case IP_RECVIF:
917: OPTSET(INP_RECVIF);
918: break;
919: }
920: break;
921: #undef OPTSET
922:
923: case IP_MULTICAST_IF:
924: case IP_MULTICAST_VIF:
925: case IP_MULTICAST_TTL:
926: case IP_MULTICAST_LOOP:
927: case IP_ADD_MEMBERSHIP:
928: case IP_DROP_MEMBERSHIP:
929: error = ip_setmoptions(sopt, &inp->inp_moptions);
930: break;
931:
932: case IP_PORTRANGE:
933: error = sooptcopyin(sopt, &optval, sizeof optval,
934: sizeof optval);
935: if (error)
936: break;
937:
938: switch (optval) {
939: case IP_PORTRANGE_DEFAULT:
940: inp->inp_flags &= ~(INP_LOWPORT);
941: inp->inp_flags &= ~(INP_HIGHPORT);
942: break;
943:
944: case IP_PORTRANGE_HIGH:
945: inp->inp_flags &= ~(INP_LOWPORT);
946: inp->inp_flags |= INP_HIGHPORT;
947: break;
948:
949: case IP_PORTRANGE_LOW:
950: inp->inp_flags &= ~(INP_HIGHPORT);
951: inp->inp_flags |= INP_LOWPORT;
952: break;
953:
954: default:
955: error = EINVAL;
956: break;
957: }
958: break;
959:
960: default:
961: error = ENOPROTOOPT;
962: break;
963: }
964: break;
965:
966: case SOPT_GET:
967: switch (sopt->sopt_name) {
968: case IP_OPTIONS:
969: case IP_RETOPTS:
970: if (inp->inp_options)
971: error = sooptcopyout(sopt,
972: mtod(inp->inp_options,
973: char *),
974: inp->inp_options->m_len);
975: else
976: sopt->sopt_valsize = 0;
977: break;
978:
979: case IP_TOS:
980: case IP_TTL:
981: case IP_RECVOPTS:
982: case IP_RECVRETOPTS:
983: case IP_RECVDSTADDR:
984: case IP_RECVIF:
985: case IP_PORTRANGE:
986: switch (sopt->sopt_name) {
987:
988: case IP_TOS:
989: optval = inp->inp_ip_tos;
990: break;
991:
992: case IP_TTL:
993: optval = inp->inp_ip_ttl;
994: break;
995:
996: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
997:
998: case IP_RECVOPTS:
999: optval = OPTBIT(INP_RECVOPTS);
1000: break;
1001:
1002: case IP_RECVRETOPTS:
1003: optval = OPTBIT(INP_RECVRETOPTS);
1004: break;
1005:
1006: case IP_RECVDSTADDR:
1007: optval = OPTBIT(INP_RECVDSTADDR);
1008: break;
1009:
1010: case IP_RECVIF:
1011: optval = OPTBIT(INP_RECVIF);
1012: break;
1013:
1014: case IP_PORTRANGE:
1015: if (inp->inp_flags & INP_HIGHPORT)
1016: optval = IP_PORTRANGE_HIGH;
1017: else if (inp->inp_flags & INP_LOWPORT)
1018: optval = IP_PORTRANGE_LOW;
1019: else
1020: optval = 0;
1021: break;
1022: }
1023: error = sooptcopyout(sopt, &optval, sizeof optval);
1024: break;
1025:
1026: case IP_MULTICAST_IF:
1027: case IP_MULTICAST_VIF:
1028: case IP_MULTICAST_TTL:
1029: case IP_MULTICAST_LOOP:
1030: case IP_ADD_MEMBERSHIP:
1031: case IP_DROP_MEMBERSHIP:
1032: error = ip_getmoptions(sopt, inp->inp_moptions);
1033: break;
1034:
1035: default:
1036: error = ENOPROTOOPT;
1037: break;
1038: }
1039: break;
1040: }
1041: return (error);
1042: }
1043:
1044: /*
1045: * Set up IP options in pcb for insertion in output packets.
1046: * Store in mbuf with pointer in pcbopt, adding pseudo-option
1047: * with destination address if source routed.
1048: */
1049: static int
1050: ip_pcbopts(optname, pcbopt, m)
1051: int optname;
1052: struct mbuf **pcbopt;
1053: register struct mbuf *m;
1054: {
1055: register int cnt, optlen;
1056: register u_char *cp;
1057: u_char opt;
1058:
1059: /* turn off any old options */
1060: if (*pcbopt)
1061: (void)m_free(*pcbopt);
1062: *pcbopt = 0;
1063: if (m == (struct mbuf *)0 || m->m_len == 0) {
1064: /*
1065: * Only turning off any previous options.
1066: */
1067: if (m)
1068: (void)m_free(m);
1069: return (0);
1070: }
1071:
1072: #ifndef vax
1073: if (m->m_len % sizeof(int32_t))
1074: goto bad;
1075: #endif
1076: /*
1077: * IP first-hop destination address will be stored before
1078: * actual options; move other options back
1079: * and clear it when none present.
1080: */
1081: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
1082: goto bad;
1083: cnt = m->m_len;
1084: m->m_len += sizeof(struct in_addr);
1085: cp = mtod(m, u_char *) + sizeof(struct in_addr);
1086: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
1087: bzero(mtod(m, caddr_t), sizeof(struct in_addr));
1088:
1089: for (; cnt > 0; cnt -= optlen, cp += optlen) {
1090: opt = cp[IPOPT_OPTVAL];
1091: if (opt == IPOPT_EOL)
1092: break;
1093: if (opt == IPOPT_NOP)
1094: optlen = 1;
1095: else {
1096: optlen = cp[IPOPT_OLEN];
1097: if (optlen <= IPOPT_OLEN || optlen > cnt)
1098: goto bad;
1099: }
1100: switch (opt) {
1101:
1102: default:
1103: break;
1104:
1105: case IPOPT_LSRR:
1106: case IPOPT_SSRR:
1107: /*
1108: * user process specifies route as:
1109: * ->A->B->C->D
1110: * D must be our final destination (but we can't
1111: * check that since we may not have connected yet).
1112: * A is first hop destination, which doesn't appear in
1113: * actual IP option, but is stored before the options.
1114: */
1115: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
1116: goto bad;
1117: m->m_len -= sizeof(struct in_addr);
1118: cnt -= sizeof(struct in_addr);
1119: optlen -= sizeof(struct in_addr);
1120: cp[IPOPT_OLEN] = optlen;
1121: /*
1122: * Move first hop before start of options.
1123: */
1124: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
1125: sizeof(struct in_addr));
1126: /*
1127: * Then copy rest of options back
1128: * to close up the deleted entry.
1129: */
1130: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
1131: sizeof(struct in_addr)),
1132: (caddr_t)&cp[IPOPT_OFFSET+1],
1133: (unsigned)cnt + sizeof(struct in_addr));
1134: break;
1135: }
1136: }
1137: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
1138: goto bad;
1139: *pcbopt = m;
1140: return (0);
1141:
1142: bad:
1143: (void)m_free(m);
1144: return (EINVAL);
1145: }
1146:
1147: /*
1148: * XXX
1149: * The whole multicast option thing needs to be re-thought.
1150: * Several of these options are equally applicable to non-multicast
1151: * transmission, and one (IP_MULTICAST_TTL) totally duplicates a
1152: * standard option (IP_TTL).
1153: */
1154: /*
1155: * Set the IP multicast options in response to user setsockopt().
1156: */
1157: static int
1158: ip_setmoptions(sopt, imop)
1159: struct sockopt *sopt;
1160: struct ip_moptions **imop;
1161: {
1162: int error = 0;
1163: int i;
1164: struct in_addr addr;
1165: struct ip_mreq mreq;
1166: struct ifnet *ifp;
1167: struct ip_moptions *imo = *imop;
1168: struct route ro;
1169: struct sockaddr_in *dst;
1170: int s;
1171:
1172: if (imo == NULL) {
1173: /*
1174: * No multicast option buffer attached to the pcb;
1175: * allocate one and initialize to default values.
1176: */
1177: imo = (struct ip_moptions*) _MALLOC(sizeof(*imo), M_IPMOPTS,
1178: M_WAITOK);
1179:
1180: if (imo == NULL)
1181: return (ENOBUFS);
1182: *imop = imo;
1183: imo->imo_multicast_ifp = NULL;
1184: imo->imo_multicast_vif = -1;
1185: imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1186: imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
1187: imo->imo_num_memberships = 0;
1188: }
1189:
1190: switch (sopt->sopt_name) {
1191: /* store an index number for the vif you wanna use in the send */
1192: case IP_MULTICAST_VIF:
1193: if (legal_vif_num == 0) {
1194: error = EOPNOTSUPP;
1195: break;
1196: }
1197: error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
1198: if (error)
1199: break;
1200: if (!legal_vif_num(i) && (i != -1)) {
1201: error = EINVAL;
1202: break;
1203: }
1204: imo->imo_multicast_vif = i;
1205: break;
1206:
1207: case IP_MULTICAST_IF:
1208: /*
1209: * Select the interface for outgoing multicast packets.
1210: */
1211: error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr);
1212: if (error)
1213: break;
1214: /*
1215: * INADDR_ANY is used to remove a previous selection.
1216: * When no interface is selected, a default one is
1217: * chosen every time a multicast packet is sent.
1218: */
1219: if (addr.s_addr == INADDR_ANY) {
1220: imo->imo_multicast_ifp = NULL;
1221: break;
1222: }
1223: /*
1224: * The selected interface is identified by its local
1225: * IP address. Find the interface and confirm that
1226: * it supports multicasting.
1227: */
1228: s = splimp();
1229: INADDR_TO_IFP(addr, ifp);
1230: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1231: splx(s);
1232: error = EADDRNOTAVAIL;
1233: break;
1234: }
1235: imo->imo_multicast_ifp = ifp;
1236: splx(s);
1237: break;
1238:
1239: case IP_MULTICAST_TTL:
1240: /*
1241: * Set the IP time-to-live for outgoing multicast packets.
1242: * The original multicast API required a char argument,
1243: * which is inconsistent with the rest of the socket API.
1244: * We allow either a char or an int.
1245: */
1246: if (sopt->sopt_valsize == 1) {
1247: u_char ttl;
1248: error = sooptcopyin(sopt, &ttl, 1, 1);
1249: if (error)
1250: break;
1251: imo->imo_multicast_ttl = ttl;
1252: } else {
1253: u_int ttl;
1254: error = sooptcopyin(sopt, &ttl, sizeof ttl,
1255: sizeof ttl);
1256: if (error)
1257: break;
1258: if (ttl > 255)
1259: error = EINVAL;
1260: else
1261: imo->imo_multicast_ttl = ttl;
1262: }
1263: break;
1264:
1265: case IP_MULTICAST_LOOP:
1266: /*
1267: * Set the loopback flag for outgoing multicast packets.
1268: * Must be zero or one. The original multicast API required a
1269: * char argument, which is inconsistent with the rest
1270: * of the socket API. We allow either a char or an int.
1271: */
1272: if (sopt->sopt_valsize == 1) {
1273: u_char loop;
1274: error = sooptcopyin(sopt, &loop, 1, 1);
1275: if (error)
1276: break;
1277: imo->imo_multicast_loop = !!loop;
1278: } else {
1279: u_int loop;
1280: error = sooptcopyin(sopt, &loop, sizeof loop,
1281: sizeof loop);
1282: if (error)
1283: break;
1284: imo->imo_multicast_loop = !!loop;
1285: }
1286: break;
1287:
1288: case IP_ADD_MEMBERSHIP:
1289: /*
1290: * Add a multicast group membership.
1291: * Group must be a valid IP multicast address.
1292: */
1293: error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1294: if (error)
1295: break;
1296:
1297: if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1298: error = EINVAL;
1299: break;
1300: }
1301: s = splimp();
1302: /*
1303: * If no interface address was provided, use the interface of
1304: * the route to the given multicast address.
1305: */
1306: if (mreq.imr_interface.s_addr == INADDR_ANY) {
1307: bzero((caddr_t)&ro, sizeof(ro));
1308: dst = (struct sockaddr_in *)&ro.ro_dst;
1309: dst->sin_len = sizeof(*dst);
1310: dst->sin_family = AF_INET;
1311: dst->sin_addr = mreq.imr_multiaddr;
1312: rtalloc(&ro);
1313: if (ro.ro_rt == NULL) {
1314: error = EADDRNOTAVAIL;
1315: splx(s);
1316: break;
1317: }
1318: ifp = ro.ro_rt->rt_ifp;
1319: rtfree(ro.ro_rt);
1320: }
1321: else {
1322: INADDR_TO_IFP(mreq.imr_interface, ifp);
1323: }
1324:
1325: /*
1326: * See if we found an interface, and confirm that it
1327: * supports multicast.
1328: */
1329: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1330: error = EADDRNOTAVAIL;
1331: splx(s);
1332: break;
1333: }
1334: /*
1335: * See if the membership already exists or if all the
1336: * membership slots are full.
1337: */
1338: for (i = 0; i < imo->imo_num_memberships; ++i) {
1339: if (imo->imo_membership[i]->inm_ifp == ifp &&
1340: imo->imo_membership[i]->inm_addr.s_addr
1341: == mreq.imr_multiaddr.s_addr)
1342: break;
1343: }
1344: if (i < imo->imo_num_memberships) {
1345: error = EADDRINUSE;
1346: splx(s);
1347: break;
1348: }
1349: if (i == IP_MAX_MEMBERSHIPS) {
1350: error = ETOOMANYREFS;
1351: splx(s);
1352: break;
1353: }
1354: /*
1355: * Everything looks good; add a new record to the multicast
1356: * address list for the given interface.
1357: */
1358: if ((imo->imo_membership[i] =
1359: in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) {
1360: error = ENOBUFS;
1361: splx(s);
1362: break;
1363: }
1364: ++imo->imo_num_memberships;
1365: splx(s);
1366: break;
1367:
1368: case IP_DROP_MEMBERSHIP:
1369: /*
1370: * Drop a multicast group membership.
1371: * Group must be a valid IP multicast address.
1372: */
1373: error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq);
1374: if (error)
1375: break;
1376:
1377: if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) {
1378: error = EINVAL;
1379: break;
1380: }
1381:
1382: s = splimp();
1383: /*
1384: * If an interface address was specified, get a pointer
1385: * to its ifnet structure.
1386: */
1387: if (mreq.imr_interface.s_addr == INADDR_ANY)
1388: ifp = NULL;
1389: else {
1390: INADDR_TO_IFP(mreq.imr_interface, ifp);
1391: if (ifp == NULL) {
1392: error = EADDRNOTAVAIL;
1393: splx(s);
1394: break;
1395: }
1396: }
1397: /*
1398: * Find the membership in the membership array.
1399: */
1400: for (i = 0; i < imo->imo_num_memberships; ++i) {
1401: if ((ifp == NULL ||
1402: imo->imo_membership[i]->inm_ifp == ifp) &&
1403: imo->imo_membership[i]->inm_addr.s_addr ==
1404: mreq.imr_multiaddr.s_addr)
1405: break;
1406: }
1407: if (i == imo->imo_num_memberships) {
1408: error = EADDRNOTAVAIL;
1409: splx(s);
1410: break;
1411: }
1412: /*
1413: * Give up the multicast address record to which the
1414: * membership points.
1415: */
1416: in_delmulti(imo->imo_membership[i]);
1417: /*
1418: * Remove the gap in the membership array.
1419: */
1420: for (++i; i < imo->imo_num_memberships; ++i)
1421: imo->imo_membership[i-1] = imo->imo_membership[i];
1422: --imo->imo_num_memberships;
1423: splx(s);
1424: break;
1425:
1426: default:
1427: error = EOPNOTSUPP;
1428: break;
1429: }
1430:
1431: /*
1432: * If all options have default values, no need to keep the mbuf.
1433: */
1434: if (imo->imo_multicast_ifp == NULL &&
1435: imo->imo_multicast_vif == -1 &&
1436: imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1437: imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1438: imo->imo_num_memberships == 0) {
1439: FREE(*imop, M_IPMOPTS);
1440: *imop = NULL;
1441: }
1442:
1443: return (error);
1444: }
1445:
1446: /*
1447: * Return the IP multicast options in response to user getsockopt().
1448: */
1449: static int
1450: ip_getmoptions(sopt, imo)
1451: struct sockopt *sopt;
1452: register struct ip_moptions *imo;
1453: {
1454: struct in_addr addr;
1455: struct in_ifaddr *ia;
1456: int error, optval;
1457: u_char coptval;
1458:
1459: error = 0;
1460: switch (sopt->sopt_name) {
1461: case IP_MULTICAST_VIF:
1462: if (imo != NULL)
1463: optval = imo->imo_multicast_vif;
1464: else
1465: optval = -1;
1466: error = sooptcopyout(sopt, &optval, sizeof optval);
1467: break;
1468:
1469: case IP_MULTICAST_IF:
1470: if (imo == NULL || imo->imo_multicast_ifp == NULL)
1471: addr.s_addr = INADDR_ANY;
1472: else {
1473: IFP_TO_IA(imo->imo_multicast_ifp, ia);
1474: addr.s_addr = (ia == NULL) ? INADDR_ANY
1475: : IA_SIN(ia)->sin_addr.s_addr;
1476: }
1477: error = sooptcopyout(sopt, &addr, sizeof addr);
1478: break;
1479:
1480: case IP_MULTICAST_TTL:
1481: if (imo == 0)
1482: optval = coptval = IP_DEFAULT_MULTICAST_TTL;
1483: else
1484: optval = coptval = imo->imo_multicast_ttl;
1485: if (sopt->sopt_valsize == 1)
1486: error = sooptcopyout(sopt, &coptval, 1);
1487: else
1488: error = sooptcopyout(sopt, &optval, sizeof optval);
1489: break;
1490:
1491: case IP_MULTICAST_LOOP:
1492: if (imo == 0)
1493: optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
1494: else
1495: optval = coptval = imo->imo_multicast_loop;
1496: if (sopt->sopt_valsize == 1)
1497: error = sooptcopyout(sopt, &coptval, 1);
1498: else
1499: error = sooptcopyout(sopt, &optval, sizeof optval);
1500: break;
1501:
1502: default:
1503: error = ENOPROTOOPT;
1504: break;
1505: }
1506: return (error);
1507: }
1508:
1509: /*
1510: * Discard the IP multicast options.
1511: */
1512: void
1513: ip_freemoptions(imo)
1514: register struct ip_moptions *imo;
1515: {
1516: register int i;
1517:
1518: if (imo != NULL) {
1519: for (i = 0; i < imo->imo_num_memberships; ++i)
1520: in_delmulti(imo->imo_membership[i]);
1521: FREE(imo, M_IPMOPTS);
1522: }
1523: }
1524:
1525: /*
1526: * Routine called from ip_output() to loop back a copy of an IP multicast
1527: * packet to the input queue of a specified interface. Note that this
1528: * calls the output routine of the loopback "driver", but with an interface
1529: * pointer that might NOT be a loopback interface -- evil, but easier than
1530: * replicating that code here.
1531: */
1532: static void
1533: ip_mloopback(ifp, m, dst, hlen)
1534: struct ifnet *ifp;
1535: register struct mbuf *m;
1536: register struct sockaddr_in *dst;
1537: int hlen;
1538: {
1539: register struct ip *ip;
1540: struct mbuf *copym;
1541:
1542: copym = m_copy(m, 0, M_COPYALL);
1543: if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))
1544: copym = m_pullup(copym, hlen);
1545: if (copym != NULL) {
1546: /*
1547: * We don't bother to fragment if the IP length is greater
1548: * than the interface's MTU. Can this possibly matter?
1549: */
1550: ip = mtod(copym, struct ip *);
1551: ip->ip_len = htons((u_short)ip->ip_len);
1552: ip->ip_off = htons((u_short)ip->ip_off);
1553: ip->ip_sum = 0;
1554: ip->ip_sum = in_cksum(copym, hlen);
1555:
1556: /*
1557: * NB:
1558: * It's not clear whether there are any lingering
1559: * reentrancy problems in other areas which might
1560: * be exposed by using ip_input directly (in
1561: * particular, everything which modifies the packet
1562: * in-place). Yet another option is using the
1563: * protosw directly to deliver the looped back
1564: * packet. For the moment, we'll err on the side
1565: * of safety by using if_simloop().
1566: */
1567: #if 1 /* XXX */
1568: if (dst->sin_family != AF_INET) {
1569: printf("ip_mloopback: bad address family %d\n",
1570: dst->sin_family);
1571: dst->sin_family = AF_INET;
1572: }
1573: #endif
1574:
1575: /*
1576: * TedW:
1577: * We need to send all loopback traffic down to dlil in case
1578: * a filter has tapped-in.
1579: */
1580:
1581: if (lo_dl_tag == 0)
1582: dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dl_tag);
1583:
1584: if (lo_dl_tag)
1585: dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0);
1586: else {
1587: printf("Warning: ip_output call to dlil_find_dltag failed!\n");
1588: m_freem(copym);
1589: }
1590:
1591: /* if_simloop(ifp, copym, (struct sockaddr *)dst, 0);*/
1592: }
1593: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.