1*7155Swnj /* ip_output.c 1.33 82/06/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" 136339Ssam #include "../net/route.h" 146505Ssam #include <errno.h> 154496Swnj 16*7155Swnj int ipnorouteprint = 0; 17*7155Swnj 186339Ssam ip_output(m, opt, ro, allowbroadcast) 194924Swnj struct mbuf *m; 205085Swnj struct mbuf *opt; 216339Ssam struct route *ro; 226211Swnj int allowbroadcast; 234496Swnj { 244924Swnj register struct ip *ip = mtod(m, struct ip *); 255085Swnj register struct ifnet *ifp; 266505Ssam int len, hlen = sizeof (struct ip), off, error = 0; 276339Ssam struct route iproute; 286351Ssam struct sockaddr *dst; 294496Swnj 304496Swnj COUNT(IP_OUTPUT); 315219Swnj if (opt) /* XXX */ 325242Sroot (void) m_free(opt); /* XXX */ 334924Swnj /* 344924Swnj * Fill in IP header. 354924Swnj */ 364924Swnj ip->ip_v = IPVERSION; 374924Swnj ip->ip_hl = hlen >> 2; 384924Swnj ip->ip_off &= IP_DF; 395085Swnj ip->ip_id = htons(ip_id++); 404496Swnj 414545Swnj /* 42*7155Swnj * Route packet. 435085Swnj */ 446339Ssam if (ro == 0) { 456339Ssam ro = &iproute; 466339Ssam bzero((caddr_t)ro, sizeof (*ro)); 475085Swnj } 48*7155Swnj dst = &ro->ro_dst; 496339Ssam if (ro->ro_rt == 0) { 506368Ssam ro->ro_dst.sa_family = AF_INET; 516368Ssam ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = ip->ip_dst; 52*7155Swnj /* 53*7155Swnj * If routing to interface only, short circuit routing lookup. 54*7155Swnj */ 55*7155Swnj if (ro == &routetoif) { 56*7155Swnj /* check ifp is AF_INET??? */ 57*7155Swnj ifp = if_ifonnetof(ip->ip_dst.s_net); 58*7155Swnj if (ifp == 0) 59*7155Swnj goto unreachable; 60*7155Swnj goto gotif; 61*7155Swnj } 626368Ssam rtalloc(ro); 636339Ssam } 64*7155Swnj if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) 65*7155Swnj goto unreachable; 66*7155Swnj ro->ro_rt->rt_use++; 67*7155Swnj if (ro->ro_rt->rt_flags & RTF_GATEWAY) 68*7155Swnj dst = &ro->ro_rt->rt_gateway; 69*7155Swnj gotif: 70*7155Swnj /* 71*7155Swnj * If source address not specified yet, use address 72*7155Swnj * of outgoing interface. 73*7155Swnj */ 74*7155Swnj if (ip->ip_src.s_addr == 0) 75*7155Swnj ip->ip_src.s_addr = 76*7155Swnj ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr; 776505Ssam 78*7155Swnj /* 79*7155Swnj * Have interface for packet. Allow 80*7155Swnj * broadcasts only by authorized users. 81*7155Swnj */ 826339Ssam if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { 836339Ssam struct sockaddr_in *sin; 846339Ssam 856339Ssam sin = (struct sockaddr_in *)&ifp->if_broadaddr; 866505Ssam if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) { 87*7155Swnj error = EACCES; 886339Ssam goto bad; 896505Ssam } 906339Ssam } 916339Ssam 925085Swnj /* 934924Swnj * If small enough for interface, can just send directly. 944545Swnj */ 955085Swnj if (ip->ip_len <= ifp->if_mtu) { 965219Swnj #if vax 975085Swnj ip->ip_len = htons((u_short)ip->ip_len); 985085Swnj ip->ip_off = htons((u_short)ip->ip_off); 995219Swnj #endif 1005085Swnj ip->ip_sum = 0; 1015085Swnj ip->ip_sum = in_cksum(m, hlen); 102*7155Swnj error = (*ifp->if_output)(ifp, m, dst); 103*7155Swnj goto done; 1044908Swnj } 1054924Swnj 1064924Swnj /* 1074924Swnj * Too large for interface; fragment if possible. 1084924Swnj * Must be able to put at least 8 bytes per fragment. 1094924Swnj */ 1106505Ssam if (ip->ip_off & IP_DF) { 1116505Ssam error = EMSGSIZE; 1124924Swnj goto bad; 1136505Ssam } 1145085Swnj len = (ifp->if_mtu - hlen) &~ 7; 1156505Ssam if (len < 8) { 1166505Ssam error = EMSGSIZE; 1174924Swnj goto bad; 1186505Ssam } 1194924Swnj 1204924Swnj /* 1214924Swnj * Discard IP header from logical mbuf for m_copy's sake. 1224924Swnj * Loop through length of segment, make a copy of each 1234924Swnj * part and output. 1244924Swnj */ 1254924Swnj m->m_len -= sizeof (struct ip); 1264924Swnj m->m_off += sizeof (struct ip); 1275892Sroot for (off = 0; off < ip->ip_len-hlen; off += len) { 1285584Sroot struct mbuf *mh = m_get(M_DONTWAIT); 1294924Swnj struct ip *mhip; 1304924Swnj 1316505Ssam if (mh == 0) { 1326505Ssam error = ENOBUFS; 1334924Swnj goto bad; 1346505Ssam } 1354924Swnj mh->m_off = MMAXOFF - hlen; 1364924Swnj mhip = mtod(mh, struct ip *); 1374924Swnj *mhip = *ip; 1384952Swnj if (hlen > sizeof (struct ip)) { 1394924Swnj int olen = ip_optcopy(ip, mhip, off); 1404924Swnj mh->m_len = sizeof (struct ip) + olen; 1414924Swnj } else 1424924Swnj mh->m_len = sizeof (struct ip); 1435770Swnj mhip->ip_off = off >> 3; 1445892Sroot if (off + len >= ip->ip_len-hlen) 1455892Sroot len = mhip->ip_len = ip->ip_len - hlen - off; 1464924Swnj else { 1474924Swnj mhip->ip_len = len; 1484924Swnj mhip->ip_off |= IP_MF; 1494496Swnj } 1505770Swnj mhip->ip_len += sizeof (struct ip); 1515770Swnj #if vax 1525770Swnj mhip->ip_len = htons((u_short)mhip->ip_len); 1535770Swnj #endif 1544924Swnj mh->m_next = m_copy(m, off, len); 1554924Swnj if (mh->m_next == 0) { 1564967Swnj (void) m_free(mh); 1576505Ssam error = ENOBUFS; /* ??? */ 1584924Swnj goto bad; 1594674Swnj } 1605770Swnj #if vax 1615892Sroot mhip->ip_off = htons((u_short)mhip->ip_off); 1625770Swnj #endif 1635892Sroot mhip->ip_sum = 0; 1645892Sroot mhip->ip_sum = in_cksum(mh, hlen); 1656505Ssam if (error = (*ifp->if_output)(ifp, mh, dst)) 1666505Ssam break; 1674924Swnj } 168*7155Swnj m_freem(m); 169*7155Swnj goto done; 170*7155Swnj 171*7155Swnj unreachable: 172*7155Swnj if (ipnorouteprint) 173*7155Swnj printf("no route to %x (from %x, len %d)\n", 174*7155Swnj ip->ip_dst.s_addr, ip->ip_src.s_addr, ip->ip_len); 175*7155Swnj error = ENETUNREACH; 1764924Swnj bad: 1774924Swnj m_freem(m); 178*7155Swnj done: 179*7155Swnj if (ro == &iproute && ro->ro_rt) 180*7155Swnj RTFREE(ro->ro_rt); 1816505Ssam return (error); 1824924Swnj } 1834924Swnj 1844924Swnj /* 1854924Swnj * Copy options from ip to jp. 1864952Swnj * If off is 0 all options are copied 1874924Swnj * otherwise copy selectively. 1884924Swnj */ 1894924Swnj ip_optcopy(ip, jp, off) 1904924Swnj struct ip *ip, *jp; 1914924Swnj int off; 1924924Swnj { 1934924Swnj register u_char *cp, *dp; 1944924Swnj int opt, optlen, cnt; 1954924Swnj 1964952Swnj COUNT(IP_OPTCOPY); 1974924Swnj cp = (u_char *)(ip + 1); 1984924Swnj dp = (u_char *)(jp + 1); 1994924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 2004924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 2014924Swnj opt = cp[0]; 2024924Swnj if (opt == IPOPT_EOL) 2034924Swnj break; 2044924Swnj if (opt == IPOPT_NOP) 2054924Swnj optlen = 1; 2064924Swnj else 2074924Swnj optlen = cp[1]; 2084924Swnj if (optlen > cnt) /* XXX */ 2094924Swnj optlen = cnt; /* XXX */ 2104924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 2114952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 2124924Swnj dp += optlen; 2134674Swnj } 2144545Swnj } 2154924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 2164924Swnj *dp++ = IPOPT_EOL; 2174924Swnj return (optlen); 2184496Swnj } 219