1*5770Swnj /* ip_output.c 1.24 82/02/12 */ 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" 85085Swnj #include "../net/in.h" 95085Swnj #include "../net/in_systm.h" 105085Swnj #include "../net/if.h" 114802Swnj #include "../net/ip.h" 124899Swnj #include "../net/ip_var.h" 134496Swnj 145085Swnj ip_output(m, opt) 154924Swnj struct mbuf *m; 165085Swnj struct mbuf *opt; 174496Swnj { 184924Swnj register struct ip *ip = mtod(m, struct ip *); 195085Swnj register struct ifnet *ifp; 205219Swnj int len, hlen = sizeof (struct ip), off; 214496Swnj 224496Swnj COUNT(IP_OUTPUT); 235219Swnj if (opt) /* XXX */ 245242Sroot (void) m_free(opt); /* XXX */ 254924Swnj /* 264924Swnj * Fill in IP header. 274924Swnj */ 284924Swnj ip->ip_v = IPVERSION; 294924Swnj ip->ip_hl = hlen >> 2; 304924Swnj ip->ip_off &= IP_DF; 315085Swnj ip->ip_id = htons(ip_id++); 324496Swnj 334545Swnj /* 345085Swnj * Find interface for this packet. 355085Swnj */ 365085Swnj ifp = if_ifonnetof(ip->ip_dst); 375085Swnj if (ifp == 0) { 385085Swnj ifp = if_gatewayfor(ip->ip_dst); 395085Swnj if (ifp == 0) 405085Swnj goto bad; 415085Swnj } 425085Swnj 435085Swnj /* 444924Swnj * If small enough for interface, can just send directly. 454545Swnj */ 465085Swnj if (ip->ip_len <= ifp->if_mtu) { 475219Swnj #if vax 485085Swnj ip->ip_len = htons((u_short)ip->ip_len); 495085Swnj ip->ip_off = htons((u_short)ip->ip_off); 505219Swnj #endif 515085Swnj ip->ip_sum = 0; 525085Swnj ip->ip_sum = in_cksum(m, hlen); 535085Swnj return ((*ifp->if_output)(ifp, m, PF_INET)); 544908Swnj } 554924Swnj 564924Swnj /* 574924Swnj * Too large for interface; fragment if possible. 584924Swnj * Must be able to put at least 8 bytes per fragment. 594924Swnj */ 604924Swnj if (ip->ip_off & IP_DF) 614924Swnj goto bad; 625085Swnj len = (ifp->if_mtu - hlen) &~ 7; 634924Swnj if (len < 8) 644924Swnj goto bad; 654924Swnj 664924Swnj /* 674924Swnj * Discard IP header from logical mbuf for m_copy's sake. 684924Swnj * Loop through length of segment, make a copy of each 694924Swnj * part and output. 704924Swnj */ 714924Swnj m->m_len -= sizeof (struct ip); 724924Swnj m->m_off += sizeof (struct ip); 734924Swnj for (off = 0; off < ip->ip_len; off += len) { 745584Sroot struct mbuf *mh = m_get(M_DONTWAIT); 754924Swnj struct ip *mhip; 764924Swnj 774924Swnj if (mh == 0) 784924Swnj goto bad; 794924Swnj mh->m_off = MMAXOFF - hlen; 804924Swnj mhip = mtod(mh, struct ip *); 814924Swnj *mhip = *ip; 824952Swnj if (hlen > sizeof (struct ip)) { 834924Swnj int olen = ip_optcopy(ip, mhip, off); 844924Swnj mh->m_len = sizeof (struct ip) + olen; 854924Swnj } else 864924Swnj mh->m_len = sizeof (struct ip); 87*5770Swnj mhip->ip_off = off >> 3; 884924Swnj if (off + len >= ip->ip_len) 89*5770Swnj len = mhip->ip_len = ip->ip_len - off; 904924Swnj else { 914924Swnj mhip->ip_len = len; 924924Swnj mhip->ip_off |= IP_MF; 934496Swnj } 94*5770Swnj mhip->ip_len += sizeof (struct ip); 95*5770Swnj #if vax 96*5770Swnj mhip->ip_len = htons((u_short)mhip->ip_len); 97*5770Swnj #endif 984924Swnj mh->m_next = m_copy(m, off, len); 994924Swnj if (mh->m_next == 0) { 1004967Swnj (void) m_free(mh); 1014924Swnj goto bad; 1024674Swnj } 103*5770Swnj #if vax 1045085Swnj ip->ip_off = htons((u_short)ip->ip_off); 105*5770Swnj #endif 1065085Swnj ip->ip_sum = 0; 1075085Swnj ip->ip_sum = in_cksum(m, hlen); 1085085Swnj if ((*ifp->if_output)(ifp, mh, PF_INET) == 0) 1095085Swnj goto bad; 1104924Swnj } 1115085Swnj m_freem(m); 1125085Swnj return (1); 1134924Swnj bad: 1144924Swnj m_freem(m); 1155085Swnj return (0); 1164924Swnj } 1174924Swnj 1184924Swnj /* 1194924Swnj * Copy options from ip to jp. 1204952Swnj * If off is 0 all options are copied 1214924Swnj * otherwise copy selectively. 1224924Swnj */ 1234924Swnj ip_optcopy(ip, jp, off) 1244924Swnj struct ip *ip, *jp; 1254924Swnj int off; 1264924Swnj { 1274924Swnj register u_char *cp, *dp; 1284924Swnj int opt, optlen, cnt; 1294924Swnj 1304952Swnj COUNT(IP_OPTCOPY); 1314924Swnj cp = (u_char *)(ip + 1); 1324924Swnj dp = (u_char *)(jp + 1); 1334924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1344924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1354924Swnj opt = cp[0]; 1364924Swnj if (opt == IPOPT_EOL) 1374924Swnj break; 1384924Swnj if (opt == IPOPT_NOP) 1394924Swnj optlen = 1; 1404924Swnj else 1414924Swnj optlen = cp[1]; 1424924Swnj if (optlen > cnt) /* XXX */ 1434924Swnj optlen = cnt; /* XXX */ 1444924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1454952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1464924Swnj dp += optlen; 1474674Swnj } 1484545Swnj } 1494924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1504924Swnj *dp++ = IPOPT_EOL; 1514924Swnj return (optlen); 1524496Swnj } 153