123745Skarels /* 244371Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 5*57966Sandrew * Redistribution and use in source and binary forms, with or without 6*57966Sandrew * modification, are permitted provided that the following conditions 7*57966Sandrew * are met: 8*57966Sandrew * 1. Redistributions of source code must retain the above copyright 9*57966Sandrew * notice, this list of conditions and the following disclaimer. 10*57966Sandrew * 2. Redistributions in binary form must reproduce the above copyright 11*57966Sandrew * notice, this list of conditions and the following disclaimer in the 12*57966Sandrew * documentation and/or other materials provided with the distribution. 13*57966Sandrew * 3. All advertising materials mentioning features or use of this software 14*57966Sandrew * must display the following acknowledgement: 15*57966Sandrew * This product includes software developed by the University of 16*57966Sandrew * California, Berkeley and its contributors. 17*57966Sandrew * 4. Neither the name of the University nor the names of its contributors 18*57966Sandrew * may be used to endorse or promote products derived from this software 19*57966Sandrew * without specific prior written permission. 2032787Sbostic * 21*57966Sandrew * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22*57966Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*57966Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*57966Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25*57966Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*57966Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*57966Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*57966Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*57966Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*57966Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*57966Sandrew * SUCH DAMAGE. 32*57966Sandrew * 33*57966Sandrew * @(#)ip_output.c 7.28 (Berkeley) 2/7/93 3423745Skarels */ 354571Swnj 3656531Sbostic #include <sys/param.h> 3756531Sbostic #include <sys/malloc.h> 3856531Sbostic #include <sys/mbuf.h> 3956531Sbostic #include <sys/errno.h> 4056531Sbostic #include <sys/protosw.h> 4156531Sbostic #include <sys/socket.h> 4256531Sbostic #include <sys/socketvar.h> 4310893Ssam 4456531Sbostic #include <net/if.h> 4556531Sbostic #include <net/route.h> 4610893Ssam 4756531Sbostic #include <netinet/in.h> 4856531Sbostic #include <netinet/in_systm.h> 4956531Sbostic #include <netinet/ip.h> 5056531Sbostic #include <netinet/in_pcb.h> 5156531Sbostic #include <netinet/in_var.h> 5256531Sbostic #include <netinet/ip_var.h> 534496Swnj 5412460Ssam #ifdef vax 5556531Sbostic #include <machine/mtpr.h> 5612460Ssam #endif 5710893Ssam 5854716Ssklower struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); 5954716Ssklower static void ip_mloopback __P((struct ifnet *, struct mbuf *, 6054716Ssklower struct sockaddr_in *)); 6124814Skarels 6224814Skarels /* 6324814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 6431037Skarels * header (with len, off, ttl, proto, tos, src, dst). 6531037Skarels * The mbuf chain containing the packet will be freed. 6631037Skarels * The mbuf opt, if present, will not be freed. 6724814Skarels */ 6854716Ssklower int 6957433Sandrew ip_output(m0, opt, ro, flags, imo) 7033598Skarels struct mbuf *m0; 715085Swnj struct mbuf *opt; 726339Ssam struct route *ro; 7312417Ssam int flags; 7454716Ssklower struct ip_moptions *imo; 754496Swnj { 7633598Skarels register struct ip *ip, *mhip; 775085Swnj register struct ifnet *ifp; 7833598Skarels register struct mbuf *m = m0; 7933598Skarels register int hlen = sizeof (struct ip); 8033598Skarels int len, off, error = 0; 816339Ssam struct route iproute; 8216602Ssam struct sockaddr_in *dst; 8340794Ssklower struct in_ifaddr *ia; 844496Swnj 8545014Skarels #ifdef DIAGNOSTIC 8645014Skarels if ((m->m_flags & M_PKTHDR) == 0) 8745014Skarels panic("ip_output no HDR"); 8845014Skarels #endif 8933598Skarels if (opt) { 9033598Skarels m = ip_insertoptions(m, opt, &len); 9133598Skarels hlen = len; 9233598Skarels } 9324814Skarels ip = mtod(m, struct ip *); 944924Swnj /* 954924Swnj * Fill in IP header. 964924Swnj */ 97*57966Sandrew if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { 9812417Ssam ip->ip_v = IPVERSION; 9912417Ssam ip->ip_off &= IP_DF; 10012417Ssam ip->ip_id = htons(ip_id++); 10116545Skarels ip->ip_hl = hlen >> 2; 10257433Sandrew ipstat.ips_localout++; 10339185Ssklower } else { 10424814Skarels hlen = ip->ip_hl << 2; 10539185Ssklower } 1064545Swnj /* 1077155Swnj * Route packet. 1085085Swnj */ 1096339Ssam if (ro == 0) { 1106339Ssam ro = &iproute; 1116339Ssam bzero((caddr_t)ro, sizeof (*ro)); 1125085Swnj } 11316602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 11426156Skarels /* 11526156Skarels * If there is a cached route, 11626156Skarels * check that it is to the same destination 11726156Skarels * and is still up. If not, free it and try again. 11826156Skarels */ 11926156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 12026156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 12126156Skarels RTFREE(ro->ro_rt); 12226156Skarels ro->ro_rt = (struct rtentry *)0; 12326156Skarels } 1246339Ssam if (ro->ro_rt == 0) { 12516602Ssam dst->sin_family = AF_INET; 12637318Skarels dst->sin_len = sizeof(*dst); 12716602Ssam dst->sin_addr = ip->ip_dst; 12826058Skarels } 12926058Skarels /* 13026058Skarels * If routing to interface only, 13126058Skarels * short circuit routing lookup. 13226058Skarels */ 13326058Skarels if (flags & IP_ROUTETOIF) { 13427196Skarels 13534500Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); 13627196Skarels if (ia == 0) 13727196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 13826058Skarels if (ia == 0) { 13957433Sandrew ipstat.ips_noroute++; 14026058Skarels error = ENETUNREACH; 14126058Skarels goto bad; 14226058Skarels } 14326058Skarels ifp = ia->ia_ifp; 14426058Skarels } else { 14526058Skarels if (ro->ro_rt == 0) 14626058Skarels rtalloc(ro); 14744371Skarels if (ro->ro_rt == 0) { 14857433Sandrew ipstat.ips_noroute++; 14944371Skarels error = EHOSTUNREACH; 15026058Skarels goto bad; 15126058Skarels } 15240794Ssklower ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; 15344371Skarels ifp = ro->ro_rt->rt_ifp; 15426058Skarels ro->ro_rt->rt_use++; 15530761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 15637318Skarels dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1576339Ssam } 15854716Ssklower if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 15954716Ssklower struct in_multi *inm; 16054716Ssklower extern struct ifnet loif; 16154716Ssklower 16254716Ssklower m->m_flags |= M_MCAST; 16354716Ssklower /* 16454716Ssklower * IP destination address is multicast. Make sure "dst" 16554716Ssklower * still points to the address in "ro". (It may have been 16654716Ssklower * changed to point to a gateway address, above.) 16754716Ssklower */ 16854716Ssklower dst = (struct sockaddr_in *)&ro->ro_dst; 16954716Ssklower /* 17054716Ssklower * See if the caller provided any multicast options 17154716Ssklower */ 17254716Ssklower if (imo != NULL) { 17354716Ssklower ip->ip_ttl = imo->imo_multicast_ttl; 17454716Ssklower if (imo->imo_multicast_ifp != NULL) 17554716Ssklower ifp = imo->imo_multicast_ifp; 17654716Ssklower } else 17754716Ssklower ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; 17854716Ssklower /* 17954716Ssklower * Confirm that the outgoing interface supports multicast. 18054716Ssklower */ 18154716Ssklower if ((ifp->if_flags & IFF_MULTICAST) == 0) { 18257433Sandrew ipstat.ips_noroute++; 18354716Ssklower error = ENETUNREACH; 18454716Ssklower goto bad; 18554716Ssklower } 18654716Ssklower /* 18754716Ssklower * If source address not specified yet, use address 18854716Ssklower * of outgoing interface. 18954716Ssklower */ 19054716Ssklower if (ip->ip_src.s_addr == INADDR_ANY) { 19154716Ssklower register struct in_ifaddr *ia; 19254716Ssklower 19354716Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 19454716Ssklower if (ia->ia_ifp == ifp) { 19554716Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 19654716Ssklower break; 19754716Ssklower } 19854716Ssklower } 19954716Ssklower 20054716Ssklower IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); 20154716Ssklower if (inm != NULL && 20254716Ssklower (imo == NULL || imo->imo_multicast_loop)) { 20354716Ssklower /* 20454716Ssklower * If we belong to the destination multicast group 20554716Ssklower * on the outgoing interface, and the caller did not 20654716Ssklower * forbid loopback, loop back a copy. 20754716Ssklower */ 20854716Ssklower ip_mloopback(ifp, m, dst); 20954716Ssklower } 21054716Ssklower #ifdef MROUTING 21157878Ssklower else { 21254716Ssklower /* 21354716Ssklower * If we are acting as a multicast router, perform 21454716Ssklower * multicast forwarding as if the packet had just 21554716Ssklower * arrived on the interface to which we are about 21654716Ssklower * to send. The multicast forwarding function 21754716Ssklower * recursively calls this function, using the 21854716Ssklower * IP_FORWARDING flag to prevent infinite recursion. 21954716Ssklower * 22054716Ssklower * Multicasts that are looped back by ip_mloopback(), 22154716Ssklower * above, will be forwarded by the ip_input() routine, 22254716Ssklower * if necessary. 22354716Ssklower */ 22457878Ssklower extern struct socket *ip_mrouter; 22557878Ssklower if (ip_mrouter && (flags & IP_FORWARDING) == 0) { 22657878Ssklower if (ip_mforward(m, ifp) != 0) { 22757878Ssklower m_freem(m); 22857878Ssklower goto done; 22957878Ssklower } 23054716Ssklower } 23154716Ssklower } 23254716Ssklower #endif 23354716Ssklower /* 23454716Ssklower * Multicasts with a time-to-live of zero may be looped- 23554716Ssklower * back, above, but must not be transmitted on a network. 23654716Ssklower * Also, multicasts addressed to the loopback interface 23754716Ssklower * are not sent -- the above call to ip_mloopback() will 23854716Ssklower * loop back a copy if this host actually belongs to the 23954716Ssklower * destination group on the loopback interface. 24054716Ssklower */ 24154716Ssklower if (ip->ip_ttl == 0 || ifp == &loif) { 24254716Ssklower m_freem(m); 24354716Ssklower goto done; 24454716Ssklower } 24554716Ssklower 24654716Ssklower goto sendit; 24754716Ssklower } 24823745Skarels #ifndef notdef 2497155Swnj /* 25023745Skarels * If source address not specified yet, use address 25123745Skarels * of outgoing interface. 25223745Skarels */ 25340794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 25440794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 25523745Skarels #endif 25623745Skarels /* 25710402Ssam * Look for broadcast address and 25810402Ssam * and verify user is allowed to send 25910146Ssam * such a packet. 2607155Swnj */ 26118375Skarels if (in_broadcast(dst->sin_addr)) { 26210146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 26310146Ssam error = EADDRNOTAVAIL; 26410146Ssam goto bad; 26510146Ssam } 26612417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 2677155Swnj error = EACCES; 2686339Ssam goto bad; 2696505Ssam } 27010146Ssam /* don't allow broadcast messages to be fragmented */ 27144372Skarels if ((u_short)ip->ip_len > ifp->if_mtu) { 27210146Ssam error = EMSGSIZE; 27310146Ssam goto bad; 27410146Ssam } 27537318Skarels m->m_flags |= M_BCAST; 27657433Sandrew } else 27757433Sandrew m->m_flags &= ~M_BCAST; 2786339Ssam 27954716Ssklower sendit: 2805085Swnj /* 2814924Swnj * If small enough for interface, can just send directly. 2824545Swnj */ 28344372Skarels if ((u_short)ip->ip_len <= ifp->if_mtu) { 2845085Swnj ip->ip_len = htons((u_short)ip->ip_len); 2855085Swnj ip->ip_off = htons((u_short)ip->ip_off); 2865085Swnj ip->ip_sum = 0; 2875085Swnj ip->ip_sum = in_cksum(m, hlen); 28840794Ssklower error = (*ifp->if_output)(ifp, m, 28940794Ssklower (struct sockaddr *)dst, ro->ro_rt); 2907155Swnj goto done; 2914908Swnj } 2924924Swnj /* 2934924Swnj * Too large for interface; fragment if possible. 2944924Swnj * Must be able to put at least 8 bytes per fragment. 2954924Swnj */ 2966505Ssam if (ip->ip_off & IP_DF) { 2976505Ssam error = EMSGSIZE; 29857433Sandrew ipstat.ips_cantfrag++; 2994924Swnj goto bad; 3006505Ssam } 3015085Swnj len = (ifp->if_mtu - hlen) &~ 7; 3026505Ssam if (len < 8) { 3036505Ssam error = EMSGSIZE; 3044924Swnj goto bad; 3056505Ssam } 3064924Swnj 30733744Skarels { 30833744Skarels int mhlen, firstlen = len; 30937318Skarels struct mbuf **mnext = &m->m_nextpkt; 31033744Skarels 3114924Swnj /* 31233744Skarels * Loop through length of segment after first fragment, 31333744Skarels * make new header and copy data of each part and link onto chain. 3144924Swnj */ 31533598Skarels m0 = m; 31633744Skarels mhlen = sizeof (struct ip); 31744372Skarels for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 31837318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 31933598Skarels if (m == 0) { 3206505Ssam error = ENOBUFS; 32157433Sandrew ipstat.ips_odropped++; 32234820Skarels goto sendorfree; 3236505Ssam } 32437318Skarels m->m_data += max_linkhdr; 32533598Skarels mhip = mtod(m, struct ip *); 3264924Swnj *mhip = *ip; 3274952Swnj if (hlen > sizeof (struct ip)) { 32833744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 32933598Skarels mhip->ip_hl = mhlen >> 2; 33033744Skarels } 33133598Skarels m->m_len = mhlen; 33233744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 33316545Skarels if (ip->ip_off & IP_MF) 33416545Skarels mhip->ip_off |= IP_MF; 33544372Skarels if (off + len >= (u_short)ip->ip_len) 33644372Skarels len = (u_short)ip->ip_len - off; 33733598Skarels else 3384924Swnj mhip->ip_off |= IP_MF; 33933598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 34033598Skarels m->m_next = m_copy(m0, off, len); 34133598Skarels if (m->m_next == 0) { 3426505Ssam error = ENOBUFS; /* ??? */ 34357433Sandrew ipstat.ips_odropped++; 34433744Skarels goto sendorfree; 3454674Swnj } 34637318Skarels m->m_pkthdr.len = mhlen + len; 34737318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 3485892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 3495892Sroot mhip->ip_sum = 0; 35033598Skarels mhip->ip_sum = in_cksum(m, mhlen); 35133744Skarels *mnext = m; 35237318Skarels mnext = &m->m_nextpkt; 35339185Ssklower ipstat.ips_ofragments++; 3544924Swnj } 35533744Skarels /* 35633744Skarels * Update first fragment by trimming what's been copied out 35733744Skarels * and updating header, then send each fragment (in order). 35833744Skarels */ 35940254Smckusick m = m0; 36044372Skarels m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 36137318Skarels m->m_pkthdr.len = hlen + firstlen; 36237318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 36333983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 36433744Skarels ip->ip_sum = 0; 36540254Smckusick ip->ip_sum = in_cksum(m, hlen); 36633744Skarels sendorfree: 36733744Skarels for (m = m0; m; m = m0) { 36837318Skarels m0 = m->m_nextpkt; 36937318Skarels m->m_nextpkt = 0; 37033744Skarels if (error == 0) 37133744Skarels error = (*ifp->if_output)(ifp, m, 37240794Ssklower (struct sockaddr *)dst, ro->ro_rt); 37333744Skarels else 37433744Skarels m_freem(m); 37533744Skarels } 37657433Sandrew 37757433Sandrew if (error == 0) 37857433Sandrew ipstat.ips_fragmented++; 37933744Skarels } 3807155Swnj done: 38112417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 3827155Swnj RTFREE(ro->ro_rt); 3836505Ssam return (error); 38433744Skarels bad: 38533744Skarels m_freem(m0); 38633744Skarels goto done; 3874924Swnj } 3884924Swnj 3894924Swnj /* 39024814Skarels * Insert IP options into preformed packet. 39124814Skarels * Adjust IP destination as required for IP source routing, 39224814Skarels * as indicated by a non-zero in_addr at the start of the options. 39324814Skarels */ 39424814Skarels struct mbuf * 39524814Skarels ip_insertoptions(m, opt, phlen) 39624814Skarels register struct mbuf *m; 39724814Skarels struct mbuf *opt; 39824814Skarels int *phlen; 39924814Skarels { 40024814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 40124814Skarels struct mbuf *n; 40224814Skarels register struct ip *ip = mtod(m, struct ip *); 40326385Skarels unsigned optlen; 40424814Skarels 40524814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 40644372Skarels if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 40744372Skarels return (m); /* XXX should fail */ 40824814Skarels if (p->ipopt_dst.s_addr) 40924814Skarels ip->ip_dst = p->ipopt_dst; 41037318Skarels if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 41137318Skarels MGETHDR(n, M_DONTWAIT, MT_HEADER); 41224814Skarels if (n == 0) 41324814Skarels return (m); 41437318Skarels n->m_pkthdr.len = m->m_pkthdr.len + optlen; 41524814Skarels m->m_len -= sizeof(struct ip); 41637318Skarels m->m_data += sizeof(struct ip); 41724814Skarels n->m_next = m; 41824814Skarels m = n; 41924814Skarels m->m_len = optlen + sizeof(struct ip); 42037318Skarels m->m_data += max_linkhdr; 42124814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 42224814Skarels } else { 42337318Skarels m->m_data -= optlen; 42424814Skarels m->m_len += optlen; 42537318Skarels m->m_pkthdr.len += optlen; 42624814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 42724814Skarels } 42824814Skarels ip = mtod(m, struct ip *); 42926385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 43024814Skarels *phlen = sizeof(struct ip) + optlen; 43124814Skarels ip->ip_len += optlen; 43224814Skarels return (m); 43324814Skarels } 43424814Skarels 43524814Skarels /* 43633744Skarels * Copy options from ip to jp, 43733744Skarels * omitting those not copied during fragmentation. 4384924Swnj */ 43954716Ssklower int 44033744Skarels ip_optcopy(ip, jp) 4414924Swnj struct ip *ip, *jp; 4424924Swnj { 4434924Swnj register u_char *cp, *dp; 4444924Swnj int opt, optlen, cnt; 4454924Swnj 4464924Swnj cp = (u_char *)(ip + 1); 4474924Swnj dp = (u_char *)(jp + 1); 4484924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 4494924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 4504924Swnj opt = cp[0]; 4514924Swnj if (opt == IPOPT_EOL) 4524924Swnj break; 45357433Sandrew if (opt == IPOPT_NOP) { 45457433Sandrew /* Preserve for IP mcast tunnel's LSRR alignment. */ 45557433Sandrew *dp++ = IPOPT_NOP; 4564924Swnj optlen = 1; 45757433Sandrew continue; 45857433Sandrew } else 45924814Skarels optlen = cp[IPOPT_OLEN]; 46033744Skarels /* bogus lengths should have been caught by ip_dooptions */ 46133744Skarels if (optlen > cnt) 46233744Skarels optlen = cnt; 46333744Skarels if (IPOPT_COPIED(opt)) { 4644952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 4654924Swnj dp += optlen; 4664674Swnj } 4674545Swnj } 4684924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 4694924Swnj *dp++ = IPOPT_EOL; 4704924Swnj return (optlen); 4714496Swnj } 47224814Skarels 47324814Skarels /* 47424814Skarels * IP socket option processing. 47524814Skarels */ 47654716Ssklower int 47744371Skarels ip_ctloutput(op, so, level, optname, mp) 47824814Skarels int op; 47924814Skarels struct socket *so; 48024814Skarels int level, optname; 48144371Skarels struct mbuf **mp; 48224814Skarels { 48344371Skarels register struct inpcb *inp = sotoinpcb(so); 48444371Skarels register struct mbuf *m = *mp; 48544371Skarels register int optval; 48624814Skarels int error = 0; 48724814Skarels 48824814Skarels if (level != IPPROTO_IP) 48951273Ssklower goto freeit; 49024814Skarels else switch (op) { 49124814Skarels 49224814Skarels case PRCO_SETOPT: 49324814Skarels switch (optname) { 49424814Skarels case IP_OPTIONS: 49545014Skarels #ifdef notyet 49644371Skarels case IP_RETOPTS: 49744371Skarels return (ip_pcbopts(optname, &inp->inp_options, m)); 49845014Skarels #else 49945014Skarels return (ip_pcbopts(&inp->inp_options, m)); 50045014Skarels #endif 50124814Skarels 50244371Skarels case IP_TOS: 50344371Skarels case IP_TTL: 50444371Skarels case IP_RECVOPTS: 50544371Skarels case IP_RECVRETOPTS: 50644371Skarels case IP_RECVDSTADDR: 50744371Skarels if (m->m_len != sizeof(int)) 50844371Skarels error = EINVAL; 50944371Skarels else { 51044371Skarels optval = *mtod(m, int *); 51145014Skarels switch (optname) { 51244371Skarels 51344371Skarels case IP_TOS: 51444371Skarels inp->inp_ip.ip_tos = optval; 51544371Skarels break; 51644371Skarels 51744371Skarels case IP_TTL: 51845567Ssklower inp->inp_ip.ip_ttl = optval; 51944371Skarels break; 52044371Skarels #define OPTSET(bit) \ 52144371Skarels if (optval) \ 52244371Skarels inp->inp_flags |= bit; \ 52344371Skarels else \ 52444371Skarels inp->inp_flags &= ~bit; 52544371Skarels 52644371Skarels case IP_RECVOPTS: 52744371Skarels OPTSET(INP_RECVOPTS); 52844371Skarels break; 52944371Skarels 53044371Skarels case IP_RECVRETOPTS: 53144371Skarels OPTSET(INP_RECVRETOPTS); 53244371Skarels break; 53344371Skarels 53444371Skarels case IP_RECVDSTADDR: 53544371Skarels OPTSET(INP_RECVDSTADDR); 53644371Skarels break; 53744371Skarels } 53844371Skarels } 53944371Skarels break; 54044371Skarels #undef OPTSET 54144371Skarels 54254716Ssklower case IP_MULTICAST_IF: 54354716Ssklower case IP_MULTICAST_TTL: 54454716Ssklower case IP_MULTICAST_LOOP: 54554716Ssklower case IP_ADD_MEMBERSHIP: 54654716Ssklower case IP_DROP_MEMBERSHIP: 54754716Ssklower error = ip_setmoptions(optname, &inp->inp_moptions, m); 54854716Ssklower break; 54954716Ssklower 55051273Ssklower freeit: 55124814Skarels default: 55224814Skarels error = EINVAL; 55324814Skarels break; 55424814Skarels } 55544371Skarels if (m) 55644371Skarels (void)m_free(m); 55724814Skarels break; 55824814Skarels 55924814Skarels case PRCO_GETOPT: 56024814Skarels switch (optname) { 56124814Skarels case IP_OPTIONS: 56245014Skarels case IP_RETOPTS: 56344371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 56424814Skarels if (inp->inp_options) { 56544371Skarels m->m_len = inp->inp_options->m_len; 56624814Skarels bcopy(mtod(inp->inp_options, caddr_t), 56744371Skarels mtod(m, caddr_t), (unsigned)m->m_len); 56824814Skarels } else 56944371Skarels m->m_len = 0; 57024814Skarels break; 57144371Skarels 57244371Skarels case IP_TOS: 57344371Skarels case IP_TTL: 57444371Skarels case IP_RECVOPTS: 57544371Skarels case IP_RECVRETOPTS: 57644371Skarels case IP_RECVDSTADDR: 57744371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 57844371Skarels m->m_len = sizeof(int); 57945014Skarels switch (optname) { 58044371Skarels 58144371Skarels case IP_TOS: 58244371Skarels optval = inp->inp_ip.ip_tos; 58344371Skarels break; 58444371Skarels 58544371Skarels case IP_TTL: 58645567Ssklower optval = inp->inp_ip.ip_ttl; 58744371Skarels break; 58844371Skarels 58944371Skarels #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 59044371Skarels 59144371Skarels case IP_RECVOPTS: 59244371Skarels optval = OPTBIT(INP_RECVOPTS); 59344371Skarels break; 59444371Skarels 59544371Skarels case IP_RECVRETOPTS: 59644371Skarels optval = OPTBIT(INP_RECVRETOPTS); 59744371Skarels break; 59844371Skarels 59944371Skarels case IP_RECVDSTADDR: 60044371Skarels optval = OPTBIT(INP_RECVDSTADDR); 60144371Skarels break; 60244371Skarels } 60344371Skarels *mtod(m, int *) = optval; 60444371Skarels break; 60544371Skarels 60654716Ssklower case IP_MULTICAST_IF: 60754716Ssklower case IP_MULTICAST_TTL: 60854716Ssklower case IP_MULTICAST_LOOP: 60954716Ssklower case IP_ADD_MEMBERSHIP: 61054716Ssklower case IP_DROP_MEMBERSHIP: 61154716Ssklower error = ip_getmoptions(optname, inp->inp_moptions, mp); 61254716Ssklower break; 61354716Ssklower 61424814Skarels default: 61524814Skarels error = EINVAL; 61624814Skarels break; 61724814Skarels } 61824814Skarels break; 61924814Skarels } 62024814Skarels return (error); 62124814Skarels } 62224814Skarels 62324814Skarels /* 62426036Skarels * Set up IP options in pcb for insertion in output packets. 62526036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 62626036Skarels * with destination address if source routed. 62724814Skarels */ 62854716Ssklower int 62945014Skarels #ifdef notyet 63045014Skarels ip_pcbopts(optname, pcbopt, m) 63145014Skarels int optname; 63245014Skarels #else 63326036Skarels ip_pcbopts(pcbopt, m) 63445014Skarels #endif 63526036Skarels struct mbuf **pcbopt; 63626036Skarels register struct mbuf *m; 63724814Skarels { 63824814Skarels register cnt, optlen; 63924814Skarels register u_char *cp; 64024814Skarels u_char opt; 64124814Skarels 64224814Skarels /* turn off any old options */ 64326036Skarels if (*pcbopt) 64426385Skarels (void)m_free(*pcbopt); 64526036Skarels *pcbopt = 0; 64624814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 64724814Skarels /* 64824814Skarels * Only turning off any previous options. 64924814Skarels */ 65024814Skarels if (m) 65126385Skarels (void)m_free(m); 65224814Skarels return (0); 65324814Skarels } 65424814Skarels 65524814Skarels #ifndef vax 65624814Skarels if (m->m_len % sizeof(long)) 65724814Skarels goto bad; 65824814Skarels #endif 65924814Skarels /* 66024814Skarels * IP first-hop destination address will be stored before 66124814Skarels * actual options; move other options back 66224814Skarels * and clear it when none present. 66324814Skarels */ 66437318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 66524814Skarels goto bad; 66624814Skarels cnt = m->m_len; 66724814Skarels m->m_len += sizeof(struct in_addr); 66824814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 66926385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 67024814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 67124814Skarels 67224814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 67324814Skarels opt = cp[IPOPT_OPTVAL]; 67424814Skarels if (opt == IPOPT_EOL) 67524814Skarels break; 67624814Skarels if (opt == IPOPT_NOP) 67724814Skarels optlen = 1; 67824814Skarels else { 67924814Skarels optlen = cp[IPOPT_OLEN]; 68024814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 68124814Skarels goto bad; 68224814Skarels } 68324814Skarels switch (opt) { 68424814Skarels 68524814Skarels default: 68624814Skarels break; 68724814Skarels 68824814Skarels case IPOPT_LSRR: 68924814Skarels case IPOPT_SSRR: 69024814Skarels /* 69124814Skarels * user process specifies route as: 69224814Skarels * ->A->B->C->D 69324814Skarels * D must be our final destination (but we can't 69424814Skarels * check that since we may not have connected yet). 69524814Skarels * A is first hop destination, which doesn't appear in 69624814Skarels * actual IP option, but is stored before the options. 69724814Skarels */ 69824814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 69924814Skarels goto bad; 70024814Skarels m->m_len -= sizeof(struct in_addr); 70124814Skarels cnt -= sizeof(struct in_addr); 70224814Skarels optlen -= sizeof(struct in_addr); 70324814Skarels cp[IPOPT_OLEN] = optlen; 70424814Skarels /* 70524814Skarels * Move first hop before start of options. 70624814Skarels */ 70726385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 70824814Skarels sizeof(struct in_addr)); 70924814Skarels /* 71024814Skarels * Then copy rest of options back 71124814Skarels * to close up the deleted entry. 71224814Skarels */ 71326385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 71426385Skarels sizeof(struct in_addr)), 71526385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 71626385Skarels (unsigned)cnt + sizeof(struct in_addr)); 71724814Skarels break; 71824814Skarels } 71924814Skarels } 72037318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 72137318Skarels goto bad; 72226036Skarels *pcbopt = m; 72324814Skarels return (0); 72424814Skarels 72524814Skarels bad: 72626385Skarels (void)m_free(m); 72724814Skarels return (EINVAL); 72824814Skarels } 72954716Ssklower 73054716Ssklower /* 73154716Ssklower * Set the IP multicast options in response to user setsockopt(). 73254716Ssklower */ 73354716Ssklower int 73454716Ssklower ip_setmoptions(optname, imop, m) 73554716Ssklower int optname; 73654716Ssklower struct ip_moptions **imop; 73754716Ssklower struct mbuf *m; 73854716Ssklower { 73954716Ssklower register int error = 0; 74054716Ssklower u_char loop; 74154716Ssklower register int i; 74254716Ssklower struct in_addr addr; 74354716Ssklower register struct ip_mreq *mreq; 74454716Ssklower register struct ifnet *ifp; 74554716Ssklower register struct ip_moptions *imo = *imop; 74654716Ssklower struct route ro; 74754716Ssklower register struct sockaddr_in *dst; 74854716Ssklower 74954716Ssklower if (imo == NULL) { 75054716Ssklower /* 75154716Ssklower * No multicast option buffer attached to the pcb; 75254716Ssklower * allocate one and initialize to default values. 75354716Ssklower */ 75454716Ssklower imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, 75554716Ssklower M_WAITOK); 75654716Ssklower 75754716Ssklower if (imo == NULL) 75854716Ssklower return (ENOBUFS); 75954716Ssklower *imop = imo; 76054716Ssklower imo->imo_multicast_ifp = NULL; 76154716Ssklower imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 76254716Ssklower imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 76354716Ssklower imo->imo_num_memberships = 0; 76454716Ssklower } 76554716Ssklower 76654716Ssklower switch (optname) { 76754716Ssklower 76854716Ssklower case IP_MULTICAST_IF: 76954716Ssklower /* 77054716Ssklower * Select the interface for outgoing multicast packets. 77154716Ssklower */ 77254716Ssklower if (m == NULL || m->m_len != sizeof(struct in_addr)) { 77354716Ssklower error = EINVAL; 77454716Ssklower break; 77554716Ssklower } 77654716Ssklower addr = *(mtod(m, struct in_addr *)); 77754716Ssklower /* 77854716Ssklower * INADDR_ANY is used to remove a previous selection. 77954716Ssklower * When no interface is selected, a default one is 78054716Ssklower * chosen every time a multicast packet is sent. 78154716Ssklower */ 78254716Ssklower if (addr.s_addr == INADDR_ANY) { 78354716Ssklower imo->imo_multicast_ifp = NULL; 78454716Ssklower break; 78554716Ssklower } 78654716Ssklower /* 78754716Ssklower * The selected interface is identified by its local 78854716Ssklower * IP address. Find the interface and confirm that 78954716Ssklower * it supports multicasting. 79054716Ssklower */ 79154716Ssklower INADDR_TO_IFP(addr, ifp); 79254716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 79354716Ssklower error = EADDRNOTAVAIL; 79454716Ssklower break; 79554716Ssklower } 79654716Ssklower imo->imo_multicast_ifp = ifp; 79754716Ssklower break; 79854716Ssklower 79954716Ssklower case IP_MULTICAST_TTL: 80054716Ssklower /* 80154716Ssklower * Set the IP time-to-live for outgoing multicast packets. 80254716Ssklower */ 80354716Ssklower if (m == NULL || m->m_len != 1) { 80454716Ssklower error = EINVAL; 80554716Ssklower break; 80654716Ssklower } 80754716Ssklower imo->imo_multicast_ttl = *(mtod(m, u_char *)); 80854716Ssklower break; 80954716Ssklower 81054716Ssklower case IP_MULTICAST_LOOP: 81154716Ssklower /* 81254716Ssklower * Set the loopback flag for outgoing multicast packets. 81354716Ssklower * Must be zero or one. 81454716Ssklower */ 81554716Ssklower if (m == NULL || m->m_len != 1 || 81654716Ssklower (loop = *(mtod(m, u_char *))) > 1) { 81754716Ssklower error = EINVAL; 81854716Ssklower break; 81954716Ssklower } 82054716Ssklower imo->imo_multicast_loop = loop; 82154716Ssklower break; 82254716Ssklower 82354716Ssklower case IP_ADD_MEMBERSHIP: 82454716Ssklower /* 82554716Ssklower * Add a multicast group membership. 82654716Ssklower * Group must be a valid IP multicast address. 82754716Ssklower */ 82854716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 82954716Ssklower error = EINVAL; 83054716Ssklower break; 83154716Ssklower } 83254716Ssklower mreq = mtod(m, struct ip_mreq *); 83354716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 83454716Ssklower error = EINVAL; 83554716Ssklower break; 83654716Ssklower } 83754716Ssklower /* 83854716Ssklower * If no interface address was provided, use the interface of 83954716Ssklower * the route to the given multicast address. 84054716Ssklower */ 84154716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) { 84254716Ssklower ro.ro_rt = NULL; 84354716Ssklower dst = (struct sockaddr_in *)&ro.ro_dst; 84454716Ssklower dst->sin_len = sizeof(*dst); 84554716Ssklower dst->sin_family = AF_INET; 84654716Ssklower dst->sin_addr = mreq->imr_multiaddr; 84754716Ssklower rtalloc(&ro); 84854716Ssklower if (ro.ro_rt == NULL) { 84954716Ssklower error = EADDRNOTAVAIL; 85054716Ssklower break; 85154716Ssklower } 85254716Ssklower ifp = ro.ro_rt->rt_ifp; 85354716Ssklower rtfree(ro.ro_rt); 85454716Ssklower } 85554716Ssklower else { 85654716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 85754716Ssklower } 85854716Ssklower /* 85954716Ssklower * See if we found an interface, and confirm that it 86054716Ssklower * supports multicast. 86154716Ssklower */ 86254716Ssklower if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 86354716Ssklower error = EADDRNOTAVAIL; 86454716Ssklower break; 86554716Ssklower } 86654716Ssklower /* 86754716Ssklower * See if the membership already exists or if all the 86854716Ssklower * membership slots are full. 86954716Ssklower */ 87054716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 87154716Ssklower if (imo->imo_membership[i]->inm_ifp == ifp && 87254716Ssklower imo->imo_membership[i]->inm_addr.s_addr 87354716Ssklower == mreq->imr_multiaddr.s_addr) 87454716Ssklower break; 87554716Ssklower } 87654716Ssklower if (i < imo->imo_num_memberships) { 87754716Ssklower error = EADDRINUSE; 87854716Ssklower break; 87954716Ssklower } 88054716Ssklower if (i == IP_MAX_MEMBERSHIPS) { 88154716Ssklower error = ETOOMANYREFS; 88254716Ssklower break; 88354716Ssklower } 88454716Ssklower /* 88554716Ssklower * Everything looks good; add a new record to the multicast 88654716Ssklower * address list for the given interface. 88754716Ssklower */ 88854716Ssklower if ((imo->imo_membership[i] = 88954716Ssklower in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { 89054716Ssklower error = ENOBUFS; 89154716Ssklower break; 89254716Ssklower } 89354716Ssklower ++imo->imo_num_memberships; 89454716Ssklower break; 89554716Ssklower 89654716Ssklower case IP_DROP_MEMBERSHIP: 89754716Ssklower /* 89854716Ssklower * Drop a multicast group membership. 89954716Ssklower * Group must be a valid IP multicast address. 90054716Ssklower */ 90154716Ssklower if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { 90254716Ssklower error = EINVAL; 90354716Ssklower break; 90454716Ssklower } 90554716Ssklower mreq = mtod(m, struct ip_mreq *); 90654716Ssklower if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { 90754716Ssklower error = EINVAL; 90854716Ssklower break; 90954716Ssklower } 91054716Ssklower /* 91154716Ssklower * If an interface address was specified, get a pointer 91254716Ssklower * to its ifnet structure. 91354716Ssklower */ 91454716Ssklower if (mreq->imr_interface.s_addr == INADDR_ANY) 91554716Ssklower ifp = NULL; 91654716Ssklower else { 91754716Ssklower INADDR_TO_IFP(mreq->imr_interface, ifp); 91854716Ssklower if (ifp == NULL) { 91954716Ssklower error = EADDRNOTAVAIL; 92054716Ssklower break; 92154716Ssklower } 92254716Ssklower } 92354716Ssklower /* 92454716Ssklower * Find the membership in the membership array. 92554716Ssklower */ 92654716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) { 92754716Ssklower if ((ifp == NULL || 92854716Ssklower imo->imo_membership[i]->inm_ifp == ifp) && 92954716Ssklower imo->imo_membership[i]->inm_addr.s_addr == 93054716Ssklower mreq->imr_multiaddr.s_addr) 93154716Ssklower break; 93254716Ssklower } 93354716Ssklower if (i == imo->imo_num_memberships) { 93454716Ssklower error = EADDRNOTAVAIL; 93554716Ssklower break; 93654716Ssklower } 93754716Ssklower /* 93854716Ssklower * Give up the multicast address record to which the 93954716Ssklower * membership points. 94054716Ssklower */ 94154716Ssklower in_delmulti(imo->imo_membership[i]); 94254716Ssklower /* 94354716Ssklower * Remove the gap in the membership array. 94454716Ssklower */ 94554716Ssklower for (++i; i < imo->imo_num_memberships; ++i) 94654716Ssklower imo->imo_membership[i-1] = imo->imo_membership[i]; 94754716Ssklower --imo->imo_num_memberships; 94854716Ssklower break; 94954716Ssklower 95054716Ssklower default: 95154716Ssklower error = EOPNOTSUPP; 95254716Ssklower break; 95354716Ssklower } 95454716Ssklower 95554716Ssklower /* 95654716Ssklower * If all options have default values, no need to keep the mbuf. 95754716Ssklower */ 95854716Ssklower if (imo->imo_multicast_ifp == NULL && 95954716Ssklower imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && 96054716Ssklower imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && 96154716Ssklower imo->imo_num_memberships == 0) { 96254716Ssklower free(*imop, M_IPMOPTS); 96354716Ssklower *imop = NULL; 96454716Ssklower } 96554716Ssklower 96654716Ssklower return (error); 96754716Ssklower } 96854716Ssklower 96954716Ssklower /* 97054716Ssklower * Return the IP multicast options in response to user getsockopt(). 97154716Ssklower */ 97254716Ssklower int 97354716Ssklower ip_getmoptions(optname, imo, mp) 97454716Ssklower int optname; 97554716Ssklower register struct ip_moptions *imo; 97654716Ssklower register struct mbuf **mp; 97754716Ssklower { 97854716Ssklower u_char *ttl; 97954716Ssklower u_char *loop; 98054716Ssklower struct in_addr *addr; 98154716Ssklower struct in_ifaddr *ia; 98254716Ssklower 98354716Ssklower *mp = m_get(M_WAIT, MT_SOOPTS); 98454716Ssklower 98554716Ssklower switch (optname) { 98654716Ssklower 98754716Ssklower case IP_MULTICAST_IF: 98854716Ssklower addr = mtod(*mp, struct in_addr *); 98954716Ssklower (*mp)->m_len = sizeof(struct in_addr); 99054716Ssklower if (imo == NULL || imo->imo_multicast_ifp == NULL) 99154716Ssklower addr->s_addr = INADDR_ANY; 99254716Ssklower else { 99354716Ssklower IFP_TO_IA(imo->imo_multicast_ifp, ia); 99454716Ssklower addr->s_addr = (ia == NULL) ? INADDR_ANY 99554716Ssklower : IA_SIN(ia)->sin_addr.s_addr; 99654716Ssklower } 99754716Ssklower return (0); 99854716Ssklower 99954716Ssklower case IP_MULTICAST_TTL: 100054716Ssklower ttl = mtod(*mp, u_char *); 100154716Ssklower (*mp)->m_len = 1; 100254716Ssklower *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL 100354716Ssklower : imo->imo_multicast_ttl; 100454716Ssklower return (0); 100554716Ssklower 100654716Ssklower case IP_MULTICAST_LOOP: 100754716Ssklower loop = mtod(*mp, u_char *); 100854716Ssklower (*mp)->m_len = 1; 100954716Ssklower *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP 101054716Ssklower : imo->imo_multicast_loop; 101154716Ssklower return (0); 101254716Ssklower 101354716Ssklower default: 101454716Ssklower return (EOPNOTSUPP); 101554716Ssklower } 101654716Ssklower } 101754716Ssklower 101854716Ssklower /* 101954716Ssklower * Discard the IP multicast options. 102054716Ssklower */ 102154716Ssklower void 102254716Ssklower ip_freemoptions(imo) 102354716Ssklower register struct ip_moptions *imo; 102454716Ssklower { 102554716Ssklower register int i; 102654716Ssklower 102754716Ssklower if (imo != NULL) { 102854716Ssklower for (i = 0; i < imo->imo_num_memberships; ++i) 102954716Ssklower in_delmulti(imo->imo_membership[i]); 103054716Ssklower free(imo, M_IPMOPTS); 103154716Ssklower } 103254716Ssklower } 103354716Ssklower 103454716Ssklower /* 103554716Ssklower * Routine called from ip_output() to loop back a copy of an IP multicast 103654716Ssklower * packet to the input queue of a specified interface. Note that this 103754716Ssklower * calls the output routine of the loopback "driver", but with an interface 103854716Ssklower * pointer that might NOT be &loif -- easier than replicating that code here. 103954716Ssklower */ 104054716Ssklower static void 104154716Ssklower ip_mloopback(ifp, m, dst) 104254716Ssklower struct ifnet *ifp; 104354716Ssklower register struct mbuf *m; 104454716Ssklower register struct sockaddr_in *dst; 104554716Ssklower { 104654716Ssklower register struct ip *ip; 104754716Ssklower struct mbuf *copym; 104854716Ssklower 104954716Ssklower copym = m_copy(m, 0, M_COPYALL); 105054716Ssklower if (copym != NULL) { 105154716Ssklower /* 105254716Ssklower * We don't bother to fragment if the IP length is greater 105354716Ssklower * than the interface's MTU. Can this possibly matter? 105454716Ssklower */ 105554716Ssklower ip = mtod(copym, struct ip *); 105654716Ssklower ip->ip_len = htons((u_short)ip->ip_len); 105754716Ssklower ip->ip_off = htons((u_short)ip->ip_off); 105854716Ssklower ip->ip_sum = 0; 105954716Ssklower ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); 106054716Ssklower (void) looutput(ifp, copym, (struct sockaddr *)dst); 106154716Ssklower } 106254716Ssklower } 1063