123745Skarels /* 234820Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423745Skarels * 532787Sbostic * Redistribution and use in source and binary forms are permitted 6*34854Sbostic * provided that the above copyright notice and this paragraph are 7*34854Sbostic * duplicated in all such forms and that any documentation, 8*34854Sbostic * advertising materials, and other materials related to such 9*34854Sbostic * distribution and use acknowledge that the software was developed 10*34854Sbostic * by the University of California, Berkeley. The name of the 11*34854Sbostic * University may not be used to endorse or promote products derived 12*34854Sbostic * from this software without specific prior written permission. 13*34854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*34854Sbostic * @(#)ip_output.c 7.13 (Berkeley) 06/29/88 1823745Skarels */ 194571Swnj 2017061Sbloom #include "param.h" 2117061Sbloom #include "mbuf.h" 2217061Sbloom #include "errno.h" 2324814Skarels #include "protosw.h" 2417061Sbloom #include "socket.h" 2517061Sbloom #include "socketvar.h" 2610893Ssam 2710893Ssam #include "../net/if.h" 2810893Ssam #include "../net/route.h" 2910893Ssam 3017061Sbloom #include "in.h" 3124814Skarels #include "in_pcb.h" 3217061Sbloom #include "in_systm.h" 3318375Skarels #include "in_var.h" 3417061Sbloom #include "ip.h" 3517061Sbloom #include "ip_var.h" 364496Swnj 3712460Ssam #ifdef vax 3829923Skarels #include "../machine/mtpr.h" 3912460Ssam #endif 4010893Ssam 4124814Skarels struct mbuf *ip_insertoptions(); 4224814Skarels 4324814Skarels /* 4424814Skarels * IP output. The packet in mbuf chain m contains a skeletal IP 4531037Skarels * header (with len, off, ttl, proto, tos, src, dst). 4631037Skarels * The mbuf chain containing the packet will be freed. 4731037Skarels * The mbuf opt, if present, will not be freed. 4824814Skarels */ 4933598Skarels ip_output(m0, opt, ro, flags) 5033598Skarels struct mbuf *m0; 515085Swnj struct mbuf *opt; 526339Ssam struct route *ro; 5312417Ssam int flags; 544496Swnj { 5533598Skarels register struct ip *ip, *mhip; 565085Swnj register struct ifnet *ifp; 5733598Skarels register struct mbuf *m = m0; 5833598Skarels register int hlen = sizeof (struct ip); 5933598Skarels int len, off, error = 0; 606339Ssam struct route iproute; 6116602Ssam struct sockaddr_in *dst; 624496Swnj 6333598Skarels if (opt) { 6433598Skarels m = ip_insertoptions(m, opt, &len); 6533598Skarels hlen = len; 6633598Skarels } 6724814Skarels ip = mtod(m, struct ip *); 684924Swnj /* 694924Swnj * Fill in IP header. 704924Swnj */ 7112417Ssam if ((flags & IP_FORWARDING) == 0) { 7212417Ssam ip->ip_v = IPVERSION; 7312417Ssam ip->ip_off &= IP_DF; 7412417Ssam ip->ip_id = htons(ip_id++); 7516545Skarels ip->ip_hl = hlen >> 2; 7624814Skarels } else 7724814Skarels hlen = ip->ip_hl << 2; 784496Swnj 794545Swnj /* 807155Swnj * Route packet. 815085Swnj */ 826339Ssam if (ro == 0) { 836339Ssam ro = &iproute; 846339Ssam bzero((caddr_t)ro, sizeof (*ro)); 855085Swnj } 8616602Ssam dst = (struct sockaddr_in *)&ro->ro_dst; 8726156Skarels /* 8826156Skarels * If there is a cached route, 8926156Skarels * check that it is to the same destination 9026156Skarels * and is still up. If not, free it and try again. 9126156Skarels */ 9226156Skarels if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 9326156Skarels dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 9426156Skarels RTFREE(ro->ro_rt); 9526156Skarels ro->ro_rt = (struct rtentry *)0; 9626156Skarels } 976339Ssam if (ro->ro_rt == 0) { 9816602Ssam dst->sin_family = AF_INET; 9916602Ssam dst->sin_addr = ip->ip_dst; 10026058Skarels } 10126058Skarels /* 10226058Skarels * If routing to interface only, 10326058Skarels * short circuit routing lookup. 10426058Skarels */ 10526058Skarels if (flags & IP_ROUTETOIF) { 10626058Skarels struct in_ifaddr *ia; 10727196Skarels 10834500Skarels ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); 10927196Skarels if (ia == 0) 11027196Skarels ia = in_iaonnetof(in_netof(ip->ip_dst)); 11126058Skarels if (ia == 0) { 11226058Skarels error = ENETUNREACH; 11326058Skarels goto bad; 11426058Skarels } 11526058Skarels ifp = ia->ia_ifp; 11626058Skarels } else { 11726058Skarels if (ro->ro_rt == 0) 11826058Skarels rtalloc(ro); 11926058Skarels if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 12031200Skarels if (in_localaddr(ip->ip_dst)) 12131200Skarels error = EHOSTUNREACH; 12231200Skarels else 12331200Skarels error = ENETUNREACH; 12426058Skarels goto bad; 12526058Skarels } 12626058Skarels ro->ro_rt->rt_use++; 12730761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 12826058Skarels dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; 1296339Ssam } 13023745Skarels #ifndef notdef 1317155Swnj /* 13223745Skarels * If source address not specified yet, use address 13323745Skarels * of outgoing interface. 13423745Skarels */ 13523745Skarels if (ip->ip_src.s_addr == INADDR_ANY) { 13623745Skarels register struct in_ifaddr *ia; 13723745Skarels 13823745Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 13923745Skarels if (ia->ia_ifp == ifp) { 14023745Skarels ip->ip_src = IA_SIN(ia)->sin_addr; 14123745Skarels break; 14223745Skarels } 14323745Skarels } 14423745Skarels #endif 14523745Skarels /* 14610402Ssam * Look for broadcast address and 14710402Ssam * and verify user is allowed to send 14810146Ssam * such a packet. 1497155Swnj */ 15018375Skarels if (in_broadcast(dst->sin_addr)) { 15110146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 15210146Ssam error = EADDRNOTAVAIL; 15310146Ssam goto bad; 15410146Ssam } 15512417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 1567155Swnj error = EACCES; 1576339Ssam goto bad; 1586505Ssam } 15910146Ssam /* don't allow broadcast messages to be fragmented */ 16010146Ssam if (ip->ip_len > ifp->if_mtu) { 16110146Ssam error = EMSGSIZE; 16210146Ssam goto bad; 16310146Ssam } 1646339Ssam } 1656339Ssam 1665085Swnj /* 1674924Swnj * If small enough for interface, can just send directly. 1684545Swnj */ 1695085Swnj if (ip->ip_len <= ifp->if_mtu) { 1705085Swnj ip->ip_len = htons((u_short)ip->ip_len); 1715085Swnj ip->ip_off = htons((u_short)ip->ip_off); 1725085Swnj ip->ip_sum = 0; 1735085Swnj ip->ip_sum = in_cksum(m, hlen); 17416602Ssam error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); 1757155Swnj goto done; 1764908Swnj } 1774924Swnj 1784924Swnj /* 1794924Swnj * Too large for interface; fragment if possible. 1804924Swnj * Must be able to put at least 8 bytes per fragment. 1814924Swnj */ 1826505Ssam if (ip->ip_off & IP_DF) { 1836505Ssam error = EMSGSIZE; 1844924Swnj goto bad; 1856505Ssam } 1865085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1876505Ssam if (len < 8) { 1886505Ssam error = EMSGSIZE; 1894924Swnj goto bad; 1906505Ssam } 1914924Swnj 19233744Skarels { 19333744Skarels int mhlen, firstlen = len; 19433744Skarels struct mbuf **mnext = &m->m_act; 19533744Skarels 1964924Swnj /* 19733744Skarels * Loop through length of segment after first fragment, 19833744Skarels * make new header and copy data of each part and link onto chain. 1994924Swnj */ 20033598Skarels m0 = m; 20133744Skarels mhlen = sizeof (struct ip); 20233744Skarels for (off = hlen + len; off < ip->ip_len; off += len) { 20333598Skarels MGET(m, M_DONTWAIT, MT_HEADER); 20433598Skarels if (m == 0) { 2056505Ssam error = ENOBUFS; 20634820Skarels goto sendorfree; 2076505Ssam } 20833598Skarels m->m_off = MMAXOFF - hlen; 20933598Skarels mhip = mtod(m, struct ip *); 2104924Swnj *mhip = *ip; 2114952Swnj if (hlen > sizeof (struct ip)) { 21233744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 21333598Skarels mhip->ip_hl = mhlen >> 2; 21433744Skarels } 21533598Skarels m->m_len = mhlen; 21633744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 21716545Skarels if (ip->ip_off & IP_MF) 21816545Skarels mhip->ip_off |= IP_MF; 21933744Skarels if (off + len >= ip->ip_len) 22033744Skarels len = ip->ip_len - off; 22133598Skarels else 2224924Swnj mhip->ip_off |= IP_MF; 22333598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 22433598Skarels m->m_next = m_copy(m0, off, len); 22533598Skarels if (m->m_next == 0) { 2266505Ssam error = ENOBUFS; /* ??? */ 22733744Skarels goto sendorfree; 2284674Swnj } 2295892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 2305892Sroot mhip->ip_sum = 0; 23133598Skarels mhip->ip_sum = in_cksum(m, mhlen); 23233744Skarels *mnext = m; 23333744Skarels mnext = &m->m_act; 2344924Swnj } 23533744Skarels /* 23633744Skarels * Update first fragment by trimming what's been copied out 23733744Skarels * and updating header, then send each fragment (in order). 23833744Skarels */ 23933744Skarels m_adj(m0, hlen + firstlen - ip->ip_len); 24033983Skarels ip->ip_len = htons((u_short)(hlen + firstlen)); 24133983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 24233744Skarels ip->ip_sum = 0; 24333744Skarels ip->ip_sum = in_cksum(m0, hlen); 24433744Skarels sendorfree: 24533744Skarels for (m = m0; m; m = m0) { 24633744Skarels m0 = m->m_act; 24733744Skarels m->m_act = 0; 24833744Skarels if (error == 0) 24933744Skarels error = (*ifp->if_output)(ifp, m, 25033744Skarels (struct sockaddr *)dst); 25133744Skarels else 25233744Skarels m_freem(m); 25333744Skarels } 25433744Skarels } 2557155Swnj done: 25612417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 2577155Swnj RTFREE(ro->ro_rt); 2586505Ssam return (error); 25933744Skarels bad: 26033744Skarels m_freem(m0); 26133744Skarels goto done; 2624924Swnj } 2634924Swnj 2644924Swnj /* 26524814Skarels * Insert IP options into preformed packet. 26624814Skarels * Adjust IP destination as required for IP source routing, 26724814Skarels * as indicated by a non-zero in_addr at the start of the options. 26824814Skarels */ 26924814Skarels struct mbuf * 27024814Skarels ip_insertoptions(m, opt, phlen) 27124814Skarels register struct mbuf *m; 27224814Skarels struct mbuf *opt; 27324814Skarels int *phlen; 27424814Skarels { 27524814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 27624814Skarels struct mbuf *n; 27724814Skarels register struct ip *ip = mtod(m, struct ip *); 27826385Skarels unsigned optlen; 27924814Skarels 28024814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 28124814Skarels if (p->ipopt_dst.s_addr) 28224814Skarels ip->ip_dst = p->ipopt_dst; 28324814Skarels if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { 28424814Skarels MGET(n, M_DONTWAIT, MT_HEADER); 28524814Skarels if (n == 0) 28624814Skarels return (m); 28724814Skarels m->m_len -= sizeof(struct ip); 28824814Skarels m->m_off += sizeof(struct ip); 28924814Skarels n->m_next = m; 29024814Skarels m = n; 29124814Skarels m->m_off = MMAXOFF - sizeof(struct ip) - optlen; 29224814Skarels m->m_len = optlen + sizeof(struct ip); 29324814Skarels bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 29424814Skarels } else { 29524814Skarels m->m_off -= optlen; 29624814Skarels m->m_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 */ 34324814Skarels ip_ctloutput(op, so, level, optname, m) 34424814Skarels int op; 34524814Skarels struct socket *so; 34624814Skarels int level, optname; 34724814Skarels struct mbuf **m; 34824814Skarels { 34924814Skarels int error = 0; 35024814Skarels struct inpcb *inp = sotoinpcb(so); 35124814Skarels 35224814Skarels if (level != IPPROTO_IP) 35324814Skarels error = EINVAL; 35424814Skarels else switch (op) { 35524814Skarels 35624814Skarels case PRCO_SETOPT: 35724814Skarels switch (optname) { 35824814Skarels case IP_OPTIONS: 35926036Skarels return (ip_pcbopts(&inp->inp_options, *m)); 36024814Skarels 36124814Skarels default: 36224814Skarels error = EINVAL; 36324814Skarels break; 36424814Skarels } 36524814Skarels break; 36624814Skarels 36724814Skarels case PRCO_GETOPT: 36824814Skarels switch (optname) { 36924814Skarels case IP_OPTIONS: 37024814Skarels *m = m_get(M_WAIT, MT_SOOPTS); 37124814Skarels if (inp->inp_options) { 37224814Skarels (*m)->m_off = inp->inp_options->m_off; 37324814Skarels (*m)->m_len = inp->inp_options->m_len; 37424814Skarels bcopy(mtod(inp->inp_options, caddr_t), 37526385Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 37624814Skarels } else 37724814Skarels (*m)->m_len = 0; 37824814Skarels break; 37924814Skarels default: 38024814Skarels error = EINVAL; 38124814Skarels break; 38224814Skarels } 38324814Skarels break; 38424814Skarels } 38531649Smckusick if (op == PRCO_SETOPT && *m) 38626385Skarels (void)m_free(*m); 38724814Skarels return (error); 38824814Skarels } 38924814Skarels 39024814Skarels /* 39126036Skarels * Set up IP options in pcb for insertion in output packets. 39226036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 39326036Skarels * with destination address if source routed. 39424814Skarels */ 39526036Skarels ip_pcbopts(pcbopt, m) 39626036Skarels struct mbuf **pcbopt; 39726036Skarels register struct mbuf *m; 39824814Skarels { 39924814Skarels register cnt, optlen; 40024814Skarels register u_char *cp; 40124814Skarels u_char opt; 40224814Skarels 40324814Skarels /* turn off any old options */ 40426036Skarels if (*pcbopt) 40526385Skarels (void)m_free(*pcbopt); 40626036Skarels *pcbopt = 0; 40724814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 40824814Skarels /* 40924814Skarels * Only turning off any previous options. 41024814Skarels */ 41124814Skarels if (m) 41226385Skarels (void)m_free(m); 41324814Skarels return (0); 41424814Skarels } 41524814Skarels 41624814Skarels #ifndef vax 41724814Skarels if (m->m_len % sizeof(long)) 41824814Skarels goto bad; 41924814Skarels #endif 42024814Skarels /* 42124814Skarels * IP first-hop destination address will be stored before 42224814Skarels * actual options; move other options back 42324814Skarels * and clear it when none present. 42424814Skarels */ 42524814Skarels #if MAX_IPOPTLEN >= MMAXOFF - MMINOFF 42624814Skarels if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) 42724814Skarels goto bad; 42824814Skarels #else 42924814Skarels if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) 43024814Skarels goto bad; 43124814Skarels #endif 43224814Skarels cnt = m->m_len; 43324814Skarels m->m_len += sizeof(struct in_addr); 43424814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 43526385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 43624814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 43724814Skarels 43824814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 43924814Skarels opt = cp[IPOPT_OPTVAL]; 44024814Skarels if (opt == IPOPT_EOL) 44124814Skarels break; 44224814Skarels if (opt == IPOPT_NOP) 44324814Skarels optlen = 1; 44424814Skarels else { 44524814Skarels optlen = cp[IPOPT_OLEN]; 44624814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 44724814Skarels goto bad; 44824814Skarels } 44924814Skarels switch (opt) { 45024814Skarels 45124814Skarels default: 45224814Skarels break; 45324814Skarels 45424814Skarels case IPOPT_LSRR: 45524814Skarels case IPOPT_SSRR: 45624814Skarels /* 45724814Skarels * user process specifies route as: 45824814Skarels * ->A->B->C->D 45924814Skarels * D must be our final destination (but we can't 46024814Skarels * check that since we may not have connected yet). 46124814Skarels * A is first hop destination, which doesn't appear in 46224814Skarels * actual IP option, but is stored before the options. 46324814Skarels */ 46424814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 46524814Skarels goto bad; 46624814Skarels m->m_len -= sizeof(struct in_addr); 46724814Skarels cnt -= sizeof(struct in_addr); 46824814Skarels optlen -= sizeof(struct in_addr); 46924814Skarels cp[IPOPT_OLEN] = optlen; 47024814Skarels /* 47124814Skarels * Move first hop before start of options. 47224814Skarels */ 47326385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 47424814Skarels sizeof(struct in_addr)); 47524814Skarels /* 47624814Skarels * Then copy rest of options back 47724814Skarels * to close up the deleted entry. 47824814Skarels */ 47926385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 48026385Skarels sizeof(struct in_addr)), 48126385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 48226385Skarels (unsigned)cnt + sizeof(struct in_addr)); 48324814Skarels break; 48424814Skarels } 48524814Skarels } 48626036Skarels *pcbopt = m; 48724814Skarels return (0); 48824814Skarels 48924814Skarels bad: 49026385Skarels (void)m_free(m); 49124814Skarels return (EINVAL); 49224814Skarels } 493