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 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*40794Ssklower * @(#)ip_output.c 7.18 (Berkeley) 04/05/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" 32*40794Ssklower #include "in_systm.h" 33*40794Ssklower #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; 63*40794Ssklower 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); 12426058Skarels if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 12531200Skarels if (in_localaddr(ip->ip_dst)) 12631200Skarels error = EHOSTUNREACH; 12731200Skarels else 12831200Skarels error = ENETUNREACH; 12926058Skarels goto bad; 13026058Skarels } 131*40794Ssklower ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; 13226058Skarels ro->ro_rt->rt_use++; 13330761Skarels if (ro->ro_rt->rt_flags & RTF_GATEWAY) 13437318Skarels dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1356339Ssam } 13623745Skarels #ifndef notdef 1377155Swnj /* 13823745Skarels * If source address not specified yet, use address 13923745Skarels * of outgoing interface. 14023745Skarels */ 141*40794Ssklower if (ip->ip_src.s_addr == INADDR_ANY) 142*40794Ssklower ip->ip_src = IA_SIN(ia)->sin_addr; 14323745Skarels #endif 14423745Skarels /* 14510402Ssam * Look for broadcast address and 14610402Ssam * and verify user is allowed to send 14710146Ssam * such a packet. 1487155Swnj */ 14918375Skarels if (in_broadcast(dst->sin_addr)) { 15010146Ssam if ((ifp->if_flags & IFF_BROADCAST) == 0) { 15110146Ssam error = EADDRNOTAVAIL; 15210146Ssam goto bad; 15310146Ssam } 15412417Ssam if ((flags & IP_ALLOWBROADCAST) == 0) { 1557155Swnj error = EACCES; 1566339Ssam goto bad; 1576505Ssam } 15810146Ssam /* don't allow broadcast messages to be fragmented */ 15910146Ssam if (ip->ip_len > ifp->if_mtu) { 16010146Ssam error = EMSGSIZE; 16110146Ssam goto bad; 16210146Ssam } 16337318Skarels m->m_flags |= M_BCAST; 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); 174*40794Ssklower error = (*ifp->if_output)(ifp, m, 175*40794Ssklower (struct sockaddr *)dst, ro->ro_rt); 1767155Swnj goto done; 1774908Swnj } 17839185Ssklower ipstat.ips_fragmented++; 1794924Swnj /* 1804924Swnj * Too large for interface; fragment if possible. 1814924Swnj * Must be able to put at least 8 bytes per fragment. 1824924Swnj */ 1836505Ssam if (ip->ip_off & IP_DF) { 1846505Ssam error = EMSGSIZE; 1854924Swnj goto bad; 1866505Ssam } 1875085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1886505Ssam if (len < 8) { 1896505Ssam error = EMSGSIZE; 1904924Swnj goto bad; 1916505Ssam } 1924924Swnj 19333744Skarels { 19433744Skarels int mhlen, firstlen = len; 19537318Skarels struct mbuf **mnext = &m->m_nextpkt; 19633744Skarels 1974924Swnj /* 19833744Skarels * Loop through length of segment after first fragment, 19933744Skarels * make new header and copy data of each part and link onto chain. 2004924Swnj */ 20133598Skarels m0 = m; 20233744Skarels mhlen = sizeof (struct ip); 20333744Skarels for (off = hlen + len; off < ip->ip_len; off += len) { 20437318Skarels MGETHDR(m, M_DONTWAIT, MT_HEADER); 20533598Skarels if (m == 0) { 2066505Ssam error = ENOBUFS; 20734820Skarels goto sendorfree; 2086505Ssam } 20937318Skarels m->m_data += max_linkhdr; 21033598Skarels mhip = mtod(m, struct ip *); 2114924Swnj *mhip = *ip; 2124952Swnj if (hlen > sizeof (struct ip)) { 21333744Skarels mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 21433598Skarels mhip->ip_hl = mhlen >> 2; 21533744Skarels } 21633598Skarels m->m_len = mhlen; 21733744Skarels mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 21816545Skarels if (ip->ip_off & IP_MF) 21916545Skarels mhip->ip_off |= IP_MF; 22033744Skarels if (off + len >= ip->ip_len) 22133744Skarels len = ip->ip_len - off; 22233598Skarels else 2234924Swnj mhip->ip_off |= IP_MF; 22433598Skarels mhip->ip_len = htons((u_short)(len + mhlen)); 22533598Skarels m->m_next = m_copy(m0, off, len); 22633598Skarels if (m->m_next == 0) { 2276505Ssam error = ENOBUFS; /* ??? */ 22833744Skarels goto sendorfree; 2294674Swnj } 23037318Skarels m->m_pkthdr.len = mhlen + len; 23137318Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 2325892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 2335892Sroot mhip->ip_sum = 0; 23433598Skarels mhip->ip_sum = in_cksum(m, mhlen); 23533744Skarels *mnext = m; 23637318Skarels mnext = &m->m_nextpkt; 23739185Ssklower ipstat.ips_ofragments++; 2384924Swnj } 23933744Skarels /* 24033744Skarels * Update first fragment by trimming what's been copied out 24133744Skarels * and updating header, then send each fragment (in order). 24233744Skarels */ 24340254Smckusick m = m0; 24440254Smckusick m_adj(m, hlen + firstlen - ip->ip_len); 24537318Skarels m->m_pkthdr.len = hlen + firstlen; 24637318Skarels ip->ip_len = htons((u_short)m->m_pkthdr.len); 24733983Skarels ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); 24833744Skarels ip->ip_sum = 0; 24940254Smckusick ip->ip_sum = in_cksum(m, hlen); 25033744Skarels sendorfree: 25133744Skarels for (m = m0; m; m = m0) { 25237318Skarels m0 = m->m_nextpkt; 25337318Skarels m->m_nextpkt = 0; 25433744Skarels if (error == 0) 25533744Skarels error = (*ifp->if_output)(ifp, m, 256*40794Ssklower (struct sockaddr *)dst, ro->ro_rt); 25733744Skarels else 25833744Skarels m_freem(m); 25933744Skarels } 26033744Skarels } 2617155Swnj done: 26212417Ssam if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 2637155Swnj RTFREE(ro->ro_rt); 2646505Ssam return (error); 26533744Skarels bad: 26633744Skarels m_freem(m0); 26733744Skarels goto done; 2684924Swnj } 2694924Swnj 2704924Swnj /* 27124814Skarels * Insert IP options into preformed packet. 27224814Skarels * Adjust IP destination as required for IP source routing, 27324814Skarels * as indicated by a non-zero in_addr at the start of the options. 27424814Skarels */ 27524814Skarels struct mbuf * 27624814Skarels ip_insertoptions(m, opt, phlen) 27724814Skarels register struct mbuf *m; 27824814Skarels struct mbuf *opt; 27924814Skarels int *phlen; 28024814Skarels { 28124814Skarels register struct ipoption *p = mtod(opt, struct ipoption *); 28224814Skarels struct mbuf *n; 28324814Skarels register struct ip *ip = mtod(m, struct ip *); 28426385Skarels unsigned optlen; 28524814Skarels 28624814Skarels optlen = opt->m_len - sizeof(p->ipopt_dst); 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 */ 35124814Skarels ip_ctloutput(op, so, level, optname, m) 35224814Skarels int op; 35324814Skarels struct socket *so; 35424814Skarels int level, optname; 35524814Skarels struct mbuf **m; 35624814Skarels { 35724814Skarels int error = 0; 35824814Skarels struct inpcb *inp = sotoinpcb(so); 35924814Skarels 36024814Skarels if (level != IPPROTO_IP) 36124814Skarels error = EINVAL; 36224814Skarels else switch (op) { 36324814Skarels 36424814Skarels case PRCO_SETOPT: 36524814Skarels switch (optname) { 36624814Skarels case IP_OPTIONS: 36726036Skarels return (ip_pcbopts(&inp->inp_options, *m)); 36824814Skarels 36924814Skarels default: 37024814Skarels error = EINVAL; 37124814Skarels break; 37224814Skarels } 37324814Skarels break; 37424814Skarels 37524814Skarels case PRCO_GETOPT: 37624814Skarels switch (optname) { 37724814Skarels case IP_OPTIONS: 37824814Skarels *m = m_get(M_WAIT, MT_SOOPTS); 37924814Skarels if (inp->inp_options) { 38024814Skarels (*m)->m_len = inp->inp_options->m_len; 38124814Skarels bcopy(mtod(inp->inp_options, caddr_t), 38226385Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 38324814Skarels } else 38424814Skarels (*m)->m_len = 0; 38524814Skarels break; 38624814Skarels default: 38724814Skarels error = EINVAL; 38824814Skarels break; 38924814Skarels } 39024814Skarels break; 39124814Skarels } 39231649Smckusick if (op == PRCO_SETOPT && *m) 39326385Skarels (void)m_free(*m); 39424814Skarels return (error); 39524814Skarels } 39624814Skarels 39724814Skarels /* 39826036Skarels * Set up IP options in pcb for insertion in output packets. 39926036Skarels * Store in mbuf with pointer in pcbopt, adding pseudo-option 40026036Skarels * with destination address if source routed. 40124814Skarels */ 40226036Skarels ip_pcbopts(pcbopt, m) 40326036Skarels struct mbuf **pcbopt; 40426036Skarels register struct mbuf *m; 40524814Skarels { 40624814Skarels register cnt, optlen; 40724814Skarels register u_char *cp; 40824814Skarels u_char opt; 40924814Skarels 41024814Skarels /* turn off any old options */ 41126036Skarels if (*pcbopt) 41226385Skarels (void)m_free(*pcbopt); 41326036Skarels *pcbopt = 0; 41424814Skarels if (m == (struct mbuf *)0 || m->m_len == 0) { 41524814Skarels /* 41624814Skarels * Only turning off any previous options. 41724814Skarels */ 41824814Skarels if (m) 41926385Skarels (void)m_free(m); 42024814Skarels return (0); 42124814Skarels } 42224814Skarels 42324814Skarels #ifndef vax 42424814Skarels if (m->m_len % sizeof(long)) 42524814Skarels goto bad; 42624814Skarels #endif 42724814Skarels /* 42824814Skarels * IP first-hop destination address will be stored before 42924814Skarels * actual options; move other options back 43024814Skarels * and clear it when none present. 43124814Skarels */ 43237318Skarels if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 43324814Skarels goto bad; 43424814Skarels cnt = m->m_len; 43524814Skarels m->m_len += sizeof(struct in_addr); 43624814Skarels cp = mtod(m, u_char *) + sizeof(struct in_addr); 43726385Skarels ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 43824814Skarels bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 43924814Skarels 44024814Skarels for (; cnt > 0; cnt -= optlen, cp += optlen) { 44124814Skarels opt = cp[IPOPT_OPTVAL]; 44224814Skarels if (opt == IPOPT_EOL) 44324814Skarels break; 44424814Skarels if (opt == IPOPT_NOP) 44524814Skarels optlen = 1; 44624814Skarels else { 44724814Skarels optlen = cp[IPOPT_OLEN]; 44824814Skarels if (optlen <= IPOPT_OLEN || optlen > cnt) 44924814Skarels goto bad; 45024814Skarels } 45124814Skarels switch (opt) { 45224814Skarels 45324814Skarels default: 45424814Skarels break; 45524814Skarels 45624814Skarels case IPOPT_LSRR: 45724814Skarels case IPOPT_SSRR: 45824814Skarels /* 45924814Skarels * user process specifies route as: 46024814Skarels * ->A->B->C->D 46124814Skarels * D must be our final destination (but we can't 46224814Skarels * check that since we may not have connected yet). 46324814Skarels * A is first hop destination, which doesn't appear in 46424814Skarels * actual IP option, but is stored before the options. 46524814Skarels */ 46624814Skarels if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 46724814Skarels goto bad; 46824814Skarels m->m_len -= sizeof(struct in_addr); 46924814Skarels cnt -= sizeof(struct in_addr); 47024814Skarels optlen -= sizeof(struct in_addr); 47124814Skarels cp[IPOPT_OLEN] = optlen; 47224814Skarels /* 47324814Skarels * Move first hop before start of options. 47424814Skarels */ 47526385Skarels bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 47624814Skarels sizeof(struct in_addr)); 47724814Skarels /* 47824814Skarels * Then copy rest of options back 47924814Skarels * to close up the deleted entry. 48024814Skarels */ 48126385Skarels ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 48226385Skarels sizeof(struct in_addr)), 48326385Skarels (caddr_t)&cp[IPOPT_OFFSET+1], 48426385Skarels (unsigned)cnt + sizeof(struct in_addr)); 48524814Skarels break; 48624814Skarels } 48724814Skarels } 48837318Skarels if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 48937318Skarels goto bad; 49026036Skarels *pcbopt = m; 49124814Skarels return (0); 49224814Skarels 49324814Skarels bad: 49426385Skarels (void)m_free(m); 49524814Skarels return (EINVAL); 49624814Skarels } 497