1*6339Ssam /* ip_output.c 1.27 82/03/28 */ 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" 13*6339Ssam #include "../net/route.h" 144496Swnj 15*6339Ssam ip_output(m, opt, ro, allowbroadcast) 164924Swnj struct mbuf *m; 175085Swnj struct mbuf *opt; 18*6339Ssam struct route *ro; 196211Swnj int allowbroadcast; 204496Swnj { 214924Swnj register struct ip *ip = mtod(m, struct ip *); 225085Swnj register struct ifnet *ifp; 235219Swnj int len, hlen = sizeof (struct ip), off; 24*6339Ssam struct sockaddr_in tempaddr; /* temp kludge */ 25*6339Ssam struct route iproute; 264496Swnj 274496Swnj COUNT(IP_OUTPUT); 285219Swnj if (opt) /* XXX */ 295242Sroot (void) m_free(opt); /* XXX */ 304924Swnj /* 314924Swnj * Fill in IP header. 324924Swnj */ 334924Swnj ip->ip_v = IPVERSION; 344924Swnj ip->ip_hl = hlen >> 2; 354924Swnj ip->ip_off &= IP_DF; 365085Swnj ip->ip_id = htons(ip_id++); 374496Swnj 38*6339Ssam #ifdef notdef 394545Swnj /* 405085Swnj * Find interface for this packet. 415085Swnj */ 42*6339Ssam if (ro == 0) { 43*6339Ssam ro = &iproute; 44*6339Ssam bzero((caddr_t)ro, sizeof (*ro)); 455085Swnj } 46*6339Ssam if (ro->ro_rt == 0) { 47*6339Ssam ro->ro_dest.sin_addr = ip->ip_dst; 48*6339Ssam ro->ro_dest.sin_family = AF_INET; 49*6339Ssam route(ro); 50*6339Ssam } 51*6339Ssam if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) 526211Swnj goto bad; 53*6339Ssam #else 54*6339Ssam /* interim kludge before routing fallout */ 55*6339Ssam ifp = if_ifonnetof(ip->ip_dst.s_net); 56*6339Ssam if (ifp == 0) 57*6339Ssam goto bad; 58*6339Ssam tempaddr.sin_family = AF_INET; 59*6339Ssam tempaddr.sin_addr = ip->ip_dst; 60*6339Ssam #endif 615085Swnj 62*6339Ssam if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { 63*6339Ssam struct sockaddr_in *sin; 64*6339Ssam 65*6339Ssam sin = (struct sockaddr_in *)&ifp->if_broadaddr; 66*6339Ssam if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) 67*6339Ssam goto bad; 68*6339Ssam } 69*6339Ssam 705085Swnj /* 714924Swnj * If small enough for interface, can just send directly. 724545Swnj */ 735085Swnj if (ip->ip_len <= ifp->if_mtu) { 745219Swnj #if vax 755085Swnj ip->ip_len = htons((u_short)ip->ip_len); 765085Swnj ip->ip_off = htons((u_short)ip->ip_off); 775219Swnj #endif 785085Swnj ip->ip_sum = 0; 795085Swnj ip->ip_sum = in_cksum(m, hlen); 80*6339Ssam return ((*ifp->if_output)(ifp, m, 81*6339Ssam #ifdef notdef 82*6339Ssam &ro->ro_rt->rt_dest)); 83*6339Ssam #else 84*6339Ssam (struct sockaddr *)&tempaddr)); 85*6339Ssam #endif 864908Swnj } 874924Swnj 884924Swnj /* 894924Swnj * Too large for interface; fragment if possible. 904924Swnj * Must be able to put at least 8 bytes per fragment. 914924Swnj */ 924924Swnj if (ip->ip_off & IP_DF) 934924Swnj goto bad; 945085Swnj len = (ifp->if_mtu - hlen) &~ 7; 954924Swnj if (len < 8) 964924Swnj goto bad; 974924Swnj 984924Swnj /* 994924Swnj * Discard IP header from logical mbuf for m_copy's sake. 1004924Swnj * Loop through length of segment, make a copy of each 1014924Swnj * part and output. 1024924Swnj */ 1034924Swnj m->m_len -= sizeof (struct ip); 1044924Swnj m->m_off += sizeof (struct ip); 1055892Sroot for (off = 0; off < ip->ip_len-hlen; off += len) { 1065584Sroot struct mbuf *mh = m_get(M_DONTWAIT); 1074924Swnj struct ip *mhip; 1084924Swnj 1094924Swnj if (mh == 0) 1104924Swnj goto bad; 1114924Swnj mh->m_off = MMAXOFF - hlen; 1124924Swnj mhip = mtod(mh, struct ip *); 1134924Swnj *mhip = *ip; 1144952Swnj if (hlen > sizeof (struct ip)) { 1154924Swnj int olen = ip_optcopy(ip, mhip, off); 1164924Swnj mh->m_len = sizeof (struct ip) + olen; 1174924Swnj } else 1184924Swnj mh->m_len = sizeof (struct ip); 1195770Swnj mhip->ip_off = off >> 3; 1205892Sroot if (off + len >= ip->ip_len-hlen) 1215892Sroot len = mhip->ip_len = ip->ip_len - hlen - off; 1224924Swnj else { 1234924Swnj mhip->ip_len = len; 1244924Swnj mhip->ip_off |= IP_MF; 1254496Swnj } 1265770Swnj mhip->ip_len += sizeof (struct ip); 1275770Swnj #if vax 1285770Swnj mhip->ip_len = htons((u_short)mhip->ip_len); 1295770Swnj #endif 1304924Swnj mh->m_next = m_copy(m, off, len); 1314924Swnj if (mh->m_next == 0) { 1324967Swnj (void) m_free(mh); 1334924Swnj goto bad; 1344674Swnj } 1355770Swnj #if vax 1365892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 1375770Swnj #endif 1385892Sroot mhip->ip_sum = 0; 1395892Sroot mhip->ip_sum = in_cksum(mh, hlen); 140*6339Ssam if ((*ifp->if_output)(ifp, mh, 141*6339Ssam #ifdef notdef 142*6339Ssam &ro->ro_rt->rt_dest) == 0) 143*6339Ssam #else 144*6339Ssam (struct sockaddr *)&tempaddr) == 0) 145*6339Ssam #endif 1465085Swnj goto bad; 1474924Swnj } 1485085Swnj m_freem(m); 1495085Swnj return (1); 1504924Swnj bad: 1514924Swnj m_freem(m); 1525085Swnj return (0); 1534924Swnj } 1544924Swnj 1554924Swnj /* 1564924Swnj * Copy options from ip to jp. 1574952Swnj * If off is 0 all options are copied 1584924Swnj * otherwise copy selectively. 1594924Swnj */ 1604924Swnj ip_optcopy(ip, jp, off) 1614924Swnj struct ip *ip, *jp; 1624924Swnj int off; 1634924Swnj { 1644924Swnj register u_char *cp, *dp; 1654924Swnj int opt, optlen, cnt; 1664924Swnj 1674952Swnj COUNT(IP_OPTCOPY); 1684924Swnj cp = (u_char *)(ip + 1); 1694924Swnj dp = (u_char *)(jp + 1); 1704924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1714924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1724924Swnj opt = cp[0]; 1734924Swnj if (opt == IPOPT_EOL) 1744924Swnj break; 1754924Swnj if (opt == IPOPT_NOP) 1764924Swnj optlen = 1; 1774924Swnj else 1784924Swnj optlen = cp[1]; 1794924Swnj if (optlen > cnt) /* XXX */ 1804924Swnj optlen = cnt; /* XXX */ 1814924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1824952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1834924Swnj dp += optlen; 1844674Swnj } 1854545Swnj } 1864924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1874924Swnj *dp++ = IPOPT_EOL; 1884924Swnj return (optlen); 1894496Swnj } 190