1*5085Swnj /* ip_output.c 1.20 81/11/26 */ 24571Swnj 34496Swnj #include "../h/param.h" 44662Swnj #include "../h/mbuf.h" 54724Swnj #include "../h/mtpr.h" 64662Swnj #include "../h/socket.h" 74924Swnj #include "../h/socketvar.h" 8*5085Swnj #include "../net/in.h" 9*5085Swnj #include "../net/in_systm.h" 10*5085Swnj #include "../net/if.h" 114802Swnj #include "../net/ip.h" 124899Swnj #include "../net/ip_var.h" 134496Swnj 14*5085Swnj ip_output(m, opt) 154924Swnj struct mbuf *m; 16*5085Swnj struct mbuf *opt; 174496Swnj { 184924Swnj register struct ip *ip = mtod(m, struct ip *); 19*5085Swnj register struct ifnet *ifp; 204924Swnj int len, hlen = ip->ip_hl << 2, off; 214496Swnj 224496Swnj COUNT(IP_OUTPUT); 234924Swnj /* 244924Swnj * Fill in IP header. 254924Swnj */ 264924Swnj ip->ip_v = IPVERSION; 274924Swnj ip->ip_hl = hlen >> 2; 284924Swnj ip->ip_off &= IP_DF; 29*5085Swnj ip->ip_id = htons(ip_id++); 304496Swnj 314545Swnj /* 32*5085Swnj * Find interface for this packet. 33*5085Swnj */ 34*5085Swnj ifp = if_ifonnetof(ip->ip_dst); 35*5085Swnj if (ifp == 0) { 36*5085Swnj ifp = if_gatewayfor(ip->ip_dst); 37*5085Swnj if (ifp == 0) 38*5085Swnj goto bad; 39*5085Swnj } 40*5085Swnj 41*5085Swnj /* 424924Swnj * If small enough for interface, can just send directly. 434545Swnj */ 44*5085Swnj if (ip->ip_len <= ifp->if_mtu) { 45*5085Swnj ip->ip_len = htons((u_short)ip->ip_len); 46*5085Swnj ip->ip_off = htons((u_short)ip->ip_off); 47*5085Swnj ip->ip_sum = 0; 48*5085Swnj ip->ip_sum = in_cksum(m, hlen); 49*5085Swnj return ((*ifp->if_output)(ifp, m, PF_INET)); 504908Swnj } 514924Swnj 524924Swnj /* 534924Swnj * Too large for interface; fragment if possible. 544924Swnj * Must be able to put at least 8 bytes per fragment. 554924Swnj */ 564924Swnj if (ip->ip_off & IP_DF) 574924Swnj goto bad; 58*5085Swnj len = (ifp->if_mtu - hlen) &~ 7; 594924Swnj if (len < 8) 604924Swnj goto bad; 614924Swnj 624924Swnj /* 634924Swnj * Discard IP header from logical mbuf for m_copy's sake. 644924Swnj * Loop through length of segment, make a copy of each 654924Swnj * part and output. 664924Swnj */ 674924Swnj m->m_len -= sizeof (struct ip); 684924Swnj m->m_off += sizeof (struct ip); 694924Swnj for (off = 0; off < ip->ip_len; off += len) { 704924Swnj struct mbuf *mh = m_get(0); 714924Swnj struct ip *mhip; 724924Swnj 734924Swnj if (mh == 0) 744924Swnj goto bad; 754924Swnj mh->m_off = MMAXOFF - hlen; 764924Swnj mhip = mtod(mh, struct ip *); 774924Swnj *mhip = *ip; 784952Swnj if (hlen > sizeof (struct ip)) { 794924Swnj int olen = ip_optcopy(ip, mhip, off); 804924Swnj mh->m_len = sizeof (struct ip) + olen; 814924Swnj } else 824924Swnj mh->m_len = sizeof (struct ip); 834924Swnj mhip->ip_off = off; 844924Swnj if (off + len >= ip->ip_len) 854924Swnj mhip->ip_len = ip->ip_len - off; 864924Swnj else { 874924Swnj mhip->ip_len = len; 884924Swnj mhip->ip_off |= IP_MF; 894496Swnj } 90*5085Swnj mhip->ip_len = htons((u_short)(mhip->ip_len + sizeof (struct ip))); 914924Swnj mh->m_next = m_copy(m, off, len); 924924Swnj if (mh->m_next == 0) { 934967Swnj (void) m_free(mh); 944924Swnj goto bad; 954674Swnj } 96*5085Swnj ip->ip_off = htons((u_short)ip->ip_off); 97*5085Swnj ip->ip_sum = 0; 98*5085Swnj ip->ip_sum = in_cksum(m, hlen); 99*5085Swnj if ((*ifp->if_output)(ifp, mh, PF_INET) == 0) 100*5085Swnj goto bad; 1014924Swnj } 102*5085Swnj m_freem(m); 103*5085Swnj return (1); 1044924Swnj bad: 1054924Swnj m_freem(m); 106*5085Swnj return (0); 1074924Swnj } 1084924Swnj 1094924Swnj /* 1104924Swnj * Copy options from ip to jp. 1114952Swnj * If off is 0 all options are copied 1124924Swnj * otherwise copy selectively. 1134924Swnj */ 1144924Swnj ip_optcopy(ip, jp, off) 1154924Swnj struct ip *ip, *jp; 1164924Swnj int off; 1174924Swnj { 1184924Swnj register u_char *cp, *dp; 1194924Swnj int opt, optlen, cnt; 1204924Swnj 1214952Swnj COUNT(IP_OPTCOPY); 1224924Swnj cp = (u_char *)(ip + 1); 1234924Swnj dp = (u_char *)(jp + 1); 1244924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1254924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1264924Swnj opt = cp[0]; 1274924Swnj if (opt == IPOPT_EOL) 1284924Swnj break; 1294924Swnj if (opt == IPOPT_NOP) 1304924Swnj optlen = 1; 1314924Swnj else 1324924Swnj optlen = cp[1]; 1334924Swnj if (optlen > cnt) /* XXX */ 1344924Swnj optlen = cnt; /* XXX */ 1354924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1364952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1374924Swnj dp += optlen; 1384674Swnj } 1394545Swnj } 1404924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1414924Swnj *dp++ = IPOPT_EOL; 1424924Swnj return (optlen); 1434496Swnj } 144