123745Skarels /* 229144Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 532787Sbostic * Redistribution and use in source and binary forms are permitted 632787Sbostic * provided that this notice is preserved and that due credit is given 732787Sbostic * to the University of California at Berkeley. The name of the University 832787Sbostic * may not be used to endorse or promote products derived from this 932787Sbostic * software without specific prior written permission. This software 1032787Sbostic * is provided ``as is'' without express or implied warranty. 1132787Sbostic * 12*33983Skarels * @(#)ip_output.c 7.10 (Berkeley) 04/07/88 1323745Skarels */ 144571Swnj 1517061Sbloom #include "param.h" 1617061Sbloom #include "mbuf.h" 1717061Sbloom #include "errno.h" 1824814Skarels #include "protosw.h" 1917061Sbloom #include "socket.h" 2017061Sbloom #include "socketvar.h" 2110893Ssam 2210893Ssam #include "../net/if.h" 2310893Ssam #include "../net/route.h" 2410893Ssam 2517061Sbloom #include "in.h" 2624814Skarels #include "in_pcb.h" 2717061Sbloom #include "in_systm.h" 2818375Skarels #include "in_var.h" 2917061Sbloom #include "ip.h" 3017061Sbloom #include "ip_var.h" 314496Swnj 3212460Ssam #ifdef vax 3329923Skarels #include "../machine/mtpr.h" 3412460Ssam #endif 3510893Ssam 3624814Skarels struct mbuf *ip_insertoptions(); 3724814Skarels 3824814Skarels /* 3924814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 4031037Skarels * header (with len, off, ttl, proto, tos, src, dst). 4131037Skarels * The mbuf chain containing the packet will be freed. 4231037Skarels * The mbuf opt, if present, will not be freed. 4324814Skarels */ 4433598Skarels ip_output(m0, opt, ro, flags) 4533598Skarels struct mbuf *m0; 465085Swnj struct mbuf *opt; 476339Ssam struct route *ro; 4812417Ssam int flags; 494496Swnj { 5033598Skarels register struct ip *ip, *mhip; 515085Swnj register struct ifnet *ifp; 5233598Skarels register struct mbuf *m = m0; 5333598Skarels register int hlen = sizeof (struct ip); 5433598Skarels int len, off, error = 0; 556339Ssam struct route iproute; 5616602Ssam struct sockaddr_in *dst; 574496Swnj 5833598Skarels if (opt) { 5933598Skarels m = ip_insertoptions(m, opt, &len); 6033598Skarels hlen = len; 6133598Skarels } 6224814Skarels ip = mtod(m, struct ip *); 634924Swnj /* 644924Swnj * Fill in IP header. 654924Swnj */ 6612417Ssam if ((flags & IP_FORWARDING) == 0) { 6712417Ssam ip->ip_v = IPVERSION; 6812417Ssam ip->ip_off &= IP_DF; 6912417Ssam ip->ip_id = htons(ip_id++); 7016545Skarels ip->ip_hl = hlen >> 2; 7124814Skarels } else 7224814Skarels hlen = ip->ip_hl << 2; 734496Swnj 744545Swnj /* 757155Swnj * Route packet. 765085Swnj */ 776339Ssam if (ro == 0) { 786339Ssam ro = &iproute; 796339Ssam bzero((caddr_t)ro, sizeof (*ro)); 805085Swnj } 8116602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 8226156Skarels /* 8326156Skarels * If there is a cached route, 8426156Skarels * check that it is to the same destination 8526156Skarels * and is still up. If not, free it and try again. 8626156Skarels */ 8726156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 8826156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 8926156Skarels RTFREE(ro->ro_rt); 9026156Skarels ro->ro_rt = (struct rtentry *)0; 9126156Skarels } 926339Ssam if (ro->ro_rt == 0) { 9316602Ssam dst->sin_family = AF_INET; 9416602Ssam dst->sin_addr = ip->ip_dst; 9526058Skarels } 9626058Skarels /* 9726058Skarels * If routing to interface only, 9826058Skarels * short circuit routing lookup. 9926058Skarels */ 10026058Skarels if (flags & IP_ROUTETOIF) { 10126058Skarels struct in_ifaddr *ia; 10227196Skarels 10327973Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst); 10427196Skarels if (ia == 0) 10527196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 10626058Skarels if (ia == 0) { 10726058Skarels error = ENETUNREACH; 10826058Skarels goto bad; 10926058Skarels } 11026058Skarels ifp = ia->ia_ifp; 11126058Skarels } else { 11226058Skarels if (ro->ro_rt == 0) 11326058Skarels rtalloc(ro); 11426058Skarels if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 11531200Skarels if (in_localaddr(ip->ip_dst)) 11631200Skarels error = EHOSTUNREACH; 11731200Skarels else 11831200Skarels error = ENETUNREACH; 11926058Skarels goto bad; 12026058Skarels } 12126058Skarels ro->ro_rt->rt_use++; 12230761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 12326058Skarels dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; 1246339Ssam } 12523745Skarels #ifndef notdef 1267155Swnj /* 12723745Skarels * If source address not specified yet, use address 12823745Skarels * of outgoing interface. 12923745Skarels */ 13023745Skarels if (ip->ip_src.s_addr == INADDR_ANY) { 13123745Skarels register struct in_ifaddr *ia; 13223745Skarels 13323745Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 13423745Skarels if (ia->ia_ifp == ifp) { 13523745Skarels ip->ip_src = IA_SIN(ia)->sin_addr; 13623745Skarels break; 13723745Skarels } 13823745Skarels } 13923745Skarels #endif 14023745Skarels /* 14110402Ssam * Look for broadcast address and 14210402Ssam * and verify user is allowed to send 14310146Ssam * such a packet. 1447155Swnj */ 14518375Skarels if (in_broadcast(dst->sin_addr)) { 14610146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 14710146Ssam error = EADDRNOTAVAIL; 14810146Ssam goto bad; 14910146Ssam } 15012417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 1517155Swnj error = EACCES; 1526339Ssam goto bad; 1536505Ssam } 15410146Ssam /* don't allow broadcast messages to be fragmented */ 15510146Ssam if (ip->ip_len > ifp->if_mtu) { 15610146Ssam error = EMSGSIZE; 15710146Ssam goto bad; 15810146Ssam } 1596339Ssam } 1606339Ssam 1615085Swnj /* 1624924Swnj * If small enough for interface, can just send directly. 1634545Swnj */ 1645085Swnj if (ip->ip_len <= ifp->if_mtu) { 1655085Swnj ip->ip_len = htons((u_short)ip->ip_len); 1665085Swnj ip->ip_off = htons((u_short)ip->ip_off); 1675085Swnj ip->ip_sum = 0; 1685085Swnj ip->ip_sum = in_cksum(m, hlen); 16916602Ssam error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); 1707155Swnj goto done; 1714908Swnj } 1724924Swnj 1734924Swnj /* 1744924Swnj * Too large for interface; fragment if possible. 1754924Swnj * Must be able to put at least 8 bytes per fragment. 1764924Swnj */ 1776505Ssam if (ip->ip_off & IP_DF) { 1786505Ssam error = EMSGSIZE; 1794924Swnj goto bad; 1806505Ssam } 1815085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1826505Ssam if (len < 8) { 1836505Ssam error = EMSGSIZE; 1844924Swnj goto bad; 1856505Ssam } 1864924Swnj 18733744Skarels { 18833744Skarels int mhlen, firstlen = len; 18933744Skarels struct mbuf **mnext = &m->m_act; 19033744Skarels 1914924Swnj /* 19233744Skarels * Loop through length of segment after first fragment, 19333744Skarels * make new header and copy data of each part and link onto chain. 1944924Swnj */ 19533598Skarels m0 = m; 19633744Skarels mhlen = sizeof (struct ip); 19733744Skarels for (off = hlen + len; off < ip->ip_len; off += len) { 19833598Skarels MGET(m, M_DONTWAIT, MT_HEADER); 19933598Skarels if (m == 0) { 2006505Ssam error = ENOBUFS; 2014924Swnj goto bad; 2026505Ssam } 20333598Skarels m->m_off = MMAXOFF - hlen; 20433598Skarels mhip = mtod(m, struct ip *); 2054924Swnj *mhip = *ip; 2064952Swnj if (hlen > sizeof (struct ip)) { 20733744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 20833598Skarels mhip->ip_hl = mhlen >> 2; 20933744Skarels } 21033598Skarels m->m_len = mhlen; 21133744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 21216545Skarels if (ip->ip_off & IP_MF) 21316545Skarels mhip->ip_off |= IP_MF; 21433744Skarels if (off + len >= ip->ip_len) 21533744Skarels len = ip->ip_len - off; 21633598Skarels else 2174924Swnj mhip->ip_off |= IP_MF; 21833598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 21933598Skarels m->m_next = m_copy(m0, off, len); 22033598Skarels if (m->m_next == 0) { 2216505Ssam error = ENOBUFS; /* ??? */ 22233744Skarels goto sendorfree; 2234674Swnj } 2245892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 2255892Sroot mhip->ip_sum = 0; 22633598Skarels mhip->ip_sum = in_cksum(m, mhlen); 22733744Skarels *mnext = m; 22833744Skarels mnext = &m->m_act; 2294924Swnj } 23033744Skarels /* 23133744Skarels * Update first fragment by trimming what's been copied out 23233744Skarels * and updating header, then send each fragment (in order). 23333744Skarels */ 23433744Skarels m_adj(m0, hlen + firstlen - ip->ip_len); 235*33983Skarels ip->ip_len = htons((u_short)(hlen + firstlen)); 236*33983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 23733744Skarels ip->ip_sum = 0; 23833744Skarels ip->ip_sum = in_cksum(m0, hlen); 23933744Skarels sendorfree: 24033744Skarels for (m = m0; m; m = m0) { 24133744Skarels m0 = m->m_act; 24233744Skarels m->m_act = 0; 24333744Skarels if (error == 0) 24433744Skarels error = (*ifp->if_output)(ifp, m, 24533744Skarels (struct sockaddr *)dst); 24633744Skarels else 24733744Skarels m_freem(m); 24833744Skarels } 24933744Skarels } 2507155Swnj done: 25112417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 2527155Swnj RTFREE(ro->ro_rt); 2536505Ssam return (error); 25433744Skarels bad: 25533744Skarels m_freem(m0); 25633744Skarels goto done; 2574924Swnj } 2584924Swnj 2594924Swnj /* 26024814Skarels * Insert IP options into preformed packet. 26124814Skarels * Adjust IP destination as required for IP source routing, 26224814Skarels * as indicated by a non-zero in_addr at the start of the options. 26324814Skarels */ 26424814Skarels struct mbuf * 26524814Skarels ip_insertoptions(m, opt, phlen) 26624814Skarels register struct mbuf *m; 26724814Skarels struct mbuf *opt; 26824814Skarels int *phlen; 26924814Skarels { 27024814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 27124814Skarels struct mbuf *n; 27224814Skarels register struct ip *ip = mtod(m, struct ip *); 27326385Skarels unsigned optlen; 27424814Skarels 27524814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 27624814Skarels if (p->ipopt_dst.s_addr) 27724814Skarels ip->ip_dst = p->ipopt_dst; 27824814Skarels if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { 27924814Skarels MGET(n, M_DONTWAIT, MT_HEADER); 28024814Skarels if (n == 0) 28124814Skarels return (m); 28224814Skarels m->m_len -= sizeof(struct ip); 28324814Skarels m->m_off += sizeof(struct ip); 28424814Skarels n->m_next = m; 28524814Skarels m = n; 28624814Skarels m->m_off = MMAXOFF - sizeof(struct ip) - optlen; 28724814Skarels m->m_len = optlen + sizeof(struct ip); 28824814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 28924814Skarels } else { 29024814Skarels m->m_off -= optlen; 29124814Skarels m->m_len += optlen; 29224814Skarels ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 29324814Skarels } 29424814Skarels ip = mtod(m, struct ip *); 29526385Skarels bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 29624814Skarels *phlen = sizeof(struct ip) + optlen; 29724814Skarels ip->ip_len += optlen; 29824814Skarels return (m); 29924814Skarels } 30024814Skarels 30124814Skarels /* 30233744Skarels * Copy options from ip to jp, 30333744Skarels * omitting those not copied during fragmentation. 3044924Swnj */ 30533744Skarels ip_optcopy(ip, jp) 3064924Swnj struct ip *ip, *jp; 3074924Swnj { 3084924Swnj register u_char *cp, *dp; 3094924Swnj int opt, optlen, cnt; 3104924Swnj 3114924Swnj cp = (u_char *)(ip + 1); 3124924Swnj dp = (u_char *)(jp + 1); 3134924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 3144924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 3154924Swnj opt = cp[0]; 3164924Swnj if (opt == IPOPT_EOL) 3174924Swnj break; 3184924Swnj if (opt == IPOPT_NOP) 3194924Swnj optlen = 1; 3204924Swnj else 32124814Skarels optlen = cp[IPOPT_OLEN]; 32233744Skarels /* bogus lengths should have been caught by ip_dooptions */ 32333744Skarels if (optlen > cnt) 32433744Skarels optlen = cnt; 32533744Skarels if (IPOPT_COPIED(opt)) { 3264952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 3274924Swnj dp += optlen; 3284674Swnj } 3294545Swnj } 3304924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 3314924Swnj *dp++ = IPOPT_EOL; 3324924Swnj return (optlen); 3334496Swnj } 33424814Skarels 33524814Skarels /* 33624814Skarels * IP socket option processing. 33724814Skarels */ 33824814Skarels ip_ctloutput(op, so, level, optname, m) 33924814Skarels int op; 34024814Skarels struct socket *so; 34124814Skarels int level, optname; 34224814Skarels struct mbuf **m; 34324814Skarels { 34424814Skarels int error = 0; 34524814Skarels struct inpcb *inp = sotoinpcb(so); 34624814Skarels 34724814Skarels if (level != IPPROTO_IP) 34824814Skarels error = EINVAL; 34924814Skarels else switch (op) { 35024814Skarels 35124814Skarels case PRCO_SETOPT: 35224814Skarels switch (optname) { 35324814Skarels case IP_OPTIONS: 35426036Skarels return (ip_pcbopts(&inp->inp_options, *m)); 35524814Skarels 35624814Skarels default: 35724814Skarels error = EINVAL; 35824814Skarels break; 35924814Skarels } 36024814Skarels break; 36124814Skarels 36224814Skarels case PRCO_GETOPT: 36324814Skarels switch (optname) { 36424814Skarels case IP_OPTIONS: 36524814Skarels *m = m_get(M_WAIT, MT_SOOPTS); 36624814Skarels if (inp->inp_options) { 36724814Skarels (*m)->m_off = inp->inp_options->m_off; 36824814Skarels (*m)->m_len = inp->inp_options->m_len; 36924814Skarels bcopy(mtod(inp->inp_options, caddr_t), 37026385Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 37124814Skarels } else 37224814Skarels (*m)->m_len = 0; 37324814Skarels break; 37424814Skarels default: 37524814Skarels error = EINVAL; 37624814Skarels break; 37724814Skarels } 37824814Skarels break; 37924814Skarels } 38031649Smckusick if (op == PRCO_SETOPT && *m) 38126385Skarels (void)m_free(*m); 38224814Skarels return (error); 38324814Skarels } 38424814Skarels 38524814Skarels /* 38626036Skarels * Set up IP options in pcb for insertion in output packets. 38726036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 38826036Skarels * with destination address if source routed. 38924814Skarels */ 39026036Skarels ip_pcbopts(pcbopt, m) 39126036Skarels struct mbuf **pcbopt; 39226036Skarels register struct mbuf *m; 39324814Skarels { 39424814Skarels register cnt, optlen; 39524814Skarels register u_char *cp; 39624814Skarels u_char opt; 39724814Skarels 39824814Skarels /* turn off any old options */ 39926036Skarels if (*pcbopt) 40026385Skarels (void)m_free(*pcbopt); 40126036Skarels *pcbopt = 0; 40224814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 40324814Skarels /* 40424814Skarels * Only turning off any previous options. 40524814Skarels */ 40624814Skarels if (m) 40726385Skarels (void)m_free(m); 40824814Skarels return (0); 40924814Skarels } 41024814Skarels 41124814Skarels #ifndef vax 41224814Skarels if (m->m_len % sizeof(long)) 41324814Skarels goto bad; 41424814Skarels #endif 41524814Skarels /* 41624814Skarels * IP first-hop destination address will be stored before 41724814Skarels * actual options; move other options back 41824814Skarels * and clear it when none present. 41924814Skarels */ 42024814Skarels #if MAX_IPOPTLEN >= MMAXOFF - MMINOFF 42124814Skarels if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) 42224814Skarels goto bad; 42324814Skarels #else 42424814Skarels if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) 42524814Skarels goto bad; 42624814Skarels #endif 42724814Skarels cnt = m->m_len; 42824814Skarels m->m_len += sizeof(struct in_addr); 42924814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 43026385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 43124814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 43224814Skarels 43324814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 43424814Skarels opt = cp[IPOPT_OPTVAL]; 43524814Skarels if (opt == IPOPT_EOL) 43624814Skarels break; 43724814Skarels if (opt == IPOPT_NOP) 43824814Skarels optlen = 1; 43924814Skarels else { 44024814Skarels optlen = cp[IPOPT_OLEN]; 44124814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 44224814Skarels goto bad; 44324814Skarels } 44424814Skarels switch (opt) { 44524814Skarels 44624814Skarels default: 44724814Skarels break; 44824814Skarels 44924814Skarels case IPOPT_LSRR: 45024814Skarels case IPOPT_SSRR: 45124814Skarels /* 45224814Skarels * user process specifies route as: 45324814Skarels * ->A->B->C->D 45424814Skarels * D must be our final destination (but we can't 45524814Skarels * check that since we may not have connected yet). 45624814Skarels * A is first hop destination, which doesn't appear in 45724814Skarels * actual IP option, but is stored before the options. 45824814Skarels */ 45924814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 46024814Skarels goto bad; 46124814Skarels m->m_len -= sizeof(struct in_addr); 46224814Skarels cnt -= sizeof(struct in_addr); 46324814Skarels optlen -= sizeof(struct in_addr); 46424814Skarels cp[IPOPT_OLEN] = optlen; 46524814Skarels /* 46624814Skarels * Move first hop before start of options. 46724814Skarels */ 46826385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 46924814Skarels sizeof(struct in_addr)); 47024814Skarels /* 47124814Skarels * Then copy rest of options back 47224814Skarels * to close up the deleted entry. 47324814Skarels */ 47426385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 47526385Skarels sizeof(struct in_addr)), 47626385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 47726385Skarels (unsigned)cnt + sizeof(struct in_addr)); 47824814Skarels break; 47924814Skarels } 48024814Skarels } 48126036Skarels *pcbopt = m; 48224814Skarels return (0); 48324814Skarels 48424814Skarels bad: 48526385Skarels (void)m_free(m); 48624814Skarels return (EINVAL); 48724814Skarels } 488