1*4924Swnj /* ip_output.c 1.14 81/11/18 */ 24571Swnj 34496Swnj #include "../h/param.h" 44662Swnj #include "../h/mbuf.h" 54724Swnj #include "../h/mtpr.h" 64662Swnj #include "../h/socket.h" 7*4924Swnj #include "../h/socketvar.h" 84802Swnj #include "../net/inet.h" 94802Swnj #include "../net/inet_systm.h" 104802Swnj #include "../net/imp.h" 114802Swnj #include "../net/inet_host.h" 124802Swnj #include "../net/ip.h" 134899Swnj #include "../net/ip_var.h" 144496Swnj 15*4924Swnj ip_output(m) 16*4924Swnj struct mbuf *m; 174496Swnj { 18*4924Swnj register struct ip *ip = mtod(m, struct ip *); 19*4924Swnj int len, hlen = ip->ip_hl << 2, off; 204496Swnj 214496Swnj COUNT(IP_OUTPUT); 22*4924Swnj /* 23*4924Swnj * Fill in IP header. 24*4924Swnj */ 25*4924Swnj ip->ip_v = IPVERSION; 26*4924Swnj ip->ip_hl = hlen >> 2; 27*4924Swnj ip->ip_off &= IP_DF; 28*4924Swnj ip->ip_ttl = MAXTTL; 29*4924Swnj ip->ip_id = ip_id++; 304496Swnj 314545Swnj /* 32*4924Swnj * If small enough for interface, can just send directly. 334545Swnj */ 34*4924Swnj if (ip->ip_len <= MTU) { 35*4924Swnj ip_send(ip); 364908Swnj return; 374908Swnj } 38*4924Swnj 39*4924Swnj /* 40*4924Swnj * Too large for interface; fragment if possible. 41*4924Swnj * Must be able to put at least 8 bytes per fragment. 42*4924Swnj */ 43*4924Swnj if (ip->ip_off & IP_DF) 44*4924Swnj goto bad; 45*4924Swnj len = (MTU-hlen) &~ 7; 46*4924Swnj if (len < 8) 47*4924Swnj goto bad; 48*4924Swnj 49*4924Swnj /* 50*4924Swnj * Discard IP header from logical mbuf for m_copy's sake. 51*4924Swnj * Loop through length of segment, make a copy of each 52*4924Swnj * part and output. 53*4924Swnj */ 54*4924Swnj m->m_len -= sizeof (struct ip); 55*4924Swnj m->m_off += sizeof (struct ip); 56*4924Swnj for (off = 0; off < ip->ip_len; off += len) { 57*4924Swnj struct mbuf *mh = m_get(0); 58*4924Swnj struct ip *mhip; 59*4924Swnj 60*4924Swnj if (mh == 0) 61*4924Swnj goto bad; 62*4924Swnj mh->m_off = MMAXOFF - hlen; 63*4924Swnj mhip = mtod(mh, struct ip *); 64*4924Swnj *mhip = *ip; 65*4924Swnj if (ip->ip_hl > sizeof (struct ip) >> 2) { 66*4924Swnj int olen = ip_optcopy(ip, mhip, off); 67*4924Swnj mh->m_len = sizeof (struct ip) + olen; 68*4924Swnj } else 69*4924Swnj mh->m_len = sizeof (struct ip); 70*4924Swnj mhip->ip_off = off; 71*4924Swnj if (off + len >= ip->ip_len) 72*4924Swnj mhip->ip_len = ip->ip_len - off; 73*4924Swnj else { 74*4924Swnj mhip->ip_len = len; 75*4924Swnj mhip->ip_off |= IP_MF; 764496Swnj } 77*4924Swnj mh->m_next = m_copy(m, off, len); 78*4924Swnj if (mh->m_next == 0) { 79*4924Swnj m_free(mh); 80*4924Swnj goto bad; 814674Swnj } 82*4924Swnj ip_send(mh); 83*4924Swnj } 84*4924Swnj bad: 85*4924Swnj m_freem(m); 86*4924Swnj } 87*4924Swnj 88*4924Swnj /* 89*4924Swnj * Copy options from ip to jp. 90*4924Swnj * If off is 0 all options are copies 91*4924Swnj * otherwise copy selectively. 92*4924Swnj */ 93*4924Swnj ip_optcopy(ip, jp, off) 94*4924Swnj struct ip *ip, *jp; 95*4924Swnj int off; 96*4924Swnj { 97*4924Swnj register u_char *cp, *dp; 98*4924Swnj int opt, optlen, cnt; 99*4924Swnj 100*4924Swnj cp = (u_char *)(ip + 1); 101*4924Swnj dp = (u_char *)(jp + 1); 102*4924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 103*4924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 104*4924Swnj opt = cp[0]; 105*4924Swnj if (opt == IPOPT_EOL) 106*4924Swnj break; 107*4924Swnj if (opt == IPOPT_NOP) 108*4924Swnj optlen = 1; 109*4924Swnj else 110*4924Swnj optlen = cp[1]; 111*4924Swnj if (optlen > cnt) /* XXX */ 112*4924Swnj optlen = cnt; /* XXX */ 113*4924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 114*4924Swnj bcopy(cp, dp, optlen); 115*4924Swnj dp += optlen; 1164674Swnj } 1174545Swnj } 118*4924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 119*4924Swnj *dp++ = IPOPT_EOL; 120*4924Swnj return (optlen); 1214496Swnj } 1224496Swnj 1234693Swnj ip_send(ip) 124*4924Swnj register struct ip *ip; 1254496Swnj { 1264496Swnj register struct mbuf *m; 1274496Swnj register struct imp *l; 128*4924Swnj int hlen = ip->ip_hl << 2; 1294545Swnj int s; 1304496Swnj COUNT(IP_SEND); 1314496Swnj 1324693Swnj m = dtom(ip); 1334908Swnj l = (struct imp *)(mtod(m, caddr_t) - L1822); 1344693Swnj l->i_shost = ip->ip_src.s_host; 1354693Swnj l->i_dhost = ip->ip_dst.s_host; 1364496Swnj l->i_type = IPTYPE; 1374693Swnj ip->ip_sum = 0; 1384908Swnj ip->ip_len = htons((u_short)ip->ip_len); 1394693Swnj ip->ip_id = htons(ip->ip_id); 1404908Swnj ip->ip_off = htons((u_short)ip->ip_off); 141*4924Swnj ip->ip_sum = inet_cksum(m, hlen); 1424693Swnj m->m_off -= L1822; 1434496Swnj m->m_len += L1822; 1444545Swnj m->m_act = NULL; 1454545Swnj #ifndef IMPLOOP 1464662Swnj s = splimp(); 1474545Swnj if (imp_stat.outq_head != NULL) 1484545Swnj imp_stat.outq_tail->m_act = m; 1494545Swnj else 1504545Swnj imp_stat.outq_head = m; 1514545Swnj imp_stat.outq_tail = m; 1524545Swnj splx(s); 1534545Swnj if (!imp_stat.outactive) 1544688Swnj enstart(0); 1554545Swnj #else 1564545Swnj if (imp_stat.inq_head != NULL) 1574545Swnj imp_stat.inq_tail->m_act = m; 1584545Swnj else 1594545Swnj imp_stat.inq_head = m; 1604545Swnj imp_stat.inq_tail = m; 1614724Swnj setsoftnet(); 1624545Swnj #endif IMPLOOP 1634496Swnj } 164