|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1988, 1990, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
59: */
60:
61: #include <sys/param.h>
62: #include <sys/malloc.h>
63: #include <sys/mbuf.h>
64: #include <sys/errno.h>
65: #include <sys/protosw.h>
66: #include <sys/socket.h>
67: #include <sys/socketvar.h>
68:
69: #include <kernserv/machine/spl.h>
70:
71: #include <net/if.h>
72: #include <net/route.h>
73:
74: #include <netinet/in.h>
75: #include <netinet/in_systm.h>
76: #include <netinet/ip.h>
77: #include <netinet/in_pcb.h>
78: #include <netinet/in_var.h>
79: #include <netinet/ip_var.h>
80:
81: #if NEXT
82: #import <kern/kdebug.h>
83:
84: #if KDEBUG
85:
86: #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 1)
87: #define DBG_LAYER_END NETDBG_CODE(DBG_NETIP, 3)
88: #define DBG_FNC_IP_OUTPUT NETDBG_CODE(DBG_NETIP, (1 << 8) | 1)
89: #endif
90:
91: #endif
92:
93: #ifdef vax
94: #include <machine/mtpr.h>
95: #endif
96:
97: static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
98: static void ip_mloopback
99: __P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
100:
101: /*
102: * IP output. The packet in mbuf chain m contains a skeletal IP
103: * header (with len, off, ttl, proto, tos, src, dst).
104: * The mbuf chain containing the packet will be freed.
105: * The mbuf opt, if present, will not be freed.
106: */
107: int
108: ip_output(m0, opt, ro, flags, imo)
109: struct mbuf *m0;
110: struct mbuf *opt;
111: struct route *ro;
112: int flags;
113: struct ip_moptions *imo;
114: {
115: register struct ip *ip, *mhip;
116: register struct ifnet *ifp;
117: register struct mbuf *m = m0;
118: register int hlen = sizeof (struct ip);
119: int len, off, error = 0;
120: struct route iproute;
121: struct sockaddr_in *dst;
122: struct in_ifaddr *ia;
123:
124:
125: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0);
126:
127: #if DIAGNOSTIC
128: if ((m->m_flags & M_PKTHDR) == 0)
129: panic("ip_output no HDR");
130: #endif
131: if (opt) {
132: m = ip_insertoptions(m, opt, &len);
133: hlen = len;
134: }
135: ip = mtod(m, struct ip *);
136: /*
137: * Fill in IP header.
138: */
139: if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
140: ip->ip_v = IPVERSION;
141: ip->ip_off &= IP_DF;
142: ip->ip_id = htons(ip_id++);
143: ip->ip_hl = hlen >> 2;
144: ipstat.ips_localout++;
145: } else {
146: hlen = ip->ip_hl << 2;
147: }
148:
149:
150:
151: KERNEL_DEBUG(DBG_LAYER_BEG, ip->ip_dst.s_addr,
152: ip->ip_src.s_addr, ip->ip_p, ip->ip_off, ip->ip_len);
153:
154: /*
155: * Route packet.
156: */
157: if (ro == 0) {
158: ro = &iproute;
159: bzero((caddr_t)ro, sizeof (*ro));
160: }
161: dst = (struct sockaddr_in *)&ro->ro_dst;
162: /*
163: * If there is a cached route,
164: * check that it is to the same destination
165: * and is still up. If not, free it and try again.
166: */
167: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
168: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
169: RTFREE(ro->ro_rt);
170: ro->ro_rt = (struct rtentry *)0;
171: }
172: if (ro->ro_rt == 0) {
173: dst->sin_family = AF_INET;
174: dst->sin_len = sizeof(*dst);
175: dst->sin_addr = ip->ip_dst;
176: }
177: /*
178: * If routing to interface only,
179: * short circuit routing lookup.
180: */
181: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
182: #define sintosa(sin) ((struct sockaddr *)(sin))
183: if (flags & IP_ROUTETOIF) {
184: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
185: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
186: ipstat.ips_noroute++;
187: error = ENETUNREACH;
188: goto bad;
189: }
190: ifp = ia->ia_ifp;
191: ip->ip_ttl = 1;
192: } else {
193: if (ro->ro_rt == 0)
194: rtalloc(ro);
195: if (ro->ro_rt == 0) {
196: ipstat.ips_noroute++;
197: error = EHOSTUNREACH;
198: goto bad;
199: }
200: ia = ifatoia(ro->ro_rt->rt_ifa);
201: ifp = ro->ro_rt->rt_ifp;
202: ro->ro_rt->rt_use++;
203: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
204: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
205: }
206: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
207: struct in_multi *inm;
208: extern struct ifnet loif;
209:
210: m->m_flags |= M_MCAST;
211: /*
212: * IP destination address is multicast. Make sure "dst"
213: * still points to the address in "ro". (It may have been
214: * changed to point to a gateway address, above.)
215: */
216: dst = (struct sockaddr_in *)&ro->ro_dst;
217: /*
218: * See if the caller provided any multicast options
219: */
220: if (imo != NULL) {
221: ip->ip_ttl = imo->imo_multicast_ttl;
222: if (imo->imo_multicast_ifp != NULL)
223: ifp = imo->imo_multicast_ifp;
224: } else
225: ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
226: /*
227: * Confirm that the outgoing interface supports multicast.
228: */
229: if ((ifp->if_flags & IFF_MULTICAST) == 0) {
230: ipstat.ips_noroute++;
231: error = ENETUNREACH;
232: goto bad;
233: }
234: /*
235: * If source address not specified yet, use address
236: * of outgoing interface.
237: */
238: if (ip->ip_src.s_addr == INADDR_ANY) {
239: register struct in_ifaddr *ia;
240:
241: for (ia = in_ifaddr; ia; ia = ia->ia_next)
242: if (ia->ia_ifp == ifp) {
243: ip->ip_src = IA_SIN(ia)->sin_addr;
244: break;
245: }
246: }
247:
248: IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
249: if (inm != NULL &&
250: (imo == NULL || imo->imo_multicast_loop)) {
251: /*
252: * If we belong to the destination multicast group
253: * on the outgoing interface, and the caller did not
254: * forbid loopback, loop back a copy.
255: */
256: ip_mloopback(ifp, m, dst);
257: }
258: #if MROUTING
259: else {
260: /*
261: * If we are acting as a multicast router, perform
262: * multicast forwarding as if the packet had just
263: * arrived on the interface to which we are about
264: * to send. The multicast forwarding function
265: * recursively calls this function, using the
266: * IP_FORWARDING flag to prevent infinite recursion.
267: *
268: * Multicasts that are looped back by ip_mloopback(),
269: * above, will be forwarded by the ip_input() routine,
270: * if necessary.
271: */
272: extern struct socket *ip_mrouter;
273: if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
274: if (ip_mforward(m, ifp) != 0) {
275: m_freem(m);
276: goto done;
277: }
278: }
279: }
280: #endif
281: /*
282: * Multicasts with a time-to-live of zero may be looped-
283: * back, above, but must not be transmitted on a network.
284: * Also, multicasts addressed to the loopback interface
285: * are not sent -- the above call to ip_mloopback() will
286: * loop back a copy if this host actually belongs to the
287: * destination group on the loopback interface.
288: */
289: if (ip->ip_ttl == 0 || ifp == &loif) {
290: m_freem(m);
291: goto done;
292: }
293:
294: goto sendit;
295: }
296: #ifndef notdef
297: /*
298: * If source address not specified yet, use address
299: * of outgoing interface.
300: */
301: if (ip->ip_src.s_addr == INADDR_ANY)
302: ip->ip_src = IA_SIN(ia)->sin_addr;
303: #endif
304: /*
305: * Look for broadcast address and
306: * and verify user is allowed to send
307: * such a packet.
308: */
309: if (in_broadcast(dst->sin_addr, ifp)) {
310: if ((ifp->if_flags & IFF_BROADCAST) == 0) {
311: error = EADDRNOTAVAIL;
312: goto bad;
313: }
314: if ((flags & IP_ALLOWBROADCAST) == 0) {
315: error = EACCES;
316: goto bad;
317: }
318: /* don't allow broadcast messages to be fragmented */
319: if ((u_short)ip->ip_len > ifp->if_mtu) {
320: error = EMSGSIZE;
321: goto bad;
322: }
323: m->m_flags |= M_BCAST;
324: } else
325: m->m_flags &= ~M_BCAST;
326:
327: sendit:
328: /*
329: * If small enough for interface, can just send directly.
330: */
331: if ((u_short)ip->ip_len <= ifp->if_mtu) {
332: ip->ip_len = htons((u_short)ip->ip_len);
333: ip->ip_off = htons((u_short)ip->ip_off);
334: ip->ip_sum = 0;
335: ip->ip_sum = in_cksum(m, hlen);
336: error = (*ifp->if_output)(ifp, m,
337: (struct sockaddr *)dst, ro->ro_rt);
338: goto done;
339: }
340: /*
341: * Too large for interface; fragment if possible.
342: * Must be able to put at least 8 bytes per fragment.
343: */
344: if (ip->ip_off & IP_DF) {
345: error = EMSGSIZE;
346: ipstat.ips_cantfrag++;
347: goto bad;
348: }
349: len = (ifp->if_mtu - hlen) &~ 7;
350: if (len < 8) {
351: error = EMSGSIZE;
352: goto bad;
353: }
354:
355: {
356: int mhlen, firstlen = len;
357: struct mbuf **mnext = &m->m_nextpkt;
358:
359: /*
360: * Loop through length of segment after first fragment,
361: * make new header and copy data of each part and link onto chain.
362: */
363: m0 = m;
364: mhlen = sizeof (struct ip);
365: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
366: MGETHDR(m, M_DONTWAIT, MT_HEADER);
367: if (m == 0) {
368: error = ENOBUFS;
369: ipstat.ips_odropped++;
370: goto sendorfree;
371: }
372: m->m_data += max_linkhdr;
373: mhip = mtod(m, struct ip *);
374: *mhip = *ip;
375: if (hlen > sizeof (struct ip)) {
376: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
377: mhip->ip_hl = mhlen >> 2;
378: }
379: m->m_len = mhlen;
380: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
381: if (ip->ip_off & IP_MF)
382: mhip->ip_off |= IP_MF;
383: if (off + len >= (u_short)ip->ip_len)
384: len = (u_short)ip->ip_len - off;
385: else
386: mhip->ip_off |= IP_MF;
387: mhip->ip_len = htons((u_short)(len + mhlen));
388: m->m_next = m_copy(m0, off, len);
389: if (m->m_next == 0) {
390: (void) m_free(m);
391: error = ENOBUFS; /* ??? */
392: ipstat.ips_odropped++;
393: goto sendorfree;
394: }
395: m->m_pkthdr.len = mhlen + len;
396: m->m_pkthdr.rcvif = (struct ifnet *)0;
397: mhip->ip_off = htons((u_short)mhip->ip_off);
398: mhip->ip_sum = 0;
399: mhip->ip_sum = in_cksum(m, mhlen);
400: *mnext = m;
401: mnext = &m->m_nextpkt;
402: ipstat.ips_ofragments++;
403: }
404: /*
405: * Update first fragment by trimming what's been copied out
406: * and updating header, then send each fragment (in order).
407: */
408: m = m0;
409: m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
410: m->m_pkthdr.len = hlen + firstlen;
411: ip->ip_len = htons((u_short)m->m_pkthdr.len);
412: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
413: ip->ip_sum = 0;
414: ip->ip_sum = in_cksum(m, hlen);
415: sendorfree:
416:
417: KERNEL_DEBUG(DBG_LAYER_END, ip->ip_dst.s_addr,
418: ip->ip_src.s_addr, ip->ip_p, ip->ip_off, ip->ip_len);
419:
420: for (m = m0; m; m = m0) {
421: m0 = m->m_nextpkt;
422: m->m_nextpkt = 0;
423: if (error == 0)
424: error = (*ifp->if_output)(ifp, m,
425: (struct sockaddr *)dst, ro->ro_rt);
426: else
427: m_freem(m);
428: }
429:
430: if (error == 0)
431: ipstat.ips_fragmented++;
432: }
433: done:
434: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
435: RTFREE(ro->ro_rt);
436:
437: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0);
438:
439: return (error);
440: bad:
441: m_freem(m0);
442: goto done;
443: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0);
444: }
445:
446: /*
447: * Insert IP options into preformed packet.
448: * Adjust IP destination as required for IP source routing,
449: * as indicated by a non-zero in_addr at the start of the options.
450: */
451: static struct mbuf *
452: ip_insertoptions(m, opt, phlen)
453: register struct mbuf *m;
454: struct mbuf *opt;
455: int *phlen;
456: {
457: register struct ipoption *p = mtod(opt, struct ipoption *);
458: struct mbuf *n;
459: register struct ip *ip = mtod(m, struct ip *);
460: unsigned optlen;
461:
462: optlen = opt->m_len - sizeof(p->ipopt_dst);
463: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
464: return (m); /* XXX should fail */
465: if (p->ipopt_dst.s_addr)
466: ip->ip_dst = p->ipopt_dst;
467: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
468: MGETHDR(n, M_DONTWAIT, MT_HEADER);
469: if (n == 0)
470: return (m);
471: n->m_pkthdr.len = m->m_pkthdr.len + optlen;
472: m->m_len -= sizeof(struct ip);
473: m->m_data += sizeof(struct ip);
474: n->m_next = m;
475: m = n;
476: m->m_len = optlen + sizeof(struct ip);
477: m->m_data += max_linkhdr;
478: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
479: } else {
480: m->m_data -= optlen;
481: m->m_len += optlen;
482: m->m_pkthdr.len += optlen;
483: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
484: }
485: ip = mtod(m, struct ip *);
486: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
487: *phlen = sizeof(struct ip) + optlen;
488: ip->ip_len += optlen;
489: return (m);
490: }
491:
492: /*
493: * Copy options from ip to jp,
494: * omitting those not copied during fragmentation.
495: */
496: int
497: ip_optcopy(ip, jp)
498: struct ip *ip, *jp;
499: {
500: register u_char *cp, *dp;
501: int opt, optlen, cnt;
502:
503: cp = (u_char *)(ip + 1);
504: dp = (u_char *)(jp + 1);
505: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
506: for (; cnt > 0; cnt -= optlen, cp += optlen) {
507: opt = cp[0];
508: if (opt == IPOPT_EOL)
509: break;
510: if (opt == IPOPT_NOP) {
511: /* Preserve for IP mcast tunnel's LSRR alignment. */
512: *dp++ = IPOPT_NOP;
513: optlen = 1;
514: continue;
515: } else
516: optlen = cp[IPOPT_OLEN];
517: /* bogus lengths should have been caught by ip_dooptions */
518: if (optlen > cnt)
519: optlen = cnt;
520: if (IPOPT_COPIED(opt)) {
521: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
522: dp += optlen;
523: }
524: }
525: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
526: *dp++ = IPOPT_EOL;
527: return (optlen);
528: }
529:
530: /*
531: * IP socket option processing.
532: */
533: int
534: ip_ctloutput(op, so, level, optname, mp)
535: int op;
536: struct socket *so;
537: int level, optname;
538: struct mbuf **mp;
539: {
540: register struct inpcb *inp = sotoinpcb(so);
541: register struct mbuf *m = *mp;
542: register int optval;
543: int error = 0;
544:
545: if (level != IPPROTO_IP) {
546: error = EINVAL;
547: if (op == PRCO_SETOPT && *mp)
548: (void) m_free(*mp);
549: } else switch (op) {
550:
551: case PRCO_SETOPT:
552: switch (optname) {
553: case IP_OPTIONS:
554: #ifdef notyet
555: case IP_RETOPTS:
556: return (ip_pcbopts(optname, &inp->inp_options, m));
557: #else
558: return (ip_pcbopts(&inp->inp_options, m));
559: #endif
560:
561: case IP_TOS:
562: case IP_TTL:
563: case IP_RECVOPTS:
564: case IP_RECVRETOPTS:
565: case IP_RECVDSTADDR:
566: if (m->m_len != sizeof(int))
567: error = EINVAL;
568: else {
569: optval = *mtod(m, int *);
570: switch (optname) {
571:
572: case IP_TOS:
573: inp->inp_ip.ip_tos = optval;
574: break;
575:
576: case IP_TTL:
577: inp->inp_ip.ip_ttl = optval;
578: break;
579: #define OPTSET(bit) \
580: if (optval) \
581: inp->inp_flags |= bit; \
582: else \
583: inp->inp_flags &= ~bit;
584:
585: case IP_RECVOPTS:
586: OPTSET(INP_RECVOPTS);
587: break;
588:
589: case IP_RECVRETOPTS:
590: OPTSET(INP_RECVRETOPTS);
591: break;
592:
593: case IP_RECVDSTADDR:
594: OPTSET(INP_RECVDSTADDR);
595: break;
596: }
597: }
598: break;
599: #undef OPTSET
600:
601: case IP_MULTICAST_IF:
602: case IP_MULTICAST_TTL:
603: case IP_MULTICAST_LOOP:
604: case IP_ADD_MEMBERSHIP:
605: case IP_DROP_MEMBERSHIP:
606: error = ip_setmoptions(optname, &inp->inp_moptions, m);
607: break;
608:
609: default:
610: error = ENOPROTOOPT;
611: break;
612: }
613: if (m)
614: (void)m_free(m);
615: break;
616:
617: case PRCO_GETOPT:
618: switch (optname) {
619: case IP_OPTIONS:
620: case IP_RETOPTS:
621: *mp = m = m_get(M_WAIT, MT_SOOPTS);
622: if (inp->inp_options) {
623: m->m_len = inp->inp_options->m_len;
624: bcopy(mtod(inp->inp_options, caddr_t),
625: mtod(m, caddr_t), (unsigned)m->m_len);
626: } else
627: m->m_len = 0;
628: break;
629:
630: case IP_TOS:
631: case IP_TTL:
632: case IP_RECVOPTS:
633: case IP_RECVRETOPTS:
634: case IP_RECVDSTADDR:
635: *mp = m = m_get(M_WAIT, MT_SOOPTS);
636: m->m_len = sizeof(int);
637: switch (optname) {
638:
639: case IP_TOS:
640: optval = inp->inp_ip.ip_tos;
641: break;
642:
643: case IP_TTL:
644: optval = inp->inp_ip.ip_ttl;
645: break;
646:
647: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
648:
649: case IP_RECVOPTS:
650: optval = OPTBIT(INP_RECVOPTS);
651: break;
652:
653: case IP_RECVRETOPTS:
654: optval = OPTBIT(INP_RECVRETOPTS);
655: break;
656:
657: case IP_RECVDSTADDR:
658: optval = OPTBIT(INP_RECVDSTADDR);
659: break;
660: }
661: *mtod(m, int *) = optval;
662: break;
663:
664: case IP_MULTICAST_IF:
665: case IP_MULTICAST_TTL:
666: case IP_MULTICAST_LOOP:
667: case IP_ADD_MEMBERSHIP:
668: case IP_DROP_MEMBERSHIP:
669: error = ip_getmoptions(optname, inp->inp_moptions, mp);
670: break;
671:
672: default:
673: error = ENOPROTOOPT;
674: break;
675: }
676: break;
677: }
678: return (error);
679: }
680:
681: /*
682: * Set up IP options in pcb for insertion in output packets.
683: * Store in mbuf with pointer in pcbopt, adding pseudo-option
684: * with destination address if source routed.
685: */
686: int
687: #ifdef notyet
688: ip_pcbopts(optname, pcbopt, m)
689: int optname;
690: #else
691: ip_pcbopts(pcbopt, m)
692: #endif
693: struct mbuf **pcbopt;
694: register struct mbuf *m;
695: {
696: register cnt, optlen;
697: register u_char *cp;
698: u_char opt;
699:
700: /* turn off any old options */
701: if (*pcbopt)
702: (void)m_free(*pcbopt);
703: *pcbopt = 0;
704: if (m == (struct mbuf *)0 || m->m_len == 0) {
705: /*
706: * Only turning off any previous options.
707: */
708: if (m)
709: (void)m_free(m);
710: return (0);
711: }
712:
713: #ifndef vax
714: if (m->m_len % sizeof(long))
715: goto bad;
716: #endif
717: /*
718: * IP first-hop destination address will be stored before
719: * actual options; move other options back
720: * and clear it when none present.
721: */
722: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
723: goto bad;
724: cnt = m->m_len;
725: m->m_len += sizeof(struct in_addr);
726: cp = mtod(m, u_char *) + sizeof(struct in_addr);
727: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
728: bzero(mtod(m, caddr_t), sizeof(struct in_addr));
729:
730: for (; cnt > 0; cnt -= optlen, cp += optlen) {
731: opt = cp[IPOPT_OPTVAL];
732: if (opt == IPOPT_EOL)
733: break;
734: if (opt == IPOPT_NOP)
735: optlen = 1;
736: else {
737: optlen = cp[IPOPT_OLEN];
738: if (optlen <= IPOPT_OLEN || optlen > cnt)
739: goto bad;
740: }
741: switch (opt) {
742:
743: default:
744: break;
745:
746: case IPOPT_LSRR:
747: case IPOPT_SSRR:
748: /*
749: * user process specifies route as:
750: * ->A->B->C->D
751: * D must be our final destination (but we can't
752: * check that since we may not have connected yet).
753: * A is first hop destination, which doesn't appear in
754: * actual IP option, but is stored before the options.
755: */
756: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
757: goto bad;
758: m->m_len -= sizeof(struct in_addr);
759: cnt -= sizeof(struct in_addr);
760: optlen -= sizeof(struct in_addr);
761: cp[IPOPT_OLEN] = optlen;
762: /*
763: * Move first hop before start of options.
764: */
765: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
766: sizeof(struct in_addr));
767: /*
768: * Then copy rest of options back
769: * to close up the deleted entry.
770: */
771: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
772: sizeof(struct in_addr)),
773: (caddr_t)&cp[IPOPT_OFFSET+1],
774: (unsigned)cnt + sizeof(struct in_addr));
775: break;
776: }
777: }
778: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
779: goto bad;
780: *pcbopt = m;
781: return (0);
782:
783: bad:
784: (void)m_free(m);
785: return (EINVAL);
786: }
787:
788: /*
789: * Set the IP multicast options in response to user setsockopt().
790: */
791: int
792: ip_setmoptions(optname, imop, m)
793: int optname;
794: struct ip_moptions **imop;
795: struct mbuf *m;
796: {
797: register int error = 0;
798: u_char loop;
799: register int i;
800: struct in_addr addr;
801: register struct ip_mreq *mreq;
802: register struct ifnet *ifp;
803: register struct ip_moptions *imo = *imop;
804: struct route ro;
805: register struct sockaddr_in *dst;
806:
807: if (imo == NULL) {
808: /*
809: * No multicast option buffer attached to the pcb;
810: * allocate one and initialize to default values.
811: */
812: imo = (struct ip_moptions*)_MALLOC(sizeof(*imo), M_IPMOPTS,
813: M_WAITOK);
814:
815: if (imo == NULL)
816: return (ENOBUFS);
817: *imop = imo;
818: imo->imo_multicast_ifp = NULL;
819: imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
820: imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
821: imo->imo_num_memberships = 0;
822: }
823:
824: switch (optname) {
825:
826: case IP_MULTICAST_IF:
827: /*
828: * Select the interface for outgoing multicast packets.
829: */
830: if (m == NULL || m->m_len != sizeof(struct in_addr)) {
831: error = EINVAL;
832: break;
833: }
834: addr = *(mtod(m, struct in_addr *));
835: /*
836: * INADDR_ANY is used to remove a previous selection.
837: * When no interface is selected, a default one is
838: * chosen every time a multicast packet is sent.
839: */
840: if (addr.s_addr == INADDR_ANY) {
841: imo->imo_multicast_ifp = NULL;
842: break;
843: }
844: /*
845: * The selected interface is identified by its local
846: * IP address. Find the interface and confirm that
847: * it supports multicasting.
848: */
849: INADDR_TO_IFP(addr, ifp);
850: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
851: error = EADDRNOTAVAIL;
852: break;
853: }
854: imo->imo_multicast_ifp = ifp;
855: break;
856:
857: case IP_MULTICAST_TTL:
858: /*
859: * Set the IP time-to-live for outgoing multicast packets.
860: */
861: if (m == NULL || m->m_len != 1) {
862: error = EINVAL;
863: break;
864: }
865: imo->imo_multicast_ttl = *(mtod(m, u_char *));
866: break;
867:
868: case IP_MULTICAST_LOOP:
869: /*
870: * Set the loopback flag for outgoing multicast packets.
871: * Must be zero or one.
872: */
873: if (m == NULL || m->m_len != 1 ||
874: (loop = *(mtod(m, u_char *))) > 1) {
875: error = EINVAL;
876: break;
877: }
878: imo->imo_multicast_loop = loop;
879: break;
880:
881: case IP_ADD_MEMBERSHIP:
882: /*
883: * Add a multicast group membership.
884: * Group must be a valid IP multicast address.
885: */
886: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
887: error = EINVAL;
888: break;
889: }
890: mreq = mtod(m, struct ip_mreq *);
891: if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
892: error = EINVAL;
893: break;
894: }
895: /*
896: * If no interface address was provided, use the interface of
897: * the route to the given multicast address.
898: */
899: if (mreq->imr_interface.s_addr == INADDR_ANY) {
900: ro.ro_rt = NULL;
901: dst = (struct sockaddr_in *)&ro.ro_dst;
902: dst->sin_len = sizeof(*dst);
903: dst->sin_family = AF_INET;
904: dst->sin_addr = mreq->imr_multiaddr;
905: rtalloc(&ro);
906: if (ro.ro_rt == NULL) {
907: error = EADDRNOTAVAIL;
908: break;
909: }
910: ifp = ro.ro_rt->rt_ifp;
911: rtfree(ro.ro_rt);
912: }
913: else {
914: INADDR_TO_IFP(mreq->imr_interface, ifp);
915: }
916: /*
917: * See if we found an interface, and confirm that it
918: * supports multicast.
919: */
920: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
921: error = EADDRNOTAVAIL;
922: break;
923: }
924: /*
925: * See if the membership already exists or if all the
926: * membership slots are full.
927: */
928: for (i = 0; i < imo->imo_num_memberships; ++i) {
929: if (imo->imo_membership[i]->inm_ifp == ifp &&
930: imo->imo_membership[i]->inm_addr.s_addr
931: == mreq->imr_multiaddr.s_addr)
932: break;
933: }
934: if (i < imo->imo_num_memberships) {
935: error = EADDRINUSE;
936: break;
937: }
938: if (i == IP_MAX_MEMBERSHIPS) {
939: error = ETOOMANYREFS;
940: break;
941: }
942: /*
943: * Everything looks good; add a new record to the multicast
944: * address list for the given interface.
945: */
946: if ((imo->imo_membership[i] =
947: in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
948: error = ENOBUFS;
949: break;
950: }
951: ++imo->imo_num_memberships;
952: break;
953:
954: case IP_DROP_MEMBERSHIP:
955: /*
956: * Drop a multicast group membership.
957: * Group must be a valid IP multicast address.
958: */
959: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
960: error = EINVAL;
961: break;
962: }
963: mreq = mtod(m, struct ip_mreq *);
964: if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
965: error = EINVAL;
966: break;
967: }
968: /*
969: * If an interface address was specified, get a pointer
970: * to its ifnet structure.
971: */
972: if (mreq->imr_interface.s_addr == INADDR_ANY)
973: ifp = NULL;
974: else {
975: INADDR_TO_IFP(mreq->imr_interface, ifp);
976: if (ifp == NULL) {
977: error = EADDRNOTAVAIL;
978: break;
979: }
980: }
981: /*
982: * Find the membership in the membership array.
983: */
984: for (i = 0; i < imo->imo_num_memberships; ++i) {
985: if ((ifp == NULL ||
986: imo->imo_membership[i]->inm_ifp == ifp) &&
987: imo->imo_membership[i]->inm_addr.s_addr ==
988: mreq->imr_multiaddr.s_addr)
989: break;
990: }
991: if (i == imo->imo_num_memberships) {
992: error = EADDRNOTAVAIL;
993: break;
994: }
995: /*
996: * Give up the multicast address record to which the
997: * membership points.
998: */
999: in_delmulti(imo->imo_membership[i]);
1000: /*
1001: * Remove the gap in the membership array.
1002: */
1003: for (++i; i < imo->imo_num_memberships; ++i)
1004: imo->imo_membership[i-1] = imo->imo_membership[i];
1005: --imo->imo_num_memberships;
1006: break;
1007:
1008: default:
1009: error = EOPNOTSUPP;
1010: break;
1011: }
1012:
1013: /*
1014: * If all options have default values, no need to keep the mbuf.
1015: */
1016: if (imo->imo_multicast_ifp == NULL &&
1017: imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1018: imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1019: imo->imo_num_memberships == 0) {
1020: _FREE(*imop, M_IPMOPTS);
1021: *imop = NULL;
1022: }
1023:
1024: return (error);
1025: }
1026:
1027: /*
1028: * Return the IP multicast options in response to user getsockopt().
1029: */
1030: int
1031: ip_getmoptions(optname, imo, mp)
1032: int optname;
1033: register struct ip_moptions *imo;
1034: register struct mbuf **mp;
1035: {
1036: u_char *ttl;
1037: u_char *loop;
1038: struct in_addr *addr;
1039: struct in_ifaddr *ia;
1040:
1041: *mp = m_get(M_WAIT, MT_SOOPTS);
1042:
1043: switch (optname) {
1044:
1045: case IP_MULTICAST_IF:
1046: addr = mtod(*mp, struct in_addr *);
1047: (*mp)->m_len = sizeof(struct in_addr);
1048: if (imo == NULL || imo->imo_multicast_ifp == NULL)
1049: addr->s_addr = INADDR_ANY;
1050: else {
1051: IFP_TO_IA(imo->imo_multicast_ifp, ia);
1052: addr->s_addr = (ia == NULL) ? INADDR_ANY
1053: : IA_SIN(ia)->sin_addr.s_addr;
1054: }
1055: return (0);
1056:
1057: case IP_MULTICAST_TTL:
1058: ttl = mtod(*mp, u_char *);
1059: (*mp)->m_len = 1;
1060: *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
1061: : imo->imo_multicast_ttl;
1062: return (0);
1063:
1064: case IP_MULTICAST_LOOP:
1065: loop = mtod(*mp, u_char *);
1066: (*mp)->m_len = 1;
1067: *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
1068: : imo->imo_multicast_loop;
1069: return (0);
1070:
1071: default:
1072: return (EOPNOTSUPP);
1073: }
1074: }
1075:
1076: /*
1077: * Discard the IP multicast options.
1078: */
1079: void
1080: ip_freemoptions(imo)
1081: register struct ip_moptions *imo;
1082: {
1083: register int i;
1084:
1085: if (imo != NULL) {
1086: for (i = 0; i < imo->imo_num_memberships; ++i)
1087: in_delmulti(imo->imo_membership[i]);
1088: _FREE(imo, M_IPMOPTS);
1089: }
1090: }
1091:
1092: /*
1093: * Routine called from ip_output() to loop back a copy of an IP multicast
1094: * packet to the input queue of a specified interface. Note that this
1095: * calls the output routine of the loopback "driver", but with an interface
1096: * pointer that might NOT be &loif -- easier than replicating that code here.
1097: */
1098: static void
1099: ip_mloopback(ifp, m, dst)
1100: struct ifnet *ifp;
1101: register struct mbuf *m;
1102: register struct sockaddr_in *dst;
1103: {
1104: register struct ip *ip;
1105: struct mbuf *copym;
1106:
1107: copym = m_copy(m, 0, M_COPYALL);
1108: if (copym != NULL) {
1109: /*
1110: * We don't bother to fragment if the IP length is greater
1111: * than the interface's MTU. Can this possibly matter?
1112: */
1113: ip = mtod(copym, struct ip *);
1114: ip->ip_len = htons((u_short)ip->ip_len);
1115: ip->ip_off = htons((u_short)ip->ip_off);
1116: ip->ip_sum = 0;
1117: ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
1118: (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL);
1119: }
1120: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.