1*6351Ssam /* ip_output.c 1.28 82/03/29 */ 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" 136339Ssam #include "../net/route.h" 144496Swnj 156339Ssam ip_output(m, opt, ro, allowbroadcast) 164924Swnj struct mbuf *m; 175085Swnj struct mbuf *opt; 186339Ssam struct route *ro; 196211Swnj int allowbroadcast; 204496Swnj { 214924Swnj register struct ip *ip = mtod(m, struct ip *); 225085Swnj register struct ifnet *ifp; 23*6351Ssam int len, hlen = sizeof (struct ip), off, direct; 246339Ssam struct sockaddr_in tempaddr; /* temp kludge */ 256339Ssam struct route iproute; 26*6351Ssam struct sockaddr *dst; 274496Swnj 284496Swnj COUNT(IP_OUTPUT); 295219Swnj if (opt) /* XXX */ 305242Sroot (void) m_free(opt); /* XXX */ 314924Swnj /* 324924Swnj * Fill in IP header. 334924Swnj */ 344924Swnj ip->ip_v = IPVERSION; 354924Swnj ip->ip_hl = hlen >> 2; 364924Swnj ip->ip_off &= IP_DF; 375085Swnj ip->ip_id = htons(ip_id++); 384496Swnj 396339Ssam #ifdef notdef 404545Swnj /* 41*6351Ssam * Find interface for this packet in the routing 42*6351Ssam * table. Note each interface has placed itself 43*6351Ssam * in there at boot time, so call on route degenerates 44*6351Ssam * to if_ifonnetof(ip->ip_dst.s_net). 455085Swnj */ 466339Ssam if (ro == 0) { 476339Ssam ro = &iproute; 486339Ssam bzero((caddr_t)ro, sizeof (*ro)); 495085Swnj } 506339Ssam if (ro->ro_rt == 0) { 516339Ssam ro->ro_dest.sin_addr = ip->ip_dst; 526339Ssam ro->ro_dest.sin_family = AF_INET; 53*6351Ssam direct = allocroute(ro); 546339Ssam } 556339Ssam if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) 566211Swnj goto bad; 57*6351Ssam dst = direct ? (struct sockaddr *)&ro->ro_dest : 58*6351Ssam &ro->ro_rt->rt_gateway; 596339Ssam #else 606339Ssam /* interim kludge before routing fallout */ 616339Ssam ifp = if_ifonnetof(ip->ip_dst.s_net); 626339Ssam if (ifp == 0) 636339Ssam goto bad; 646339Ssam tempaddr.sin_family = AF_INET; 656339Ssam tempaddr.sin_addr = ip->ip_dst; 666339Ssam #endif 675085Swnj 686339Ssam if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { 696339Ssam struct sockaddr_in *sin; 706339Ssam 716339Ssam sin = (struct sockaddr_in *)&ifp->if_broadaddr; 726339Ssam if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) 736339Ssam goto bad; 746339Ssam } 756339Ssam 765085Swnj /* 774924Swnj * If small enough for interface, can just send directly. 784545Swnj */ 795085Swnj if (ip->ip_len <= ifp->if_mtu) { 805219Swnj #if vax 815085Swnj ip->ip_len = htons((u_short)ip->ip_len); 825085Swnj ip->ip_off = htons((u_short)ip->ip_off); 835219Swnj #endif 845085Swnj ip->ip_sum = 0; 855085Swnj ip->ip_sum = in_cksum(m, hlen); 866339Ssam #ifdef notdef 87*6351Ssam return ((*ifp->if_output)(ifp, m, dst)); 886339Ssam #else 89*6351Ssam return ((*ifp->if_output)(ifp, m, 90*6351Ssam (struct sockaddr *)&tempaddr)); 916339Ssam #endif 924908Swnj } 934924Swnj 944924Swnj /* 954924Swnj * Too large for interface; fragment if possible. 964924Swnj * Must be able to put at least 8 bytes per fragment. 974924Swnj */ 984924Swnj if (ip->ip_off & IP_DF) 994924Swnj goto bad; 1005085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1014924Swnj if (len < 8) 1024924Swnj goto bad; 1034924Swnj 1044924Swnj /* 1054924Swnj * Discard IP header from logical mbuf for m_copy's sake. 1064924Swnj * Loop through length of segment, make a copy of each 1074924Swnj * part and output. 1084924Swnj */ 1094924Swnj m->m_len -= sizeof (struct ip); 1104924Swnj m->m_off += sizeof (struct ip); 1115892Sroot for (off = 0; off < ip->ip_len-hlen; off += len) { 1125584Sroot struct mbuf *mh = m_get(M_DONTWAIT); 1134924Swnj struct ip *mhip; 1144924Swnj 1154924Swnj if (mh == 0) 1164924Swnj goto bad; 1174924Swnj mh->m_off = MMAXOFF - hlen; 1184924Swnj mhip = mtod(mh, struct ip *); 1194924Swnj *mhip = *ip; 1204952Swnj if (hlen > sizeof (struct ip)) { 1214924Swnj int olen = ip_optcopy(ip, mhip, off); 1224924Swnj mh->m_len = sizeof (struct ip) + olen; 1234924Swnj } else 1244924Swnj mh->m_len = sizeof (struct ip); 1255770Swnj mhip->ip_off = off >> 3; 1265892Sroot if (off + len >= ip->ip_len-hlen) 1275892Sroot len = mhip->ip_len = ip->ip_len - hlen - off; 1284924Swnj else { 1294924Swnj mhip->ip_len = len; 1304924Swnj mhip->ip_off |= IP_MF; 1314496Swnj } 1325770Swnj mhip->ip_len += sizeof (struct ip); 1335770Swnj #if vax 1345770Swnj mhip->ip_len = htons((u_short)mhip->ip_len); 1355770Swnj #endif 1364924Swnj mh->m_next = m_copy(m, off, len); 1374924Swnj if (mh->m_next == 0) { 1384967Swnj (void) m_free(mh); 1394924Swnj goto bad; 1404674Swnj } 1415770Swnj #if vax 1425892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 1435770Swnj #endif 1445892Sroot mhip->ip_sum = 0; 1455892Sroot mhip->ip_sum = in_cksum(mh, hlen); 1466339Ssam #ifdef notdef 147*6351Ssam if ((*ifp->if_output)(ifp, mh, dst) == 0) 1486339Ssam #else 149*6351Ssam if ((*ifp->if_output)(ifp, mh, 150*6351Ssam (struct sockaddr *)&tempaddr) == 0) 1516339Ssam #endif 1525085Swnj goto bad; 1534924Swnj } 1545085Swnj m_freem(m); 1555085Swnj return (1); 1564924Swnj bad: 1574924Swnj m_freem(m); 1585085Swnj return (0); 1594924Swnj } 1604924Swnj 1614924Swnj /* 1624924Swnj * Copy options from ip to jp. 1634952Swnj * If off is 0 all options are copied 1644924Swnj * otherwise copy selectively. 1654924Swnj */ 1664924Swnj ip_optcopy(ip, jp, off) 1674924Swnj struct ip *ip, *jp; 1684924Swnj int off; 1694924Swnj { 1704924Swnj register u_char *cp, *dp; 1714924Swnj int opt, optlen, cnt; 1724924Swnj 1734952Swnj COUNT(IP_OPTCOPY); 1744924Swnj cp = (u_char *)(ip + 1); 1754924Swnj dp = (u_char *)(jp + 1); 1764924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1774924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1784924Swnj opt = cp[0]; 1794924Swnj if (opt == IPOPT_EOL) 1804924Swnj break; 1814924Swnj if (opt == IPOPT_NOP) 1824924Swnj optlen = 1; 1834924Swnj else 1844924Swnj optlen = cp[1]; 1854924Swnj if (optlen > cnt) /* XXX */ 1864924Swnj optlen = cnt; /* XXX */ 1874924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1884952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1894924Swnj dp += optlen; 1904674Swnj } 1914545Swnj } 1924924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1934924Swnj *dp++ = IPOPT_EOL; 1944924Swnj return (optlen); 1954496Swnj } 196