123745Skarels /* 244371Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 544481Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*51273Ssklower * @(#)ip_output.c 7.24 (Berkeley) 10/02/91 823745Skarels */ 94571Swnj 1017061Sbloom #include "param.h" 1137318Skarels #include "malloc.h" 1217061Sbloom #include "mbuf.h" 1317061Sbloom #include "errno.h" 1424814Skarels #include "protosw.h" 1517061Sbloom #include "socket.h" 1617061Sbloom #include "socketvar.h" 1710893Ssam 1810893Ssam #include "../net/if.h" 1910893Ssam #include "../net/route.h" 2010893Ssam 2117061Sbloom #include "in.h" 2240794Ssklower #include "in_systm.h" 2340794Ssklower #include "ip.h" 2424814Skarels #include "in_pcb.h" 2518375Skarels #include "in_var.h" 2617061Sbloom #include "ip_var.h" 274496Swnj 2812460Ssam #ifdef vax 2937502Smckusick #include "machine/mtpr.h" 3012460Ssam #endif 3110893Ssam 3224814Skarels struct mbuf *ip_insertoptions(); 3324814Skarels 3424814Skarels /* 3524814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 3631037Skarels * header (with len, off, ttl, proto, tos, src, dst). 3731037Skarels * The mbuf chain containing the packet will be freed. 3831037Skarels * The mbuf opt, if present, will not be freed. 3924814Skarels */ 4033598Skarels ip_output(m0, opt, ro, flags) 4133598Skarels struct mbuf *m0; 425085Swnj struct mbuf *opt; 436339Ssam struct route *ro; 4412417Ssam int flags; 454496Swnj { 4633598Skarels register struct ip *ip, *mhip; 475085Swnj register struct ifnet *ifp; 4833598Skarels register struct mbuf *m = m0; 4933598Skarels register int hlen = sizeof (struct ip); 5033598Skarels int len, off, error = 0; 516339Ssam struct route iproute; 5216602Ssam struct sockaddr_in *dst; 5340794Ssklower struct in_ifaddr *ia; 544496Swnj 5545014Skarels #ifdef DIAGNOSTIC 5645014Skarels if ((m->m_flags & M_PKTHDR) == 0) 5745014Skarels panic("ip_output no HDR"); 5845014Skarels #endif 5933598Skarels if (opt) { 6033598Skarels m = ip_insertoptions(m, opt, &len); 6133598Skarels hlen = len; 6233598Skarels } 6324814Skarels ip = mtod(m, struct ip *); 644924Swnj /* 654924Swnj * Fill in IP header. 664924Swnj */ 6712417Ssam if ((flags & IP_FORWARDING) == 0) { 6812417Ssam ip->ip_v = IPVERSION; 6912417Ssam ip->ip_off &= IP_DF; 7012417Ssam ip->ip_id = htons(ip_id++); 7116545Skarels ip->ip_hl = hlen >> 2; 7239185Ssklower } else { 7324814Skarels hlen = ip->ip_hl << 2; 7439185Ssklower ipstat.ips_localout++; 7539185Ssklower } 764545Swnj /* 777155Swnj * Route packet. 785085Swnj */ 796339Ssam if (ro == 0) { 806339Ssam ro = &iproute; 816339Ssam bzero((caddr_t)ro, sizeof (*ro)); 825085Swnj } 8316602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 8426156Skarels /* 8526156Skarels * If there is a cached route, 8626156Skarels * check that it is to the same destination 8726156Skarels * and is still up. If not, free it and try again. 8826156Skarels */ 8926156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 9026156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 9126156Skarels RTFREE(ro->ro_rt); 9226156Skarels ro->ro_rt = (struct rtentry *)0; 9326156Skarels } 946339Ssam if (ro->ro_rt == 0) { 9516602Ssam dst->sin_family = AF_INET; 9637318Skarels dst->sin_len = sizeof(*dst); 9716602Ssam dst->sin_addr = ip->ip_dst; 9826058Skarels } 9926058Skarels /* 10026058Skarels * If routing to interface only, 10126058Skarels * short circuit routing lookup. 10226058Skarels */ 10326058Skarels if (flags & IP_ROUTETOIF) { 10427196Skarels 10534500Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); 10627196Skarels if (ia == 0) 10727196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 10826058Skarels if (ia == 0) { 10926058Skarels error = ENETUNREACH; 11026058Skarels goto bad; 11126058Skarels } 11226058Skarels ifp = ia->ia_ifp; 11326058Skarels } else { 11426058Skarels if (ro->ro_rt == 0) 11526058Skarels rtalloc(ro); 11644371Skarels if (ro->ro_rt == 0) { 11744371Skarels error = EHOSTUNREACH; 11826058Skarels goto bad; 11926058Skarels } 12040794Ssklower ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; 12144371Skarels ifp = ro->ro_rt->rt_ifp; 12226058Skarels ro->ro_rt->rt_use++; 12330761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 12437318Skarels dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1256339Ssam } 12623745Skarels #ifndef notdef 1277155Swnj /* 12823745Skarels * If source address not specified yet, use address 12923745Skarels * of outgoing interface. 13023745Skarels */ 13140794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 13240794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 13323745Skarels #endif 13423745Skarels /* 13510402Ssam * Look for broadcast address and 13610402Ssam * and verify user is allowed to send 13710146Ssam * such a packet. 1387155Swnj */ 13918375Skarels if (in_broadcast(dst->sin_addr)) { 14010146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 14110146Ssam error = EADDRNOTAVAIL; 14210146Ssam goto bad; 14310146Ssam } 14412417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 1457155Swnj error = EACCES; 1466339Ssam goto bad; 1476505Ssam } 14810146Ssam /* don't allow broadcast messages to be fragmented */ 14944372Skarels if ((u_short)ip->ip_len > ifp->if_mtu) { 15010146Ssam error = EMSGSIZE; 15110146Ssam goto bad; 15210146Ssam } 15337318Skarels m->m_flags |= M_BCAST; 1546339Ssam } 1556339Ssam 1565085Swnj /* 1574924Swnj * If small enough for interface, can just send directly. 1584545Swnj */ 15944372Skarels if ((u_short)ip->ip_len <= ifp->if_mtu) { 1605085Swnj ip->ip_len = htons((u_short)ip->ip_len); 1615085Swnj ip->ip_off = htons((u_short)ip->ip_off); 1625085Swnj ip->ip_sum = 0; 1635085Swnj ip->ip_sum = in_cksum(m, hlen); 16440794Ssklower error = (*ifp->if_output)(ifp, m, 16540794Ssklower (struct sockaddr *)dst, ro->ro_rt); 1667155Swnj goto done; 1674908Swnj } 16839185Ssklower ipstat.ips_fragmented++; 1694924Swnj /* 1704924Swnj * Too large for interface; fragment if possible. 1714924Swnj * Must be able to put at least 8 bytes per fragment. 1724924Swnj */ 1736505Ssam if (ip->ip_off & IP_DF) { 1746505Ssam error = EMSGSIZE; 1754924Swnj goto bad; 1766505Ssam } 1775085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1786505Ssam if (len < 8) { 1796505Ssam error = EMSGSIZE; 1804924Swnj goto bad; 1816505Ssam } 1824924Swnj 18333744Skarels { 18433744Skarels int mhlen, firstlen = len; 18537318Skarels struct mbuf **mnext = &m->m_nextpkt; 18633744Skarels 1874924Swnj /* 18833744Skarels * Loop through length of segment after first fragment, 18933744Skarels * make new header and copy data of each part and link onto chain. 1904924Swnj */ 19133598Skarels m0 = m; 19233744Skarels mhlen = sizeof (struct ip); 19344372Skarels for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 19437318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 19533598Skarels if (m == 0) { 1966505Ssam error = ENOBUFS; 19734820Skarels goto sendorfree; 1986505Ssam } 19937318Skarels m->m_data += max_linkhdr; 20033598Skarels mhip = mtod(m, struct ip *); 2014924Swnj *mhip = *ip; 2024952Swnj if (hlen > sizeof (struct ip)) { 20333744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 20433598Skarels mhip->ip_hl = mhlen >> 2; 20533744Skarels } 20633598Skarels m->m_len = mhlen; 20733744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 20816545Skarels if (ip->ip_off & IP_MF) 20916545Skarels mhip->ip_off |= IP_MF; 21044372Skarels if (off + len >= (u_short)ip->ip_len) 21144372Skarels len = (u_short)ip->ip_len - off; 21233598Skarels else 2134924Swnj mhip->ip_off |= IP_MF; 21433598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 21533598Skarels m->m_next = m_copy(m0, off, len); 21633598Skarels if (m->m_next == 0) { 2176505Ssam error = ENOBUFS; /* ??? */ 21833744Skarels goto sendorfree; 2194674Swnj } 22037318Skarels m->m_pkthdr.len = mhlen + len; 22137318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 2225892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 2235892Sroot mhip->ip_sum = 0; 22433598Skarels mhip->ip_sum = in_cksum(m, mhlen); 22533744Skarels *mnext = m; 22637318Skarels mnext = &m->m_nextpkt; 22739185Ssklower ipstat.ips_ofragments++; 2284924Swnj } 22933744Skarels /* 23033744Skarels * Update first fragment by trimming what's been copied out 23133744Skarels * and updating header, then send each fragment (in order). 23233744Skarels */ 23340254Smckusick m = m0; 23444372Skarels m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 23537318Skarels m->m_pkthdr.len = hlen + firstlen; 23637318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 23733983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 23833744Skarels ip->ip_sum = 0; 23940254Smckusick ip->ip_sum = in_cksum(m, hlen); 24033744Skarels sendorfree: 24133744Skarels for (m = m0; m; m = m0) { 24237318Skarels m0 = m->m_nextpkt; 24337318Skarels m->m_nextpkt = 0; 24433744Skarels if (error == 0) 24533744Skarels error = (*ifp->if_output)(ifp, m, 24640794Ssklower (struct sockaddr *)dst, ro->ro_rt); 24733744Skarels else 24833744Skarels m_freem(m); 24933744Skarels } 25033744Skarels } 2517155Swnj done: 25212417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 2537155Swnj RTFREE(ro->ro_rt); 2546505Ssam return (error); 25533744Skarels bad: 25633744Skarels m_freem(m0); 25733744Skarels goto done; 2584924Swnj } 2594924Swnj 2604924Swnj /* 26124814Skarels * Insert IP options into preformed packet. 26224814Skarels * Adjust IP destination as required for IP source routing, 26324814Skarels * as indicated by a non-zero in_addr at the start of the options. 26424814Skarels */ 26524814Skarels struct mbuf * 26624814Skarels ip_insertoptions(m, opt, phlen) 26724814Skarels register struct mbuf *m; 26824814Skarels struct mbuf *opt; 26924814Skarels int *phlen; 27024814Skarels { 27124814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 27224814Skarels struct mbuf *n; 27324814Skarels register struct ip *ip = mtod(m, struct ip *); 27426385Skarels unsigned optlen; 27524814Skarels 27624814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 27744372Skarels if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 27844372Skarels return (m); /* XXX should fail */ 27924814Skarels if (p->ipopt_dst.s_addr) 28024814Skarels ip->ip_dst = p->ipopt_dst; 28137318Skarels if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 28237318Skarels MGETHDR(n, M_DONTWAIT, MT_HEADER); 28324814Skarels if (n == 0) 28424814Skarels return (m); 28537318Skarels n->m_pkthdr.len = m->m_pkthdr.len + optlen; 28624814Skarels m->m_len -= sizeof(struct ip); 28737318Skarels m->m_data += sizeof(struct ip); 28824814Skarels n->m_next = m; 28924814Skarels m = n; 29024814Skarels m->m_len = optlen + sizeof(struct ip); 29137318Skarels m->m_data += max_linkhdr; 29224814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 29324814Skarels } else { 29437318Skarels m->m_data -= optlen; 29524814Skarels m->m_len += optlen; 29637318Skarels m->m_pkthdr.len += optlen; 29724814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 29824814Skarels } 29924814Skarels ip = mtod(m, struct ip *); 30026385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 30124814Skarels *phlen = sizeof(struct ip) + optlen; 30224814Skarels ip->ip_len += optlen; 30324814Skarels return (m); 30424814Skarels } 30524814Skarels 30624814Skarels /* 30733744Skarels * Copy options from ip to jp, 30833744Skarels * omitting those not copied during fragmentation. 3094924Swnj */ 31033744Skarels ip_optcopy(ip, jp) 3114924Swnj struct ip *ip, *jp; 3124924Swnj { 3134924Swnj register u_char *cp, *dp; 3144924Swnj int opt, optlen, cnt; 3154924Swnj 3164924Swnj cp = (u_char *)(ip + 1); 3174924Swnj dp = (u_char *)(jp + 1); 3184924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 3194924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 3204924Swnj opt = cp[0]; 3214924Swnj if (opt == IPOPT_EOL) 3224924Swnj break; 3234924Swnj if (opt == IPOPT_NOP) 3244924Swnj optlen = 1; 3254924Swnj else 32624814Skarels optlen = cp[IPOPT_OLEN]; 32733744Skarels /* bogus lengths should have been caught by ip_dooptions */ 32833744Skarels if (optlen > cnt) 32933744Skarels optlen = cnt; 33033744Skarels if (IPOPT_COPIED(opt)) { 3314952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 3324924Swnj dp += optlen; 3334674Swnj } 3344545Swnj } 3354924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 3364924Swnj *dp++ = IPOPT_EOL; 3374924Swnj return (optlen); 3384496Swnj } 33924814Skarels 34024814Skarels /* 34124814Skarels * IP socket option processing. 34224814Skarels */ 34344371Skarels ip_ctloutput(op, so, level, optname, mp) 34424814Skarels int op; 34524814Skarels struct socket *so; 34624814Skarels int level, optname; 34744371Skarels struct mbuf **mp; 34824814Skarels { 34944371Skarels register struct inpcb *inp = sotoinpcb(so); 35044371Skarels register struct mbuf *m = *mp; 35144371Skarels register int optval; 35224814Skarels int error = 0; 35324814Skarels 35424814Skarels if (level != IPPROTO_IP) 355*51273Ssklower goto freeit; 35624814Skarels else switch (op) { 35724814Skarels 35824814Skarels case PRCO_SETOPT: 35924814Skarels switch (optname) { 36024814Skarels case IP_OPTIONS: 36145014Skarels #ifdef notyet 36244371Skarels case IP_RETOPTS: 36344371Skarels return (ip_pcbopts(optname, &inp->inp_options, m)); 36445014Skarels #else 36545014Skarels return (ip_pcbopts(&inp->inp_options, m)); 36645014Skarels #endif 36724814Skarels 36844371Skarels case IP_TOS: 36944371Skarels case IP_TTL: 37044371Skarels case IP_RECVOPTS: 37144371Skarels case IP_RECVRETOPTS: 37244371Skarels case IP_RECVDSTADDR: 37344371Skarels if (m->m_len != sizeof(int)) 37444371Skarels error = EINVAL; 37544371Skarels else { 37644371Skarels optval = *mtod(m, int *); 37745014Skarels switch (optname) { 37844371Skarels 37944371Skarels case IP_TOS: 38044371Skarels inp->inp_ip.ip_tos = optval; 38144371Skarels break; 38244371Skarels 38344371Skarels case IP_TTL: 38445567Ssklower inp->inp_ip.ip_ttl = optval; 38544371Skarels break; 38644371Skarels #define OPTSET(bit) \ 38744371Skarels if (optval) \ 38844371Skarels inp->inp_flags |= bit; \ 38944371Skarels else \ 39044371Skarels inp->inp_flags &= ~bit; 39144371Skarels 39244371Skarels case IP_RECVOPTS: 39344371Skarels OPTSET(INP_RECVOPTS); 39444371Skarels break; 39544371Skarels 39644371Skarels case IP_RECVRETOPTS: 39744371Skarels OPTSET(INP_RECVRETOPTS); 39844371Skarels break; 39944371Skarels 40044371Skarels case IP_RECVDSTADDR: 40144371Skarels OPTSET(INP_RECVDSTADDR); 40244371Skarels break; 40344371Skarels } 40444371Skarels } 40544371Skarels break; 40644371Skarels #undef OPTSET 40744371Skarels 408*51273Ssklower freeit: 40924814Skarels default: 41024814Skarels error = EINVAL; 41124814Skarels break; 41224814Skarels } 41344371Skarels if (m) 41444371Skarels (void)m_free(m); 41524814Skarels break; 41624814Skarels 41724814Skarels case PRCO_GETOPT: 41824814Skarels switch (optname) { 41924814Skarels case IP_OPTIONS: 42045014Skarels case IP_RETOPTS: 42144371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 42224814Skarels if (inp->inp_options) { 42344371Skarels m->m_len = inp->inp_options->m_len; 42424814Skarels bcopy(mtod(inp->inp_options, caddr_t), 42544371Skarels mtod(m, caddr_t), (unsigned)m->m_len); 42624814Skarels } else 42744371Skarels m->m_len = 0; 42824814Skarels break; 42944371Skarels 43044371Skarels case IP_TOS: 43144371Skarels case IP_TTL: 43244371Skarels case IP_RECVOPTS: 43344371Skarels case IP_RECVRETOPTS: 43444371Skarels case IP_RECVDSTADDR: 43544371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 43644371Skarels m->m_len = sizeof(int); 43745014Skarels switch (optname) { 43844371Skarels 43944371Skarels case IP_TOS: 44044371Skarels optval = inp->inp_ip.ip_tos; 44144371Skarels break; 44244371Skarels 44344371Skarels case IP_TTL: 44445567Ssklower optval = inp->inp_ip.ip_ttl; 44544371Skarels break; 44644371Skarels 44744371Skarels #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 44844371Skarels 44944371Skarels case IP_RECVOPTS: 45044371Skarels optval = OPTBIT(INP_RECVOPTS); 45144371Skarels break; 45244371Skarels 45344371Skarels case IP_RECVRETOPTS: 45444371Skarels optval = OPTBIT(INP_RECVRETOPTS); 45544371Skarels break; 45644371Skarels 45744371Skarels case IP_RECVDSTADDR: 45844371Skarels optval = OPTBIT(INP_RECVDSTADDR); 45944371Skarels break; 46044371Skarels } 46144371Skarels *mtod(m, int *) = optval; 46244371Skarels break; 46344371Skarels 46424814Skarels default: 46524814Skarels error = EINVAL; 46624814Skarels break; 46724814Skarels } 46824814Skarels break; 46924814Skarels } 47024814Skarels return (error); 47124814Skarels } 47224814Skarels 47324814Skarels /* 47426036Skarels * Set up IP options in pcb for insertion in output packets. 47526036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 47626036Skarels * with destination address if source routed. 47724814Skarels */ 47845014Skarels #ifdef notyet 47945014Skarels ip_pcbopts(optname, pcbopt, m) 48045014Skarels int optname; 48145014Skarels #else 48226036Skarels ip_pcbopts(pcbopt, m) 48345014Skarels #endif 48426036Skarels struct mbuf **pcbopt; 48526036Skarels register struct mbuf *m; 48624814Skarels { 48724814Skarels register cnt, optlen; 48824814Skarels register u_char *cp; 48924814Skarels u_char opt; 49024814Skarels 49124814Skarels /* turn off any old options */ 49226036Skarels if (*pcbopt) 49326385Skarels (void)m_free(*pcbopt); 49426036Skarels *pcbopt = 0; 49524814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 49624814Skarels /* 49724814Skarels * Only turning off any previous options. 49824814Skarels */ 49924814Skarels if (m) 50026385Skarels (void)m_free(m); 50124814Skarels return (0); 50224814Skarels } 50324814Skarels 50424814Skarels #ifndef vax 50524814Skarels if (m->m_len % sizeof(long)) 50624814Skarels goto bad; 50724814Skarels #endif 50824814Skarels /* 50924814Skarels * IP first-hop destination address will be stored before 51024814Skarels * actual options; move other options back 51124814Skarels * and clear it when none present. 51224814Skarels */ 51337318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 51424814Skarels goto bad; 51524814Skarels cnt = m->m_len; 51624814Skarels m->m_len += sizeof(struct in_addr); 51724814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 51826385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 51924814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 52024814Skarels 52124814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 52224814Skarels opt = cp[IPOPT_OPTVAL]; 52324814Skarels if (opt == IPOPT_EOL) 52424814Skarels break; 52524814Skarels if (opt == IPOPT_NOP) 52624814Skarels optlen = 1; 52724814Skarels else { 52824814Skarels optlen = cp[IPOPT_OLEN]; 52924814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 53024814Skarels goto bad; 53124814Skarels } 53224814Skarels switch (opt) { 53324814Skarels 53424814Skarels default: 53524814Skarels break; 53624814Skarels 53724814Skarels case IPOPT_LSRR: 53824814Skarels case IPOPT_SSRR: 53924814Skarels /* 54024814Skarels * user process specifies route as: 54124814Skarels * ->A->B->C->D 54224814Skarels * D must be our final destination (but we can't 54324814Skarels * check that since we may not have connected yet). 54424814Skarels * A is first hop destination, which doesn't appear in 54524814Skarels * actual IP option, but is stored before the options. 54624814Skarels */ 54724814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 54824814Skarels goto bad; 54924814Skarels m->m_len -= sizeof(struct in_addr); 55024814Skarels cnt -= sizeof(struct in_addr); 55124814Skarels optlen -= sizeof(struct in_addr); 55224814Skarels cp[IPOPT_OLEN] = optlen; 55324814Skarels /* 55424814Skarels * Move first hop before start of options. 55524814Skarels */ 55626385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 55724814Skarels sizeof(struct in_addr)); 55824814Skarels /* 55924814Skarels * Then copy rest of options back 56024814Skarels * to close up the deleted entry. 56124814Skarels */ 56226385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 56326385Skarels sizeof(struct in_addr)), 56426385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 56526385Skarels (unsigned)cnt + sizeof(struct in_addr)); 56624814Skarels break; 56724814Skarels } 56824814Skarels } 56937318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 57037318Skarels goto bad; 57126036Skarels *pcbopt = m; 57224814Skarels return (0); 57324814Skarels 57424814Skarels bad: 57526385Skarels (void)m_free(m); 57624814Skarels return (EINVAL); 57724814Skarels } 578