1*6211Swnj /* ip_output.c 1.26 82/03/15 */ 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 14*6211Swnj ip_output(m, opt, allowbroadcast) 154924Swnj struct mbuf *m; 165085Swnj struct mbuf *opt; 17*6211Swnj int allowbroadcast; 184496Swnj { 194924Swnj register struct ip *ip = mtod(m, struct ip *); 205085Swnj register struct ifnet *ifp; 215219Swnj int len, hlen = sizeof (struct ip), off; 224496Swnj 234496Swnj COUNT(IP_OUTPUT); 245219Swnj if (opt) /* XXX */ 255242Sroot (void) m_free(opt); /* XXX */ 264924Swnj /* 274924Swnj * Fill in IP header. 284924Swnj */ 294924Swnj ip->ip_v = IPVERSION; 304924Swnj ip->ip_hl = hlen >> 2; 314924Swnj ip->ip_off &= IP_DF; 325085Swnj ip->ip_id = htons(ip_id++); 334496Swnj 344545Swnj /* 355085Swnj * Find interface for this packet. 365085Swnj */ 375085Swnj ifp = if_ifonnetof(ip->ip_dst); 385085Swnj if (ifp == 0) { 395085Swnj ifp = if_gatewayfor(ip->ip_dst); 405085Swnj if (ifp == 0) 415085Swnj goto bad; 425085Swnj } 43*6211Swnj if (!allowbroadcast && ifp->if_broadaddr.s_addr != 0 && 44*6211Swnj ifp->if_broadaddr.s_addr == ip->ip_dst.s_addr) 45*6211Swnj goto bad; 465085Swnj 475085Swnj /* 484924Swnj * If small enough for interface, can just send directly. 494545Swnj */ 505085Swnj if (ip->ip_len <= ifp->if_mtu) { 515219Swnj #if vax 525085Swnj ip->ip_len = htons((u_short)ip->ip_len); 535085Swnj ip->ip_off = htons((u_short)ip->ip_off); 545219Swnj #endif 555085Swnj ip->ip_sum = 0; 565085Swnj ip->ip_sum = in_cksum(m, hlen); 575085Swnj return ((*ifp->if_output)(ifp, m, PF_INET)); 584908Swnj } 594924Swnj 604924Swnj /* 614924Swnj * Too large for interface; fragment if possible. 624924Swnj * Must be able to put at least 8 bytes per fragment. 634924Swnj */ 644924Swnj if (ip->ip_off & IP_DF) 654924Swnj goto bad; 665085Swnj len = (ifp->if_mtu - hlen) &~ 7; 674924Swnj if (len < 8) 684924Swnj goto bad; 694924Swnj 704924Swnj /* 714924Swnj * Discard IP header from logical mbuf for m_copy's sake. 724924Swnj * Loop through length of segment, make a copy of each 734924Swnj * part and output. 744924Swnj */ 754924Swnj m->m_len -= sizeof (struct ip); 764924Swnj m->m_off += sizeof (struct ip); 775892Sroot for (off = 0; off < ip->ip_len-hlen; off += len) { 785584Sroot struct mbuf *mh = m_get(M_DONTWAIT); 794924Swnj struct ip *mhip; 804924Swnj 814924Swnj if (mh == 0) 824924Swnj goto bad; 834924Swnj mh->m_off = MMAXOFF - hlen; 844924Swnj mhip = mtod(mh, struct ip *); 854924Swnj *mhip = *ip; 864952Swnj if (hlen > sizeof (struct ip)) { 874924Swnj int olen = ip_optcopy(ip, mhip, off); 884924Swnj mh->m_len = sizeof (struct ip) + olen; 894924Swnj } else 904924Swnj mh->m_len = sizeof (struct ip); 915770Swnj mhip->ip_off = off >> 3; 925892Sroot if (off + len >= ip->ip_len-hlen) 935892Sroot len = mhip->ip_len = ip->ip_len - hlen - off; 944924Swnj else { 954924Swnj mhip->ip_len = len; 964924Swnj mhip->ip_off |= IP_MF; 974496Swnj } 985770Swnj mhip->ip_len += sizeof (struct ip); 995770Swnj #if vax 1005770Swnj mhip->ip_len = htons((u_short)mhip->ip_len); 1015770Swnj #endif 1024924Swnj mh->m_next = m_copy(m, off, len); 1034924Swnj if (mh->m_next == 0) { 1044967Swnj (void) m_free(mh); 1054924Swnj goto bad; 1064674Swnj } 1075770Swnj #if vax 1085892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 1095770Swnj #endif 1105892Sroot mhip->ip_sum = 0; 1115892Sroot mhip->ip_sum = in_cksum(mh, hlen); 1125085Swnj if ((*ifp->if_output)(ifp, mh, PF_INET) == 0) 1135085Swnj goto bad; 1144924Swnj } 1155085Swnj m_freem(m); 1165085Swnj return (1); 1174924Swnj bad: 1184924Swnj m_freem(m); 1195085Swnj return (0); 1204924Swnj } 1214924Swnj 1224924Swnj /* 1234924Swnj * Copy options from ip to jp. 1244952Swnj * If off is 0 all options are copied 1254924Swnj * otherwise copy selectively. 1264924Swnj */ 1274924Swnj ip_optcopy(ip, jp, off) 1284924Swnj struct ip *ip, *jp; 1294924Swnj int off; 1304924Swnj { 1314924Swnj register u_char *cp, *dp; 1324924Swnj int opt, optlen, cnt; 1334924Swnj 1344952Swnj COUNT(IP_OPTCOPY); 1354924Swnj cp = (u_char *)(ip + 1); 1364924Swnj dp = (u_char *)(jp + 1); 1374924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1384924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1394924Swnj opt = cp[0]; 1404924Swnj if (opt == IPOPT_EOL) 1414924Swnj break; 1424924Swnj if (opt == IPOPT_NOP) 1434924Swnj optlen = 1; 1444924Swnj else 1454924Swnj optlen = cp[1]; 1464924Swnj if (optlen > cnt) /* XXX */ 1474924Swnj optlen = cnt; /* XXX */ 1484924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1494952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1504924Swnj dp += optlen; 1514674Swnj } 1524545Swnj } 1534924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1544924Swnj *dp++ = IPOPT_EOL; 1554924Swnj return (optlen); 1564496Swnj } 157