123745Skarels /* 244371Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 532787Sbostic * Redistribution and use in source and binary forms are permitted 634854Sbostic * provided that the above copyright notice and this paragraph are 734854Sbostic * duplicated in all such forms and that any documentation, 834854Sbostic * advertising materials, and other materials related to such 934854Sbostic * distribution and use acknowledge that the software was developed 1034854Sbostic * by the University of California, Berkeley. The name of the 1134854Sbostic * University may not be used to endorse or promote products derived 1234854Sbostic * from this software without specific prior written permission. 1334854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*44372Skarels * @(#)ip_output.c 7.20 (Berkeley) 06/28/90 1823745Skarels */ 194571Swnj 2017061Sbloom #include "param.h" 2137318Skarels #include "malloc.h" 2217061Sbloom #include "mbuf.h" 2317061Sbloom #include "errno.h" 2424814Skarels #include "protosw.h" 2517061Sbloom #include "socket.h" 2617061Sbloom #include "socketvar.h" 2710893Ssam 2810893Ssam #include "../net/if.h" 2910893Ssam #include "../net/route.h" 3010893Ssam 3117061Sbloom #include "in.h" 3240794Ssklower #include "in_systm.h" 3340794Ssklower #include "ip.h" 3424814Skarels #include "in_pcb.h" 3518375Skarels #include "in_var.h" 3617061Sbloom #include "ip_var.h" 374496Swnj 3812460Ssam #ifdef vax 3937502Smckusick #include "machine/mtpr.h" 4012460Ssam #endif 4110893Ssam 4224814Skarels struct mbuf *ip_insertoptions(); 4324814Skarels 4424814Skarels /* 4524814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 4631037Skarels * header (with len, off, ttl, proto, tos, src, dst). 4731037Skarels * The mbuf chain containing the packet will be freed. 4831037Skarels * The mbuf opt, if present, will not be freed. 4924814Skarels */ 5033598Skarels ip_output(m0, opt, ro, flags) 5133598Skarels struct mbuf *m0; 525085Swnj struct mbuf *opt; 536339Ssam struct route *ro; 5412417Ssam int flags; 554496Swnj { 5633598Skarels register struct ip *ip, *mhip; 575085Swnj register struct ifnet *ifp; 5833598Skarels register struct mbuf *m = m0; 5933598Skarels register int hlen = sizeof (struct ip); 6033598Skarels int len, off, error = 0; 616339Ssam struct route iproute; 6216602Ssam struct sockaddr_in *dst; 6340794Ssklower struct in_ifaddr *ia; 644496Swnj 6537318Skarels if ((m->m_flags & M_PKTHDR) == 0) 6637318Skarels panic("ip_output no HDR"); 6733598Skarels if (opt) { 6833598Skarels m = ip_insertoptions(m, opt, &len); 6933598Skarels hlen = len; 7033598Skarels } 7124814Skarels ip = mtod(m, struct ip *); 724924Swnj /* 734924Swnj * Fill in IP header. 744924Swnj */ 7512417Ssam if ((flags & IP_FORWARDING) == 0) { 7612417Ssam ip->ip_v = IPVERSION; 7712417Ssam ip->ip_off &= IP_DF; 7812417Ssam ip->ip_id = htons(ip_id++); 7916545Skarels ip->ip_hl = hlen >> 2; 8039185Ssklower } else { 8124814Skarels hlen = ip->ip_hl << 2; 8239185Ssklower ipstat.ips_localout++; 8339185Ssklower } 844545Swnj /* 857155Swnj * Route packet. 865085Swnj */ 876339Ssam if (ro == 0) { 886339Ssam ro = &iproute; 896339Ssam bzero((caddr_t)ro, sizeof (*ro)); 905085Swnj } 9116602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 9226156Skarels /* 9326156Skarels * If there is a cached route, 9426156Skarels * check that it is to the same destination 9526156Skarels * and is still up. If not, free it and try again. 9626156Skarels */ 9726156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 9826156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 9926156Skarels RTFREE(ro->ro_rt); 10026156Skarels ro->ro_rt = (struct rtentry *)0; 10126156Skarels } 1026339Ssam if (ro->ro_rt == 0) { 10316602Ssam dst->sin_family = AF_INET; 10437318Skarels dst->sin_len = sizeof(*dst); 10516602Ssam dst->sin_addr = ip->ip_dst; 10626058Skarels } 10726058Skarels /* 10826058Skarels * If routing to interface only, 10926058Skarels * short circuit routing lookup. 11026058Skarels */ 11126058Skarels if (flags & IP_ROUTETOIF) { 11227196Skarels 11334500Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); 11427196Skarels if (ia == 0) 11527196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 11626058Skarels if (ia == 0) { 11726058Skarels error = ENETUNREACH; 11826058Skarels goto bad; 11926058Skarels } 12026058Skarels ifp = ia->ia_ifp; 12126058Skarels } else { 12226058Skarels if (ro->ro_rt == 0) 12326058Skarels rtalloc(ro); 12444371Skarels if (ro->ro_rt == 0) { 12544371Skarels error = EHOSTUNREACH; 12626058Skarels goto bad; 12726058Skarels } 12840794Ssklower ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; 12944371Skarels ifp = ro->ro_rt->rt_ifp; 13026058Skarels ro->ro_rt->rt_use++; 13130761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 13237318Skarels dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1336339Ssam } 13423745Skarels #ifndef notdef 1357155Swnj /* 13623745Skarels * If source address not specified yet, use address 13723745Skarels * of outgoing interface. 13823745Skarels */ 13940794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 14040794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 14123745Skarels #endif 14223745Skarels /* 14310402Ssam * Look for broadcast address and 14410402Ssam * and verify user is allowed to send 14510146Ssam * such a packet. 1467155Swnj */ 14718375Skarels if (in_broadcast(dst->sin_addr)) { 14810146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 14910146Ssam error = EADDRNOTAVAIL; 15010146Ssam goto bad; 15110146Ssam } 15212417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 1537155Swnj error = EACCES; 1546339Ssam goto bad; 1556505Ssam } 15610146Ssam /* don't allow broadcast messages to be fragmented */ 157*44372Skarels if ((u_short)ip->ip_len > ifp->if_mtu) { 15810146Ssam error = EMSGSIZE; 15910146Ssam goto bad; 16010146Ssam } 16137318Skarels m->m_flags |= M_BCAST; 1626339Ssam } 1636339Ssam 1645085Swnj /* 1654924Swnj * If small enough for interface, can just send directly. 1664545Swnj */ 167*44372Skarels if ((u_short)ip->ip_len <= ifp->if_mtu) { 1685085Swnj ip->ip_len = htons((u_short)ip->ip_len); 1695085Swnj ip->ip_off = htons((u_short)ip->ip_off); 1705085Swnj ip->ip_sum = 0; 1715085Swnj ip->ip_sum = in_cksum(m, hlen); 17240794Ssklower error = (*ifp->if_output)(ifp, m, 17340794Ssklower (struct sockaddr *)dst, ro->ro_rt); 1747155Swnj goto done; 1754908Swnj } 17639185Ssklower ipstat.ips_fragmented++; 1774924Swnj /* 1784924Swnj * Too large for interface; fragment if possible. 1794924Swnj * Must be able to put at least 8 bytes per fragment. 1804924Swnj */ 1816505Ssam if (ip->ip_off & IP_DF) { 1826505Ssam error = EMSGSIZE; 1834924Swnj goto bad; 1846505Ssam } 1855085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1866505Ssam if (len < 8) { 1876505Ssam error = EMSGSIZE; 1884924Swnj goto bad; 1896505Ssam } 1904924Swnj 19133744Skarels { 19233744Skarels int mhlen, firstlen = len; 19337318Skarels struct mbuf **mnext = &m->m_nextpkt; 19433744Skarels 1954924Swnj /* 19633744Skarels * Loop through length of segment after first fragment, 19733744Skarels * make new header and copy data of each part and link onto chain. 1984924Swnj */ 19933598Skarels m0 = m; 20033744Skarels mhlen = sizeof (struct ip); 201*44372Skarels for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { 20237318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 20333598Skarels if (m == 0) { 2046505Ssam error = ENOBUFS; 20534820Skarels goto sendorfree; 2066505Ssam } 20737318Skarels m->m_data += max_linkhdr; 20833598Skarels mhip = mtod(m, struct ip *); 2094924Swnj *mhip = *ip; 2104952Swnj if (hlen > sizeof (struct ip)) { 21133744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 21233598Skarels mhip->ip_hl = mhlen >> 2; 21333744Skarels } 21433598Skarels m->m_len = mhlen; 21533744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 21616545Skarels if (ip->ip_off & IP_MF) 21716545Skarels mhip->ip_off |= IP_MF; 218*44372Skarels if (off + len >= (u_short)ip->ip_len) 219*44372Skarels len = (u_short)ip->ip_len - off; 22033598Skarels else 2214924Swnj mhip->ip_off |= IP_MF; 22233598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 22333598Skarels m->m_next = m_copy(m0, off, len); 22433598Skarels if (m->m_next == 0) { 2256505Ssam error = ENOBUFS; /* ??? */ 22633744Skarels goto sendorfree; 2274674Swnj } 22837318Skarels m->m_pkthdr.len = mhlen + len; 22937318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 2305892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 2315892Sroot mhip->ip_sum = 0; 23233598Skarels mhip->ip_sum = in_cksum(m, mhlen); 23333744Skarels *mnext = m; 23437318Skarels mnext = &m->m_nextpkt; 23539185Ssklower ipstat.ips_ofragments++; 2364924Swnj } 23733744Skarels /* 23833744Skarels * Update first fragment by trimming what's been copied out 23933744Skarels * and updating header, then send each fragment (in order). 24033744Skarels */ 24140254Smckusick m = m0; 242*44372Skarels m_adj(m, hlen + firstlen - (u_short)ip->ip_len); 24337318Skarels m->m_pkthdr.len = hlen + firstlen; 24437318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 24533983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 24633744Skarels ip->ip_sum = 0; 24740254Smckusick ip->ip_sum = in_cksum(m, hlen); 24833744Skarels sendorfree: 24933744Skarels for (m = m0; m; m = m0) { 25037318Skarels m0 = m->m_nextpkt; 25137318Skarels m->m_nextpkt = 0; 25233744Skarels if (error == 0) 25333744Skarels error = (*ifp->if_output)(ifp, m, 25440794Ssklower (struct sockaddr *)dst, ro->ro_rt); 25533744Skarels else 25633744Skarels m_freem(m); 25733744Skarels } 25833744Skarels } 2597155Swnj done: 26012417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 2617155Swnj RTFREE(ro->ro_rt); 2626505Ssam return (error); 26333744Skarels bad: 26433744Skarels m_freem(m0); 26533744Skarels goto done; 2664924Swnj } 2674924Swnj 2684924Swnj /* 26924814Skarels * Insert IP options into preformed packet. 27024814Skarels * Adjust IP destination as required for IP source routing, 27124814Skarels * as indicated by a non-zero in_addr at the start of the options. 27224814Skarels */ 27324814Skarels struct mbuf * 27424814Skarels ip_insertoptions(m, opt, phlen) 27524814Skarels register struct mbuf *m; 27624814Skarels struct mbuf *opt; 27724814Skarels int *phlen; 27824814Skarels { 27924814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 28024814Skarels struct mbuf *n; 28124814Skarels register struct ip *ip = mtod(m, struct ip *); 28226385Skarels unsigned optlen; 28324814Skarels 28424814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 285*44372Skarels if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) 286*44372Skarels return (m); /* XXX should fail */ 28724814Skarels if (p->ipopt_dst.s_addr) 28824814Skarels ip->ip_dst = p->ipopt_dst; 28937318Skarels if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 29037318Skarels MGETHDR(n, M_DONTWAIT, MT_HEADER); 29124814Skarels if (n == 0) 29224814Skarels return (m); 29337318Skarels n->m_pkthdr.len = m->m_pkthdr.len + optlen; 29424814Skarels m->m_len -= sizeof(struct ip); 29537318Skarels m->m_data += sizeof(struct ip); 29624814Skarels n->m_next = m; 29724814Skarels m = n; 29824814Skarels m->m_len = optlen + sizeof(struct ip); 29937318Skarels m->m_data += max_linkhdr; 30024814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 30124814Skarels } else { 30237318Skarels m->m_data -= optlen; 30324814Skarels m->m_len += optlen; 30437318Skarels m->m_pkthdr.len += optlen; 30524814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 30624814Skarels } 30724814Skarels ip = mtod(m, struct ip *); 30826385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 30924814Skarels *phlen = sizeof(struct ip) + optlen; 31024814Skarels ip->ip_len += optlen; 31124814Skarels return (m); 31224814Skarels } 31324814Skarels 31424814Skarels /* 31533744Skarels * Copy options from ip to jp, 31633744Skarels * omitting those not copied during fragmentation. 3174924Swnj */ 31833744Skarels ip_optcopy(ip, jp) 3194924Swnj struct ip *ip, *jp; 3204924Swnj { 3214924Swnj register u_char *cp, *dp; 3224924Swnj int opt, optlen, cnt; 3234924Swnj 3244924Swnj cp = (u_char *)(ip + 1); 3254924Swnj dp = (u_char *)(jp + 1); 3264924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 3274924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 3284924Swnj opt = cp[0]; 3294924Swnj if (opt == IPOPT_EOL) 3304924Swnj break; 3314924Swnj if (opt == IPOPT_NOP) 3324924Swnj optlen = 1; 3334924Swnj else 33424814Skarels optlen = cp[IPOPT_OLEN]; 33533744Skarels /* bogus lengths should have been caught by ip_dooptions */ 33633744Skarels if (optlen > cnt) 33733744Skarels optlen = cnt; 33833744Skarels if (IPOPT_COPIED(opt)) { 3394952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 3404924Swnj dp += optlen; 3414674Swnj } 3424545Swnj } 3434924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 3444924Swnj *dp++ = IPOPT_EOL; 3454924Swnj return (optlen); 3464496Swnj } 34724814Skarels 34824814Skarels /* 34924814Skarels * IP socket option processing. 35024814Skarels */ 35144371Skarels ip_ctloutput(op, so, level, optname, mp) 35224814Skarels int op; 35324814Skarels struct socket *so; 35424814Skarels int level, optname; 35544371Skarels struct mbuf **mp; 35624814Skarels { 35744371Skarels register struct inpcb *inp = sotoinpcb(so); 35844371Skarels register struct mbuf *m = *mp; 35944371Skarels register int optval; 36024814Skarels int error = 0; 36124814Skarels 36224814Skarels if (level != IPPROTO_IP) 36324814Skarels error = EINVAL; 36424814Skarels else switch (op) { 36524814Skarels 36624814Skarels case PRCO_SETOPT: 36724814Skarels switch (optname) { 36824814Skarels case IP_OPTIONS: 36944371Skarels case IP_RETOPTS: 37044371Skarels return (ip_pcbopts(optname, &inp->inp_options, m)); 37124814Skarels 37244371Skarels case IP_TOS: 37344371Skarels case IP_TTL: 37444371Skarels case IP_RECVOPTS: 37544371Skarels case IP_RECVRETOPTS: 37644371Skarels case IP_RECVDSTADDR: 37744371Skarels if (m->m_len != sizeof(int)) 37844371Skarels error = EINVAL; 37944371Skarels else { 38044371Skarels optval = *mtod(m, int *); 38144371Skarels switch (op) { 38244371Skarels 38344371Skarels case IP_TOS: 38444371Skarels inp->inp_ip.ip_tos = optval; 38544371Skarels break; 38644371Skarels 38744371Skarels case IP_TTL: 38844371Skarels inp->inp_ip.ip_tos = optval; 38944371Skarels break; 39044371Skarels #define OPTSET(bit) \ 39144371Skarels if (optval) \ 39244371Skarels inp->inp_flags |= bit; \ 39344371Skarels else \ 39444371Skarels inp->inp_flags &= ~bit; 39544371Skarels 39644371Skarels case IP_RECVOPTS: 39744371Skarels OPTSET(INP_RECVOPTS); 39844371Skarels break; 39944371Skarels 40044371Skarels case IP_RECVRETOPTS: 40144371Skarels OPTSET(INP_RECVRETOPTS); 40244371Skarels break; 40344371Skarels 40444371Skarels case IP_RECVDSTADDR: 40544371Skarels OPTSET(INP_RECVDSTADDR); 40644371Skarels break; 40744371Skarels } 40844371Skarels } 40944371Skarels break; 41044371Skarels #undef OPTSET 41144371Skarels 41224814Skarels default: 41324814Skarels error = EINVAL; 41424814Skarels break; 41524814Skarels } 41644371Skarels if (m) 41744371Skarels (void)m_free(m); 41824814Skarels break; 41924814Skarels 42024814Skarels case PRCO_GETOPT: 42124814Skarels switch (optname) { 42224814Skarels case IP_OPTIONS: 42344371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 42424814Skarels if (inp->inp_options) { 42544371Skarels m->m_len = inp->inp_options->m_len; 42624814Skarels bcopy(mtod(inp->inp_options, caddr_t), 42744371Skarels mtod(m, caddr_t), (unsigned)m->m_len); 42824814Skarels } else 42944371Skarels m->m_len = 0; 43024814Skarels break; 43144371Skarels 43244371Skarels case IP_TOS: 43344371Skarels case IP_TTL: 43444371Skarels case IP_RECVOPTS: 43544371Skarels case IP_RECVRETOPTS: 43644371Skarels case IP_RECVDSTADDR: 43744371Skarels *mp = m = m_get(M_WAIT, MT_SOOPTS); 43844371Skarels m->m_len = sizeof(int); 43944371Skarels switch (op) { 44044371Skarels 44144371Skarels case IP_TOS: 44244371Skarels optval = inp->inp_ip.ip_tos; 44344371Skarels break; 44444371Skarels 44544371Skarels case IP_TTL: 44644371Skarels optval = inp->inp_ip.ip_tos; 44744371Skarels break; 44844371Skarels 44944371Skarels #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) 45044371Skarels 45144371Skarels case IP_RECVOPTS: 45244371Skarels optval = OPTBIT(INP_RECVOPTS); 45344371Skarels break; 45444371Skarels 45544371Skarels case IP_RECVRETOPTS: 45644371Skarels optval = OPTBIT(INP_RECVRETOPTS); 45744371Skarels break; 45844371Skarels 45944371Skarels case IP_RECVDSTADDR: 46044371Skarels optval = OPTBIT(INP_RECVDSTADDR); 46144371Skarels break; 46244371Skarels } 46344371Skarels *mtod(m, int *) = optval; 46444371Skarels break; 46544371Skarels 46624814Skarels default: 46724814Skarels error = EINVAL; 46824814Skarels break; 46924814Skarels } 47024814Skarels break; 47124814Skarels } 47224814Skarels return (error); 47324814Skarels } 47424814Skarels 47524814Skarels /* 47626036Skarels * Set up IP options in pcb for insertion in output packets. 47726036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 47826036Skarels * with destination address if source routed. 47924814Skarels */ 48026036Skarels ip_pcbopts(pcbopt, m) 48126036Skarels struct mbuf **pcbopt; 48226036Skarels register struct mbuf *m; 48324814Skarels { 48424814Skarels register cnt, optlen; 48524814Skarels register u_char *cp; 48624814Skarels u_char opt; 48724814Skarels 48824814Skarels /* turn off any old options */ 48926036Skarels if (*pcbopt) 49026385Skarels (void)m_free(*pcbopt); 49126036Skarels *pcbopt = 0; 49224814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 49324814Skarels /* 49424814Skarels * Only turning off any previous options. 49524814Skarels */ 49624814Skarels if (m) 49726385Skarels (void)m_free(m); 49824814Skarels return (0); 49924814Skarels } 50024814Skarels 50124814Skarels #ifndef vax 50224814Skarels if (m->m_len % sizeof(long)) 50324814Skarels goto bad; 50424814Skarels #endif 50524814Skarels /* 50624814Skarels * IP first-hop destination address will be stored before 50724814Skarels * actual options; move other options back 50824814Skarels * and clear it when none present. 50924814Skarels */ 51037318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 51124814Skarels goto bad; 51224814Skarels cnt = m->m_len; 51324814Skarels m->m_len += sizeof(struct in_addr); 51424814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 51526385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 51624814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 51724814Skarels 51824814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 51924814Skarels opt = cp[IPOPT_OPTVAL]; 52024814Skarels if (opt == IPOPT_EOL) 52124814Skarels break; 52224814Skarels if (opt == IPOPT_NOP) 52324814Skarels optlen = 1; 52424814Skarels else { 52524814Skarels optlen = cp[IPOPT_OLEN]; 52624814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 52724814Skarels goto bad; 52824814Skarels } 52924814Skarels switch (opt) { 53024814Skarels 53124814Skarels default: 53224814Skarels break; 53324814Skarels 53424814Skarels case IPOPT_LSRR: 53524814Skarels case IPOPT_SSRR: 53624814Skarels /* 53724814Skarels * user process specifies route as: 53824814Skarels * ->A->B->C->D 53924814Skarels * D must be our final destination (but we can't 54024814Skarels * check that since we may not have connected yet). 54124814Skarels * A is first hop destination, which doesn't appear in 54224814Skarels * actual IP option, but is stored before the options. 54324814Skarels */ 54424814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 54524814Skarels goto bad; 54624814Skarels m->m_len -= sizeof(struct in_addr); 54724814Skarels cnt -= sizeof(struct in_addr); 54824814Skarels optlen -= sizeof(struct in_addr); 54924814Skarels cp[IPOPT_OLEN] = optlen; 55024814Skarels /* 55124814Skarels * Move first hop before start of options. 55224814Skarels */ 55326385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 55424814Skarels sizeof(struct in_addr)); 55524814Skarels /* 55624814Skarels * Then copy rest of options back 55724814Skarels * to close up the deleted entry. 55824814Skarels */ 55926385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 56026385Skarels sizeof(struct in_addr)), 56126385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 56226385Skarels (unsigned)cnt + sizeof(struct in_addr)); 56324814Skarels break; 56424814Skarels } 56524814Skarels } 56637318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 56737318Skarels goto bad; 56826036Skarels *pcbopt = m; 56924814Skarels return (0); 57024814Skarels 57124814Skarels bad: 57226385Skarels (void)m_free(m); 57324814Skarels return (EINVAL); 57424814Skarels } 575