ip_output.c revision 36995
1144194Snjl/* 2144194Snjl * Copyright (c) 1982, 1986, 1988, 1990, 1993 3144194Snjl * The Regents of the University of California. All rights reserved. 4144194Snjl * 5144194Snjl * Redistribution and use in source and binary forms, with or without 6144194Snjl * modification, are permitted provided that the following conditions 7144194Snjl * are met: 8144194Snjl * 1. Redistributions of source code must retain the above copyright 9144194Snjl * notice, this list of conditions and the following disclaimer. 10144194Snjl * 2. Redistributions in binary form must reproduce the above copyright 11144194Snjl * notice, this list of conditions and the following disclaimer in the 12144194Snjl * documentation and/or other materials provided with the distribution. 13144194Snjl * 3. All advertising materials mentioning features or use of this software 14144194Snjl * must display the following acknowledgement: 15144194Snjl * This product includes software developed by the University of 16144194Snjl * California, Berkeley and its contributors. 17144194Snjl * 4. Neither the name of the University nor the names of its contributors 18144194Snjl * may be used to endorse or promote products derived from this software 19144194Snjl * without specific prior written permission. 20144194Snjl * 21144194Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22144194Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23144194Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24144194Snjl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25144194Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26144194Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27144194Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28144194Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29144194Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30144194Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31144194Snjl * SUCH DAMAGE. 32144194Snjl * 33144194Snjl * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 34144194Snjl * $Id: ip_output.c,v 1.73 1998/06/14 20:58:17 julian Exp $ 35144194Snjl */ 36144194Snjl 37144194Snjl#define _IP_VHL 38144194Snjl 39144194Snjl#include "opt_ipfw.h" 40144194Snjl#include "opt_ipdivert.h" 41144194Snjl#include "opt_ipfilter.h" 42144194Snjl 43144194Snjl#include <sys/param.h> 44144194Snjl#include <sys/systm.h> 45144194Snjl#include <sys/malloc.h> 46144194Snjl#include <sys/mbuf.h> 47144194Snjl#include <sys/protosw.h> 48144194Snjl#include <sys/socket.h> 49144194Snjl#include <sys/socketvar.h> 50144194Snjl 51144194Snjl#include <net/if.h> 52144194Snjl#include <net/route.h> 53144194Snjl 54144194Snjl#include <netinet/in.h> 55144194Snjl#include <netinet/in_systm.h> 56144194Snjl#include <netinet/ip.h> 57144194Snjl#include <netinet/in_pcb.h> 58166197Sbruno#include <netinet/in_var.h> 59166197Sbruno#include <netinet/ip_var.h> 60166197Sbruno 61166197Sbruno#ifdef vax 62166197Sbruno#include <machine/mtpr.h> 63166197Sbruno#endif 64166197Sbruno#include <machine/in_cksum.h> 65166197Sbruno 66166197Sbrunostatic MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); 67144194Snjl 68144194Snjl#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 69144194Snjl#undef COMPAT_IPFW 70144194Snjl#define COMPAT_IPFW 1 71144194Snjl#else 72144194Snjl#undef COMPAT_IPFW 73144194Snjl#endif 74144194Snjl 75144194Snjlu_short ip_id; 76144194Snjl 77144194Snjlstatic struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); 78144194Snjlstatic void ip_mloopback 79144194Snjl __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); 80144194Snjlstatic int ip_getmoptions 81144194Snjl __P((int, struct ip_moptions *, struct mbuf **)); 82144194Snjlstatic int ip_pcbopts __P((struct mbuf **, struct mbuf *)); 83144194Snjlstatic int ip_setmoptions 84144194Snjl __P((int, struct ip_moptions **, struct mbuf *)); 85144194Snjl 86144194Snjl#if defined(IPFILTER_LKM) || defined(IPFILTER) 87144194Snjlint ip_optcopy __P((struct ip *, struct ip *)); 88144194Snjlextern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); 89144194Snjl#else 90144194Snjlstatic int ip_optcopy __P((struct ip *, struct ip *)); 91144194Snjl#endif 92144194Snjl 93144194Snjl 94144194Snjlextern struct protosw inetsw[]; 95144194Snjl 96144194Snjl/* 97144194Snjl * IP output. The packet in mbuf chain m contains a skeletal IP 98144194Snjl * header (with len, off, ttl, proto, tos, src, dst). 99144194Snjl * The mbuf chain containing the packet will be freed. 100144194Snjl * The mbuf opt, if present, will not be freed. 101144194Snjl */ 102144194Snjlint 103144194Snjlip_output(m0, opt, ro, flags, imo) 104144194Snjl struct mbuf *m0; 105144194Snjl struct mbuf *opt; 106144194Snjl struct route *ro; 107144194Snjl int flags; 108144194Snjl struct ip_moptions *imo; 109144194Snjl{ 110144194Snjl struct ip *ip, *mhip; 111144194Snjl struct ifnet *ifp; 112144194Snjl struct mbuf *m = m0; 113144194Snjl int hlen = sizeof (struct ip); 114144194Snjl int len, off, error = 0; 115144194Snjl struct sockaddr_in *dst; 116144194Snjl struct in_ifaddr *ia; 117144194Snjl int isbroadcast; 118144194Snjl 119144194Snjl#ifdef DIAGNOSTIC 120144194Snjl if ((m->m_flags & M_PKTHDR) == 0) 121144194Snjl panic("ip_output no HDR"); 122144194Snjl if (!ro) 123144194Snjl panic("ip_output no route, proto = %d", 124144194Snjl mtod(m, struct ip *)->ip_p); 125144194Snjl#endif 126144194Snjl if (opt) { 127144194Snjl m = ip_insertoptions(m, opt, &len); 128144194Snjl hlen = len; 129144194Snjl } 130144194Snjl ip = mtod(m, struct ip *); 131144194Snjl /* 132144194Snjl * Fill in IP header. 133144194Snjl */ 134144194Snjl if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { 135144194Snjl ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2); 136144194Snjl ip->ip_off &= IP_DF; 137144194Snjl ip->ip_id = htons(ip_id++); 138144194Snjl ipstat.ips_localout++; 139144194Snjl } else { 140144194Snjl hlen = IP_VHL_HL(ip->ip_vhl) << 2; 141144194Snjl } 142144194Snjl 143144194Snjl dst = (struct sockaddr_in *)&ro->ro_dst; 144144194Snjl /* 145144194Snjl * If there is a cached route, 146144194Snjl * check that it is to the same destination 147144194Snjl * and is still up. If not, free it and try again. 148144194Snjl */ 149144194Snjl if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 150144194Snjl dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 151144194Snjl RTFREE(ro->ro_rt); 152144194Snjl ro->ro_rt = (struct rtentry *)0; 153144194Snjl } 154144194Snjl if (ro->ro_rt == 0) { 155144194Snjl dst->sin_family = AF_INET; 156144194Snjl dst->sin_len = sizeof(*dst); 157144194Snjl dst->sin_addr = ip->ip_dst; 158144194Snjl } 159144194Snjl /* 160144194Snjl * If routing to interface only, 161144194Snjl * short circuit routing lookup. 162144194Snjl */ 163144194Snjl#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) 164144194Snjl#define sintosa(sin) ((struct sockaddr *)(sin)) 165144194Snjl if (flags & IP_ROUTETOIF) { 166144194Snjl if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 && 167144194Snjl (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) { 168144194Snjl ipstat.ips_noroute++; 169144194Snjl error = ENETUNREACH; 170144194Snjl goto bad; 171166197Sbruno } 172166197Sbruno ifp = ia->ia_ifp; 173166197Sbruno ip->ip_ttl = 1; 174166197Sbruno isbroadcast = in_broadcast(dst->sin_addr, ifp); 175166197Sbruno } else { 176166197Sbruno /* 177166197Sbruno * If this is the case, we probably don't want to allocate 178166197Sbruno * a protocol-cloned route since we didn't get one from the 179166197Sbruno * ULP. This lets TCP do its thing, while not burdening 180144194Snjl * forwarding or ICMP with the overhead of cloning a route. 181144194Snjl * Of course, we still want to do any cloning requested by 182144194Snjl * the link layer, as this is probably required in all cases 183144194Snjl * for correct operation (as it is for ARP). 184144194Snjl */ 185144194Snjl if (ro->ro_rt == 0) 186144194Snjl rtalloc_ign(ro, RTF_PRCLONING); 187144194Snjl if (ro->ro_rt == 0) { 188144194Snjl ipstat.ips_noroute++; 189144194Snjl error = EHOSTUNREACH; 190144194Snjl goto bad; 191144194Snjl } 192144194Snjl ia = ifatoia(ro->ro_rt->rt_ifa); 193144194Snjl ifp = ro->ro_rt->rt_ifp; 194144194Snjl ro->ro_rt->rt_use++; 195144194Snjl if (ro->ro_rt->rt_flags & RTF_GATEWAY) 196144194Snjl dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 197144194Snjl if (ro->ro_rt->rt_flags & RTF_HOST) 198144194Snjl isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST); 199144194Snjl else 200144194Snjl isbroadcast = in_broadcast(dst->sin_addr, ifp); 201144194Snjl } 202144194Snjl if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 203144194Snjl struct in_multi *inm; 204144194Snjl 205144194Snjl m->m_flags |= M_MCAST; 206144194Snjl /* 207144194Snjl * IP destination address is multicast. Make sure "dst" 208144194Snjl * still points to the address in "ro". (It may have been 209144194Snjl * changed to point to a gateway address, above.) 210144194Snjl */ 211144194Snjl dst = (struct sockaddr_in *)&ro->ro_dst; 212144194Snjl /* 213144194Snjl * See if the caller provided any multicast options 214144194Snjl */ 215144194Snjl if (imo != NULL) { 216144194Snjl ip->ip_ttl = imo->imo_multicast_ttl; 217144194Snjl if (imo->imo_multicast_ifp != NULL) 218144194Snjl ifp = imo->imo_multicast_ifp; 219144194Snjl if (imo->imo_multicast_vif != -1) 220144194Snjl ip->ip_src.s_addr = 221144194Snjl ip_mcast_src(imo->imo_multicast_vif); 222144194Snjl } else 223144194Snjl ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; 224144194Snjl /* 225144194Snjl * Confirm that the outgoing interface supports multicast. 226144194Snjl */ 227144194Snjl if ((imo == NULL) || (imo->imo_multicast_vif == -1)) { 228144194Snjl if ((ifp->if_flags & IFF_MULTICAST) == 0) { 229144194Snjl ipstat.ips_noroute++; 230166197Sbruno error = ENETUNREACH; 231144194Snjl goto bad; 232144194Snjl } 233144194Snjl } 234144194Snjl /* 235144194Snjl * If source address not specified yet, use address 236144194Snjl * of outgoing interface. 237144194Snjl */ 238144194Snjl if (ip->ip_src.s_addr == INADDR_ANY) { 239144194Snjl register struct in_ifaddr *ia1; 240144194Snjl 241144194Snjl for (ia1 = in_ifaddrhead.tqh_first; ia1; 242144194Snjl ia1 = ia1->ia_link.tqe_next) 243144194Snjl if (ia1->ia_ifp == ifp) { 244144194Snjl ip->ip_src = IA_SIN(ia1)->sin_addr; 245144194Snjl break; 246144194Snjl } 247144194Snjl } 248144194Snjl 249144194Snjl IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); 250144194Snjl if (inm != NULL && 251144194Snjl (imo == NULL || imo->imo_multicast_loop)) { 252144194Snjl /* 253144194Snjl * If we belong to the destination multicast group 254144194Snjl * on the outgoing interface, and the caller did not 255144194Snjl * forbid loopback, loop back a copy. 256144194Snjl */ 257144194Snjl ip_mloopback(ifp, m, dst, hlen); 258144194Snjl } 259144194Snjl else { 260144194Snjl /* 261144194Snjl * If we are acting as a multicast router, perform 262144194Snjl * multicast forwarding as if the packet had just 263144194Snjl * arrived on the interface to which we are about 264144194Snjl * to send. The multicast forwarding function 265144194Snjl * recursively calls this function, using the 266144194Snjl * IP_FORWARDING flag to prevent infinite recursion. 267144194Snjl * 268144194Snjl * Multicasts that are looped back by ip_mloopback(), 269144194Snjl * above, will be forwarded by the ip_input() routine, 270144194Snjl * if necessary. 271144194Snjl */ 272144194Snjl if (ip_mrouter && (flags & IP_FORWARDING) == 0) { 273144194Snjl /* 274144194Snjl * Check if rsvp daemon is running. If not, don't 275144194Snjl * set ip_moptions. This ensures that the packet 276144194Snjl * is multicast and not just sent down one link 277144194Snjl * as prescribed by rsvpd. 278144194Snjl */ 279144194Snjl if (!rsvp_on) 280144194Snjl imo = NULL; 281144194Snjl if (ip_mforward(ip, ifp, m, imo) != 0) { 282144194Snjl m_freem(m); 283144194Snjl goto done; 284144194Snjl } 285144194Snjl } 286144194Snjl } 287144194Snjl 288144194Snjl /* 289144194Snjl * Multicasts with a time-to-live of zero may be looped- 290144194Snjl * back, above, but must not be transmitted on a network. 291144194Snjl * Also, multicasts addressed to the loopback interface 292144194Snjl * are not sent -- the above call to ip_mloopback() will 293144194Snjl * loop back a copy if this host actually belongs to the 294144194Snjl * destination group on the loopback interface. 295144194Snjl */ 296166197Sbruno if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) { 297144194Snjl m_freem(m); 298144194Snjl goto done; 299144194Snjl } 300144194Snjl 301144194Snjl goto sendit; 302144194Snjl } 303144194Snjl#ifndef notdef 304144194Snjl /* 305144194Snjl * If source address not specified yet, use address 306144194Snjl * of outgoing interface. 307144194Snjl */ 308144194Snjl if (ip->ip_src.s_addr == INADDR_ANY) 309166197Sbruno ip->ip_src = IA_SIN(ia)->sin_addr; 310144194Snjl#endif 311144194Snjl /* 312144194Snjl * Verify that we have any chance at all of being able to queue 313144194Snjl * the packet or packet fragments 314144194Snjl */ 315144194Snjl if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >= 316166197Sbruno ifp->if_snd.ifq_maxlen) { 317166197Sbruno error = ENOBUFS; 318166197Sbruno goto bad; 319166197Sbruno } 320166197Sbruno 321166197Sbruno /* 322166197Sbruno * Look for broadcast address and 323166197Sbruno * and verify user is allowed to send 324166197Sbruno * such a packet. 325166197Sbruno */ 326166197Sbruno if (isbroadcast) { 327166197Sbruno if ((ifp->if_flags & IFF_BROADCAST) == 0) { 328166197Sbruno error = EADDRNOTAVAIL; 329166197Sbruno goto bad; 330166197Sbruno } 331166197Sbruno if ((flags & IP_ALLOWBROADCAST) == 0) { 332166197Sbruno error = EACCES; 333166197Sbruno goto bad; 334166197Sbruno } 335166197Sbruno /* don't allow broadcast messages to be fragmented */ 336166197Sbruno if ((u_short)ip->ip_len > ifp->if_mtu) { 337166197Sbruno error = EMSGSIZE; 338166197Sbruno goto bad; 339166197Sbruno } 340144194Snjl m->m_flags |= M_BCAST; 341144194Snjl } else { 342144194Snjl m->m_flags &= ~M_BCAST; 343144194Snjl } 344144194Snjl 345166197Sbrunosendit: 346144194Snjl /* 347144194Snjl * IpHack's section. 348166197Sbruno * - Xlate: translate packet's addr/port (NAT). 349166197Sbruno * - Firewall: deny/allow/etc. 350166197Sbruno * - Wrap: fake packet's addr/port <unimpl.> 351166197Sbruno * - Encapsulate: put it in another IP and send out. <unimp.> 352144194Snjl */ 353144194Snjl#if defined(IPFILTER) || defined(IPFILTER_LKM) 354144194Snjl if (fr_checkp) { 355144194Snjl struct mbuf *m1 = m; 356144194Snjl 357144194Snjl if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1) 358144194Snjl goto done; 359144194Snjl ip = mtod(m = m1, struct ip *); 360144194Snjl } 361144194Snjl#endif 362144194Snjl 363144194Snjl#ifdef COMPAT_IPFW 364166197Sbruno if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) { 365166197Sbruno error = EACCES; 366166197Sbruno goto done; 367166197Sbruno } 368166197Sbruno 369144194Snjl /* 370144194Snjl * Check with the firewall... 371144194Snjl */ 372144194Snjl if (ip_fw_chk_ptr) { 373144194Snjl#ifdef IPDIVERT 374144194Snjl ip_divert_port = (*ip_fw_chk_ptr)(&ip, 375144194Snjl hlen, ifp, &ip_divert_cookie, &m); 376144194Snjl if (ip_divert_port) { /* Divert packet */ 377144194Snjl (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); 378166197Sbruno goto done; 379166197Sbruno } 380166197Sbruno#else 381166197Sbruno u_int16_t dummy = 0; 382166197Sbruno /* If ipfw says divert, we have to just drop packet */ 383144194Snjl if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m)) { 384144194Snjl m_freem(m); 385144194Snjl goto done; 386144194Snjl } 387144194Snjl#endif 388144194Snjl if (!m) { 389166197Sbruno error = EACCES; 390144194Snjl goto done; 391144194Snjl } 392144194Snjl } 393144194Snjl#endif /* COMPAT_IPFW */ 394144194Snjl 395166197Sbruno /* 396144194Snjl * If small enough for interface, can just send directly. 397166197Sbruno */ 398166197Sbruno if ((u_short)ip->ip_len <= ifp->if_mtu) { 399144194Snjl ip->ip_len = htons((u_short)ip->ip_len); 400166197Sbruno ip->ip_off = htons((u_short)ip->ip_off); 401144194Snjl ip->ip_sum = 0; 402166197Sbruno if (ip->ip_vhl == IP_VHL_BORING) { 403166197Sbruno ip->ip_sum = in_cksum_hdr(ip); 404166197Sbruno } else { 405166197Sbruno ip->ip_sum = in_cksum(m, hlen); 406166197Sbruno } 407166197Sbruno error = (*ifp->if_output)(ifp, m, 408166197Sbruno (struct sockaddr *)dst, ro->ro_rt); 409166197Sbruno goto done; 410144194Snjl } 411144194Snjl /* 412144194Snjl * Too large for interface; fragment if possible. 413144194Snjl * Must be able to put at least 8 bytes per fragment. 414144194Snjl */ 415144194Snjl if (ip->ip_off & IP_DF) { 416166197Sbruno error = EMSGSIZE; 417166197Sbruno /* 418166197Sbruno * This case can happen if the user changed the MTU 419166197Sbruno * of an interface after enabling IP on it. Because 420166197Sbruno * most netifs don't keep track of routes pointing to 421166197Sbruno * them, there is no way for one to update all its 422166197Sbruno * routes when the MTU is changed. 423144194Snjl */ 424144194Snjl if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST)) 425144194Snjl && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) 426144194Snjl && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) { 427144194Snjl ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu; 428144194Snjl } 429166197Sbruno ipstat.ips_cantfrag++; 430144194Snjl goto bad; 431144194Snjl } 432144194Snjl len = (ifp->if_mtu - hlen) &~ 7; 433144194Snjl if (len < 8) { 434144194Snjl error = EMSGSIZE; 435144194Snjl goto bad; 436166197Sbruno } 437144194Snjl 438166197Sbruno { 439144194Snjl int mhlen, firstlen = len; 440144194Snjl struct mbuf **mnext = &m->m_nextpkt; 441144194Snjl 442144194Snjl /* 443144194Snjl * Loop through length of segment after first fragment, 444144194Snjl * make new header and copy data of each part and link onto chain. 445144194Snjl */ 446144194Snjl m0 = m; 447144194Snjl mhlen = sizeof (struct ip); 448144194Snjl for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 449144194Snjl MGETHDR(m, M_DONTWAIT, MT_HEADER); 450144194Snjl if (m == 0) { 451144194Snjl error = ENOBUFS; 452144194Snjl ipstat.ips_odropped++; 453166197Sbruno goto sendorfree; 454166197Sbruno } 455166197Sbruno m->m_data += max_linkhdr; 456144194Snjl mhip = mtod(m, struct ip *); 457144194Snjl *mhip = *ip; 458144194Snjl if (hlen > sizeof (struct ip)) { 459144194Snjl mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 460144194Snjl mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2); 461144194Snjl } 462144194Snjl m->m_len = mhlen; 463144194Snjl mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 464144194Snjl if (ip->ip_off & IP_MF) 465144194Snjl mhip->ip_off |= IP_MF; 466144194Snjl if (off + len >= (u_short)ip->ip_len) 467144194Snjl len = (u_short)ip->ip_len - off; 468144194Snjl else 469144194Snjl mhip->ip_off |= IP_MF; 470144194Snjl mhip->ip_len = htons((u_short)(len + mhlen)); 471144194Snjl m->m_next = m_copy(m0, off, len); 472144194Snjl if (m->m_next == 0) { 473144194Snjl (void) m_free(m); 474144194Snjl error = ENOBUFS; /* ??? */ 475144194Snjl ipstat.ips_odropped++; 476144194Snjl goto sendorfree; 477144194Snjl } 478144194Snjl m->m_pkthdr.len = mhlen + len; 479144194Snjl m->m_pkthdr.rcvif = (struct ifnet *)0; 480144194Snjl mhip->ip_off = htons((u_short)mhip->ip_off); 481144194Snjl mhip->ip_sum = 0; 482144194Snjl if (mhip->ip_vhl == IP_VHL_BORING) { 483144194Snjl mhip->ip_sum = in_cksum_hdr(mhip); 484144194Snjl } else { 485144194Snjl mhip->ip_sum = in_cksum(m, mhlen); 486144194Snjl } 487144194Snjl *mnext = m; 488166197Sbruno mnext = &m->m_nextpkt; 489166197Sbruno ipstat.ips_ofragments++; 490144194Snjl } 491144194Snjl /* 492144194Snjl * Update first fragment by trimming what's been copied out 493144194Snjl * and updating header, then send each fragment (in order). 494144194Snjl */ 495144194Snjl m = m0; 496144194Snjl m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 497144194Snjl m->m_pkthdr.len = hlen + firstlen; 498144194Snjl ip->ip_len = htons((u_short)m->m_pkthdr.len); 499144194Snjl ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 500144194Snjl ip->ip_sum = 0; 501144194Snjl if (ip->ip_vhl == IP_VHL_BORING) { 502144194Snjl ip->ip_sum = in_cksum_hdr(ip); 503144194Snjl } else { 504144194Snjl ip->ip_sum = in_cksum(m, hlen); 505144194Snjl } 506144194Snjlsendorfree: 507144194Snjl for (m = m0; m; m = m0) { 508144194Snjl m0 = m->m_nextpkt; 509144194Snjl m->m_nextpkt = 0; 510144194Snjl if (error == 0) 511144194Snjl error = (*ifp->if_output)(ifp, m, 512144194Snjl (struct sockaddr *)dst, ro->ro_rt); 513144194Snjl else 514144194Snjl m_freem(m); 515144194Snjl } 516144194Snjl 517144194Snjl if (error == 0) 518144194Snjl ipstat.ips_fragmented++; 519144194Snjl } 520144194Snjldone: 521144194Snjl return (error); 522144194Snjlbad: 523144194Snjl m_freem(m0); 524144194Snjl goto done; 525144194Snjl} 526144194Snjl 527144194Snjl/* 528144194Snjl * Insert IP options into preformed packet. 529144194Snjl * Adjust IP destination as required for IP source routing, 530144194Snjl * as indicated by a non-zero in_addr at the start of the options. 531144194Snjl * 532144194Snjl * XXX This routine assumes that the packet has no options in place. 533144194Snjl */ 534144194Snjlstatic struct mbuf * 535144194Snjlip_insertoptions(m, opt, phlen) 536144194Snjl register struct mbuf *m; 537144194Snjl struct mbuf *opt; 538144194Snjl int *phlen; 539144194Snjl{ 540144194Snjl register struct ipoption *p = mtod(opt, struct ipoption *); 541144194Snjl struct mbuf *n; 542144194Snjl register struct ip *ip = mtod(m, struct ip *); 543144194Snjl unsigned optlen; 544144194Snjl 545144194Snjl optlen = opt->m_len - sizeof(p->ipopt_dst); 546144194Snjl if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 547144194Snjl return (m); /* XXX should fail */ 548144194Snjl if (p->ipopt_dst.s_addr) 549144194Snjl ip->ip_dst = p->ipopt_dst; 550144194Snjl if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 551144194Snjl MGETHDR(n, M_DONTWAIT, MT_HEADER); 552144194Snjl if (n == 0) 553144194Snjl return (m); 554144194Snjl n->m_pkthdr.len = m->m_pkthdr.len + optlen; 555144194Snjl m->m_len -= sizeof(struct ip); 556144194Snjl m->m_data += sizeof(struct ip); 557144194Snjl n->m_next = m; 558144194Snjl m = n; 559144194Snjl m->m_len = optlen + sizeof(struct ip); 560144194Snjl m->m_data += max_linkhdr; 561144194Snjl (void)memcpy(mtod(m, void *), ip, sizeof(struct ip)); 562144194Snjl } else { 563144194Snjl m->m_data -= optlen; 564144194Snjl m->m_len += optlen; 565144194Snjl m->m_pkthdr.len += optlen; 566144194Snjl ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 567144194Snjl } 568144194Snjl ip = mtod(m, struct ip *); 569144194Snjl bcopy(p->ipopt_list, ip + 1, optlen); 570144194Snjl *phlen = sizeof(struct ip) + optlen; 571144194Snjl ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2); 572144194Snjl ip->ip_len += optlen; 573144194Snjl return (m); 574144194Snjl} 575144194Snjl 576144194Snjl/* 577166197Sbruno * Copy options from ip to jp, 578144194Snjl * omitting those not copied during fragmentation. 579144194Snjl */ 580144194Snjl#if !defined(IPFILTER) && !defined(IPFILTER_LKM) 581144194Snjlstatic 582166197Sbruno#endif 583144194Snjlint 584144194Snjlip_optcopy(ip, jp) 585144194Snjl struct ip *ip, *jp; 586144194Snjl{ 587144194Snjl register u_char *cp, *dp; 588144194Snjl int opt, optlen, cnt; 589144194Snjl 590144194Snjl cp = (u_char *)(ip + 1); 591144194Snjl dp = (u_char *)(jp + 1); 592144194Snjl cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 593144194Snjl for (; cnt > 0; cnt -= optlen, cp += optlen) { 594144194Snjl opt = cp[0]; 595144194Snjl if (opt == IPOPT_EOL) 596144194Snjl break; 597144194Snjl if (opt == IPOPT_NOP) { 598144194Snjl /* Preserve for IP mcast tunnel's LSRR alignment. */ 599166197Sbruno *dp++ = IPOPT_NOP; 600144194Snjl optlen = 1; 601144194Snjl continue; 602144194Snjl } else 603144194Snjl optlen = cp[IPOPT_OLEN]; 604144194Snjl /* bogus lengths should have been caught by ip_dooptions */ 605144194Snjl if (optlen > cnt) 606144194Snjl optlen = cnt; 607144194Snjl if (IPOPT_COPIED(opt)) { 608144194Snjl bcopy(cp, dp, optlen); 609144194Snjl dp += optlen; 610144194Snjl } 611144194Snjl } 612144194Snjl for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 613144194Snjl *dp++ = IPOPT_EOL; 614144194Snjl return (optlen); 615144194Snjl} 616144194Snjl 617144194Snjl/* 618144194Snjl * IP socket option processing. 619144194Snjl */ 620144194Snjlint 621144194Snjlip_ctloutput(op, so, level, optname, mp, p) 622144194Snjl int op; 623144194Snjl struct socket *so; 624144194Snjl int level, optname; 625144194Snjl struct mbuf **mp; 626144194Snjl struct proc *p; 627144194Snjl{ 628144194Snjl register struct inpcb *inp = sotoinpcb(so); 629144194Snjl register struct mbuf *m = *mp; 630144194Snjl register int optval = 0; 631144194Snjl int error = 0; 632144194Snjl 633144194Snjl if (level != IPPROTO_IP) { 634144194Snjl error = EINVAL; 635144194Snjl if (op == PRCO_SETOPT && *mp) 636144194Snjl (void) m_free(*mp); 637144194Snjl } else switch (op) { 638144194Snjl 639144194Snjl case PRCO_SETOPT: 640144194Snjl switch (optname) { 641144194Snjl case IP_OPTIONS: 642144194Snjl#ifdef notyet 643144194Snjl case IP_RETOPTS: 644144194Snjl return (ip_pcbopts(optname, &inp->inp_options, m)); 645144194Snjl#else 646144194Snjl return (ip_pcbopts(&inp->inp_options, m)); 647144194Snjl#endif 648144194Snjl 649144194Snjl case IP_TOS: 650144194Snjl case IP_TTL: 651144194Snjl case IP_RECVOPTS: 652144194Snjl case IP_RECVRETOPTS: 653144194Snjl case IP_RECVDSTADDR: 654144194Snjl case IP_RECVIF: 655166197Sbruno if (m == 0 || m->m_len != sizeof(int)) 656144194Snjl error = EINVAL; 657144194Snjl else { 658144194Snjl optval = *mtod(m, int *); 659144194Snjl switch (optname) { 660144194Snjl 661144194Snjl case IP_TOS: 662144194Snjl inp->inp_ip_tos = optval; 663144194Snjl break; 664144194Snjl 665144194Snjl case IP_TTL: 666144194Snjl inp->inp_ip_ttl = optval; 667144194Snjl break; 668144194Snjl#define OPTSET(bit) \ 669144194Snjl if (optval) \ 670144194Snjl inp->inp_flags |= bit; \ 671144194Snjl else \ 672144194Snjl inp->inp_flags &= ~bit; 673144194Snjl 674144194Snjl case IP_RECVOPTS: 675144194Snjl OPTSET(INP_RECVOPTS); 676144194Snjl break; 677144194Snjl 678144194Snjl case IP_RECVRETOPTS: 679144194Snjl OPTSET(INP_RECVRETOPTS); 680144194Snjl break; 681144194Snjl 682144194Snjl case IP_RECVDSTADDR: 683144194Snjl OPTSET(INP_RECVDSTADDR); 684144194Snjl break; 685144194Snjl 686144194Snjl case IP_RECVIF: 687144194Snjl OPTSET(INP_RECVIF); 688144194Snjl break; 689144194Snjl } 690144194Snjl } 691144194Snjl break; 692144194Snjl#undef OPTSET 693144194Snjl 694144380Snjl case IP_MULTICAST_IF: 695144380Snjl case IP_MULTICAST_VIF: 696144380Snjl case IP_MULTICAST_TTL: 697144380Snjl case IP_MULTICAST_LOOP: 698144380Snjl case IP_ADD_MEMBERSHIP: 699144380Snjl case IP_DROP_MEMBERSHIP: 700144380Snjl error = ip_setmoptions(optname, &inp->inp_moptions, m); 701144194Snjl break; 702144194Snjl 703144194Snjl case IP_PORTRANGE: 704144194Snjl if (m == 0 || m->m_len != sizeof(int)) 705144194Snjl error = EINVAL; 706144194Snjl else { 707144194Snjl optval = *mtod(m, int *); 708144194Snjl 709144194Snjl switch (optval) { 710144194Snjl 711144194Snjl case IP_PORTRANGE_DEFAULT: 712144194Snjl inp->inp_flags &= ~(INP_LOWPORT); 713144194Snjl inp->inp_flags &= ~(INP_HIGHPORT); 714144194Snjl break; 715144194Snjl 716144194Snjl case IP_PORTRANGE_HIGH: 717144194Snjl inp->inp_flags &= ~(INP_LOWPORT); 718144194Snjl inp->inp_flags |= INP_HIGHPORT; 719144194Snjl break; 720144194Snjl 721144194Snjl case IP_PORTRANGE_LOW: 722144194Snjl inp->inp_flags &= ~(INP_HIGHPORT); 723144194Snjl inp->inp_flags |= INP_LOWPORT; 724144194Snjl break; 725144194Snjl 726144194Snjl default: 727144194Snjl error = EINVAL; 728144194Snjl break; 729144194Snjl } 730144194Snjl } 731144194Snjl break; 732144194Snjl 733144194Snjl default: 734144194Snjl error = ENOPROTOOPT; 735144194Snjl break; 736144194Snjl } 737144194Snjl if (m) 738144194Snjl (void)m_free(m); 739144194Snjl break; 740144194Snjl 741144194Snjl case PRCO_GETOPT: 742144194Snjl switch (optname) { 743144194Snjl case IP_OPTIONS: 744144194Snjl case IP_RETOPTS: 745144194Snjl *mp = m = m_get(M_WAIT, MT_SOOPTS); 746144194Snjl if (inp->inp_options) { 747144194Snjl m->m_len = inp->inp_options->m_len; 748144194Snjl bcopy(mtod(inp->inp_options, void *), 749144194Snjl mtod(m, void *), m->m_len); 750144194Snjl } else 751144194Snjl m->m_len = 0; 752144194Snjl break; 753144194Snjl 754144194Snjl case IP_TOS: 755144194Snjl case IP_TTL: 756144194Snjl case IP_RECVOPTS: 757144194Snjl case IP_RECVRETOPTS: 758144194Snjl case IP_RECVDSTADDR: 759144194Snjl case IP_RECVIF: 760144194Snjl *mp = m = m_get(M_WAIT, MT_SOOPTS); 761144194Snjl m->m_len = sizeof(int); 762144194Snjl switch (optname) { 763144194Snjl 764144194Snjl case IP_TOS: 765144194Snjl optval = inp->inp_ip_tos; 766144194Snjl break; 767144194Snjl 768144194Snjl case IP_TTL: 769144194Snjl optval = inp->inp_ip_ttl; 770144194Snjl break; 771144194Snjl 772144194Snjl#define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 773144194Snjl 774144194Snjl case IP_RECVOPTS: 775144194Snjl optval = OPTBIT(INP_RECVOPTS); 776144194Snjl break; 777144194Snjl 778144194Snjl case IP_RECVRETOPTS: 779144194Snjl optval = OPTBIT(INP_RECVRETOPTS); 780144194Snjl break; 781144194Snjl 782144194Snjl case IP_RECVDSTADDR: 783144194Snjl optval = OPTBIT(INP_RECVDSTADDR); 784144194Snjl break; 785144194Snjl 786144194Snjl case IP_RECVIF: 787144194Snjl optval = OPTBIT(INP_RECVIF); 788144194Snjl break; 789144194Snjl } 790144194Snjl *mtod(m, int *) = optval; 791166197Sbruno break; 792144194Snjl 793144194Snjl case IP_MULTICAST_IF: 794144194Snjl case IP_MULTICAST_VIF: 795144194Snjl case IP_MULTICAST_TTL: 796144194Snjl case IP_MULTICAST_LOOP: 797144194Snjl case IP_ADD_MEMBERSHIP: 798144194Snjl case IP_DROP_MEMBERSHIP: 799144194Snjl error = ip_getmoptions(optname, inp->inp_moptions, mp); 800144194Snjl break; 801166197Sbruno 802144194Snjl case IP_PORTRANGE: 803144194Snjl *mp = m = m_get(M_WAIT, MT_SOOPTS); 804144194Snjl m->m_len = sizeof(int); 805144194Snjl 806144194Snjl if (inp->inp_flags & INP_HIGHPORT) 807144194Snjl optval = IP_PORTRANGE_HIGH; 808144194Snjl else if (inp->inp_flags & INP_LOWPORT) 809144194Snjl optval = IP_PORTRANGE_LOW; 810221102Sjkim else 811144194Snjl optval = 0; 812144194Snjl 813144194Snjl *mtod(m, int *) = optval; 814144194Snjl break; 815144194Snjl 816144194Snjl default: 817144194Snjl error = ENOPROTOOPT; 818144194Snjl break; 819144194Snjl } 820144194Snjl break; 821144194Snjl } 822144194Snjl return (error); 823144194Snjl} 824144194Snjl 825144194Snjl/* 826144194Snjl * Set up IP options in pcb for insertion in output packets. 827144194Snjl * Store in mbuf with pointer in pcbopt, adding pseudo-option 828144194Snjl * with destination address if source routed. 829144194Snjl */ 830144194Snjlstatic int 831144194Snjl#ifdef notyet 832144194Snjlip_pcbopts(optname, pcbopt, m) 833144194Snjl int optname; 834144194Snjl#else 835144194Snjlip_pcbopts(pcbopt, m) 836144194Snjl#endif 837144194Snjl struct mbuf **pcbopt; 838144194Snjl register struct mbuf *m; 839144194Snjl{ 840144194Snjl register int cnt, optlen; 841144194Snjl register u_char *cp; 842221102Sjkim u_char opt; 843144194Snjl 844144194Snjl /* turn off any old options */ 845144194Snjl if (*pcbopt) 846144194Snjl (void)m_free(*pcbopt); 847144194Snjl *pcbopt = 0; 848144194Snjl if (m == (struct mbuf *)0 || m->m_len == 0) { 849144194Snjl /* 850144194Snjl * Only turning off any previous options. 851144194Snjl */ 852144194Snjl if (m) 853144194Snjl (void)m_free(m); 854144194Snjl return (0); 855144194Snjl } 856144194Snjl 857144194Snjl#ifndef vax 858221102Sjkim if (m->m_len % sizeof(long)) 859144194Snjl goto bad; 860144194Snjl#endif 861144194Snjl /* 862144194Snjl * IP first-hop destination address will be stored before 863144194Snjl * actual options; move other options back 864144194Snjl * and clear it when none present. 865144194Snjl */ 866144194Snjl if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 867144194Snjl goto bad; 868144194Snjl cnt = m->m_len; 869184104Sjkim m->m_len += sizeof(struct in_addr); 870144194Snjl cp = mtod(m, u_char *) + sizeof(struct in_addr); 871144194Snjl ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 872144194Snjl bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 873144194Snjl 874144194Snjl for (; cnt > 0; cnt -= optlen, cp += optlen) { 875144194Snjl opt = cp[IPOPT_OPTVAL]; 876144194Snjl if (opt == IPOPT_EOL) 877144194Snjl break; 878144194Snjl if (opt == IPOPT_NOP) 879144194Snjl optlen = 1; 880185349Sjkim else { 881144194Snjl optlen = cp[IPOPT_OLEN]; 882144194Snjl if (optlen <= IPOPT_OLEN || optlen > cnt) 883144194Snjl goto bad; 884144194Snjl } 885144194Snjl switch (opt) { 886144194Snjl 887144194Snjl default: 888144194Snjl break; 889144194Snjl 890144194Snjl case IPOPT_LSRR: 891144194Snjl case IPOPT_SSRR: 892144194Snjl /* 893144194Snjl * user process specifies route as: 894166197Sbruno * ->A->B->C->D 895144194Snjl * D must be our final destination (but we can't 896144194Snjl * check that since we may not have connected yet). 897144194Snjl * A is first hop destination, which doesn't appear in 898144194Snjl * actual IP option, but is stored before the options. 899144194Snjl */ 900144194Snjl if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 901144194Snjl goto bad; 902144194Snjl m->m_len -= sizeof(struct in_addr); 903144194Snjl cnt -= sizeof(struct in_addr); 904144194Snjl optlen -= sizeof(struct in_addr); 905144194Snjl cp[IPOPT_OLEN] = optlen; 906144194Snjl /* 907144194Snjl * Move first hop before start of options. 908144194Snjl */ 909144194Snjl bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 910144194Snjl sizeof(struct in_addr)); 911144194Snjl /* 912144194Snjl * Then copy rest of options back 913144194Snjl * to close up the deleted entry. 914144194Snjl */ 915144194Snjl ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 916144194Snjl sizeof(struct in_addr)), 917144194Snjl (caddr_t)&cp[IPOPT_OFFSET+1], 918144194Snjl (unsigned)cnt + sizeof(struct in_addr)); 919144194Snjl break; 920144194Snjl } 921144194Snjl } 922144194Snjl if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 923144194Snjl goto bad; 924144194Snjl *pcbopt = m; 925144194Snjl return (0); 926144194Snjl 927144194Snjlbad: 928144194Snjl (void)m_free(m); 929144194Snjl return (EINVAL); 930144194Snjl} 931166197Sbruno 932144194Snjl/* 933144194Snjl * Set the IP multicast options in response to user setsockopt(). 934144194Snjl */ 935144194Snjlstatic int 936144194Snjlip_setmoptions(optname, imop, m) 937144194Snjl int optname; 938144194Snjl struct ip_moptions **imop; 939144194Snjl struct mbuf *m; 940144194Snjl{ 941144194Snjl register int error = 0; 942144194Snjl u_char loop; 943144194Snjl register int i; 944144194Snjl struct in_addr addr; 945144194Snjl register struct ip_mreq *mreq; 946144194Snjl register struct ifnet *ifp; 947144194Snjl register struct ip_moptions *imo = *imop; 948144194Snjl struct route ro; 949144194Snjl register struct sockaddr_in *dst; 950144194Snjl int s; 951144194Snjl 952144194Snjl if (imo == NULL) { 953144194Snjl /* 954144194Snjl * No multicast option buffer attached to the pcb; 955144194Snjl * allocate one and initialize to default values. 956144194Snjl */ 957144194Snjl imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, 958144194Snjl M_WAITOK); 959144194Snjl 960144194Snjl if (imo == NULL) 961144194Snjl return (ENOBUFS); 962144194Snjl *imop = imo; 963144194Snjl imo->imo_multicast_ifp = NULL; 964144194Snjl imo->imo_multicast_vif = -1; 965144194Snjl imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 966144194Snjl imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 967144194Snjl imo->imo_num_memberships = 0; 968144194Snjl } 969182401Sjhb 970144194Snjl switch (optname) { 971 /* store an index number for the vif you wanna use in the send */ 972 case IP_MULTICAST_VIF: 973 if (!legal_vif_num) { 974 error = EOPNOTSUPP; 975 break; 976 } 977 if (m == NULL || m->m_len != sizeof(int)) { 978 error = EINVAL; 979 break; 980 } 981 i = *(mtod(m, int *)); 982 if (!legal_vif_num(i) && (i != -1)) { 983 error = EINVAL; 984 break; 985 } 986 imo->imo_multicast_vif = i; 987 break; 988 989 case IP_MULTICAST_IF: 990 /* 991 * Select the interface for outgoing multicast packets. 992 */ 993 if (m == NULL || m->m_len != sizeof(struct in_addr)) { 994 error = EINVAL; 995 break; 996 } 997 addr = *(mtod(m, struct in_addr *)); 998 /* 999 * INADDR_ANY is used to remove a previous selection. 1000 * When no interface is selected, a default one is 1001 * chosen every time a multicast packet is sent. 1002 */ 1003 if (addr.s_addr == INADDR_ANY) { 1004 imo->imo_multicast_ifp = NULL; 1005 break; 1006 } 1007 /* 1008 * The selected interface is identified by its local 1009 * IP address. Find the interface and confirm that 1010 * it supports multicasting. 1011 */ 1012 s = splimp(); 1013 INADDR_TO_IFP(addr, ifp); 1014 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 1015 splx(s); 1016 error = EADDRNOTAVAIL; 1017 break; 1018 } 1019 imo->imo_multicast_ifp = ifp; 1020 splx(s); 1021 break; 1022 1023 case IP_MULTICAST_TTL: 1024 /* 1025 * Set the IP time-to-live for outgoing multicast packets. 1026 */ 1027 if (m == NULL || m->m_len != 1) { 1028 error = EINVAL; 1029 break; 1030 } 1031 imo->imo_multicast_ttl = *(mtod(m, u_char *)); 1032 break; 1033 1034 case IP_MULTICAST_LOOP: 1035 /* 1036 * Set the loopback flag for outgoing multicast packets. 1037 * Must be zero or one. 1038 */ 1039 if (m == NULL || m->m_len != 1 || 1040 (loop = *(mtod(m, u_char *))) > 1) { 1041 error = EINVAL; 1042 break; 1043 } 1044 imo->imo_multicast_loop = loop; 1045 break; 1046 1047 case IP_ADD_MEMBERSHIP: 1048 /* 1049 * Add a multicast group membership. 1050 * Group must be a valid IP multicast address. 1051 */ 1052 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 1053 error = EINVAL; 1054 break; 1055 } 1056 mreq = mtod(m, struct ip_mreq *); 1057 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 1058 error = EINVAL; 1059 break; 1060 } 1061 s = splimp(); 1062 /* 1063 * If no interface address was provided, use the interface of 1064 * the route to the given multicast address. 1065 */ 1066 if (mreq->imr_interface.s_addr == INADDR_ANY) { 1067 bzero((caddr_t)&ro, sizeof(ro)); 1068 dst = (struct sockaddr_in *)&ro.ro_dst; 1069 dst->sin_len = sizeof(*dst); 1070 dst->sin_family = AF_INET; 1071 dst->sin_addr = mreq->imr_multiaddr; 1072 rtalloc(&ro); 1073 if (ro.ro_rt == NULL) { 1074 error = EADDRNOTAVAIL; 1075 splx(s); 1076 break; 1077 } 1078 ifp = ro.ro_rt->rt_ifp; 1079 rtfree(ro.ro_rt); 1080 } 1081 else { 1082 INADDR_TO_IFP(mreq->imr_interface, ifp); 1083 } 1084 1085 /* 1086 * See if we found an interface, and confirm that it 1087 * supports multicast. 1088 */ 1089 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 1090 error = EADDRNOTAVAIL; 1091 splx(s); 1092 break; 1093 } 1094 /* 1095 * See if the membership already exists or if all the 1096 * membership slots are full. 1097 */ 1098 for (i = 0; i < imo->imo_num_memberships; ++i) { 1099 if (imo->imo_membership[i]->inm_ifp == ifp && 1100 imo->imo_membership[i]->inm_addr.s_addr 1101 == mreq->imr_multiaddr.s_addr) 1102 break; 1103 } 1104 if (i < imo->imo_num_memberships) { 1105 error = EADDRINUSE; 1106 splx(s); 1107 break; 1108 } 1109 if (i == IP_MAX_MEMBERSHIPS) { 1110 error = ETOOMANYREFS; 1111 splx(s); 1112 break; 1113 } 1114 /* 1115 * Everything looks good; add a new record to the multicast 1116 * address list for the given interface. 1117 */ 1118 if ((imo->imo_membership[i] = 1119 in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { 1120 error = ENOBUFS; 1121 splx(s); 1122 break; 1123 } 1124 ++imo->imo_num_memberships; 1125 splx(s); 1126 break; 1127 1128 case IP_DROP_MEMBERSHIP: 1129 /* 1130 * Drop a multicast group membership. 1131 * Group must be a valid IP multicast address. 1132 */ 1133 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 1134 error = EINVAL; 1135 break; 1136 } 1137 mreq = mtod(m, struct ip_mreq *); 1138 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 1139 error = EINVAL; 1140 break; 1141 } 1142 1143 s = splimp(); 1144 /* 1145 * If an interface address was specified, get a pointer 1146 * to its ifnet structure. 1147 */ 1148 if (mreq->imr_interface.s_addr == INADDR_ANY) 1149 ifp = NULL; 1150 else { 1151 INADDR_TO_IFP(mreq->imr_interface, ifp); 1152 if (ifp == NULL) { 1153 error = EADDRNOTAVAIL; 1154 splx(s); 1155 break; 1156 } 1157 } 1158 /* 1159 * Find the membership in the membership array. 1160 */ 1161 for (i = 0; i < imo->imo_num_memberships; ++i) { 1162 if ((ifp == NULL || 1163 imo->imo_membership[i]->inm_ifp == ifp) && 1164 imo->imo_membership[i]->inm_addr.s_addr == 1165 mreq->imr_multiaddr.s_addr) 1166 break; 1167 } 1168 if (i == imo->imo_num_memberships) { 1169 error = EADDRNOTAVAIL; 1170 splx(s); 1171 break; 1172 } 1173 /* 1174 * Give up the multicast address record to which the 1175 * membership points. 1176 */ 1177 in_delmulti(imo->imo_membership[i]); 1178 /* 1179 * Remove the gap in the membership array. 1180 */ 1181 for (++i; i < imo->imo_num_memberships; ++i) 1182 imo->imo_membership[i-1] = imo->imo_membership[i]; 1183 --imo->imo_num_memberships; 1184 splx(s); 1185 break; 1186 1187 default: 1188 error = EOPNOTSUPP; 1189 break; 1190 } 1191 1192 /* 1193 * If all options have default values, no need to keep the mbuf. 1194 */ 1195 if (imo->imo_multicast_ifp == NULL && 1196 imo->imo_multicast_vif == -1 && 1197 imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && 1198 imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && 1199 imo->imo_num_memberships == 0) { 1200 free(*imop, M_IPMOPTS); 1201 *imop = NULL; 1202 } 1203 1204 return (error); 1205} 1206 1207/* 1208 * Return the IP multicast options in response to user getsockopt(). 1209 */ 1210static int 1211ip_getmoptions(optname, imo, mp) 1212 int optname; 1213 register struct ip_moptions *imo; 1214 register struct mbuf **mp; 1215{ 1216 u_char *ttl; 1217 u_char *loop; 1218 struct in_addr *addr; 1219 struct in_ifaddr *ia; 1220 1221 *mp = m_get(M_WAIT, MT_SOOPTS); 1222 1223 switch (optname) { 1224 1225 case IP_MULTICAST_VIF: 1226 if (imo != NULL) 1227 *(mtod(*mp, int *)) = imo->imo_multicast_vif; 1228 else 1229 *(mtod(*mp, int *)) = -1; 1230 (*mp)->m_len = sizeof(int); 1231 return(0); 1232 1233 case IP_MULTICAST_IF: 1234 addr = mtod(*mp, struct in_addr *); 1235 (*mp)->m_len = sizeof(struct in_addr); 1236 if (imo == NULL || imo->imo_multicast_ifp == NULL) 1237 addr->s_addr = INADDR_ANY; 1238 else { 1239 IFP_TO_IA(imo->imo_multicast_ifp, ia); 1240 addr->s_addr = (ia == NULL) ? INADDR_ANY 1241 : IA_SIN(ia)->sin_addr.s_addr; 1242 } 1243 return (0); 1244 1245 case IP_MULTICAST_TTL: 1246 ttl = mtod(*mp, u_char *); 1247 (*mp)->m_len = 1; 1248 *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL 1249 : imo->imo_multicast_ttl; 1250 return (0); 1251 1252 case IP_MULTICAST_LOOP: 1253 loop = mtod(*mp, u_char *); 1254 (*mp)->m_len = 1; 1255 *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP 1256 : imo->imo_multicast_loop; 1257 return (0); 1258 1259 default: 1260 return (EOPNOTSUPP); 1261 } 1262} 1263 1264/* 1265 * Discard the IP multicast options. 1266 */ 1267void 1268ip_freemoptions(imo) 1269 register struct ip_moptions *imo; 1270{ 1271 register int i; 1272 1273 if (imo != NULL) { 1274 for (i = 0; i < imo->imo_num_memberships; ++i) 1275 in_delmulti(imo->imo_membership[i]); 1276 free(imo, M_IPMOPTS); 1277 } 1278} 1279 1280/* 1281 * Routine called from ip_output() to loop back a copy of an IP multicast 1282 * packet to the input queue of a specified interface. Note that this 1283 * calls the output routine of the loopback "driver", but with an interface 1284 * pointer that might NOT be a loopback interface -- evil, but easier than 1285 * replicating that code here. 1286 */ 1287static void 1288ip_mloopback(ifp, m, dst, hlen) 1289 struct ifnet *ifp; 1290 register struct mbuf *m; 1291 register struct sockaddr_in *dst; 1292 int hlen; 1293{ 1294 register struct ip *ip; 1295 struct mbuf *copym; 1296 1297 copym = m_copy(m, 0, M_COPYALL); 1298 if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen)) 1299 copym = m_pullup(copym, hlen); 1300 if (copym != NULL) { 1301 /* 1302 * We don't bother to fragment if the IP length is greater 1303 * than the interface's MTU. Can this possibly matter? 1304 */ 1305 ip = mtod(copym, struct ip *); 1306 ip->ip_len = htons((u_short)ip->ip_len); 1307 ip->ip_off = htons((u_short)ip->ip_off); 1308 ip->ip_sum = 0; 1309 if (ip->ip_vhl == IP_VHL_BORING) { 1310 ip->ip_sum = in_cksum_hdr(ip); 1311 } else { 1312 ip->ip_sum = in_cksum(copym, hlen); 1313 } 1314 /* 1315 * NB: 1316 * It's not clear whether there are any lingering 1317 * reentrancy problems in other areas which might 1318 * be exposed by using ip_input directly (in 1319 * particular, everything which modifies the packet 1320 * in-place). Yet another option is using the 1321 * protosw directly to deliver the looped back 1322 * packet. For the moment, we'll err on the side 1323 * of safety by using if_simloop(). 1324 */ 1325#if 1 /* XXX */ 1326 if (dst->sin_family != AF_INET) { 1327 printf("ip_mloopback: bad address family %d\n", 1328 dst->sin_family); 1329 dst->sin_family = AF_INET; 1330 } 1331#endif 1332 1333#ifdef notdef 1334 copym->m_pkthdr.rcvif = ifp; 1335 ip_input(copym); 1336#else 1337 if_simloop(ifp, copym, (struct sockaddr *)dst, 0); 1338#endif 1339 } 1340} 1341