1*4967Swnj /* ip_output.c 1.16 81/11/20 */ 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" 84802Swnj #include "../net/inet.h" 94802Swnj #include "../net/inet_systm.h" 104802Swnj #include "../net/imp.h" 114802Swnj #include "../net/ip.h" 124899Swnj #include "../net/ip_var.h" 134496Swnj 144924Swnj ip_output(m) 154924Swnj struct mbuf *m; 164496Swnj { 174924Swnj register struct ip *ip = mtod(m, struct ip *); 184924Swnj int len, hlen = ip->ip_hl << 2, off; 194496Swnj 204496Swnj COUNT(IP_OUTPUT); 214924Swnj /* 224924Swnj * Fill in IP header. 234924Swnj */ 244924Swnj ip->ip_v = IPVERSION; 254924Swnj ip->ip_hl = hlen >> 2; 264924Swnj ip->ip_off &= IP_DF; 274924Swnj ip->ip_ttl = MAXTTL; 284924Swnj ip->ip_id = ip_id++; 294496Swnj 304545Swnj /* 314924Swnj * If small enough for interface, can just send directly. 324545Swnj */ 334924Swnj if (ip->ip_len <= MTU) { 344924Swnj ip_send(ip); 354908Swnj return; 364908Swnj } 374924Swnj 384924Swnj /* 394924Swnj * Too large for interface; fragment if possible. 404924Swnj * Must be able to put at least 8 bytes per fragment. 414924Swnj */ 424924Swnj if (ip->ip_off & IP_DF) 434924Swnj goto bad; 444924Swnj len = (MTU-hlen) &~ 7; 454924Swnj if (len < 8) 464924Swnj goto bad; 474924Swnj 484924Swnj /* 494924Swnj * Discard IP header from logical mbuf for m_copy's sake. 504924Swnj * Loop through length of segment, make a copy of each 514924Swnj * part and output. 524924Swnj */ 534924Swnj m->m_len -= sizeof (struct ip); 544924Swnj m->m_off += sizeof (struct ip); 554924Swnj for (off = 0; off < ip->ip_len; off += len) { 564924Swnj struct mbuf *mh = m_get(0); 574924Swnj struct ip *mhip; 584924Swnj 594924Swnj if (mh == 0) 604924Swnj goto bad; 614924Swnj mh->m_off = MMAXOFF - hlen; 624924Swnj mhip = mtod(mh, struct ip *); 634924Swnj *mhip = *ip; 644952Swnj if (hlen > sizeof (struct ip)) { 654924Swnj int olen = ip_optcopy(ip, mhip, off); 664924Swnj mh->m_len = sizeof (struct ip) + olen; 674924Swnj } else 684924Swnj mh->m_len = sizeof (struct ip); 694924Swnj mhip->ip_off = off; 704924Swnj if (off + len >= ip->ip_len) 714924Swnj mhip->ip_len = ip->ip_len - off; 724924Swnj else { 734924Swnj mhip->ip_len = len; 744924Swnj mhip->ip_off |= IP_MF; 754496Swnj } 764924Swnj mh->m_next = m_copy(m, off, len); 774924Swnj if (mh->m_next == 0) { 78*4967Swnj (void) m_free(mh); 794924Swnj goto bad; 804674Swnj } 814952Swnj ip_send(mhip); 824924Swnj } 834924Swnj bad: 844924Swnj m_freem(m); 854924Swnj } 864924Swnj 874924Swnj /* 884924Swnj * Copy options from ip to jp. 894952Swnj * If off is 0 all options are copied 904924Swnj * otherwise copy selectively. 914924Swnj */ 924924Swnj ip_optcopy(ip, jp, off) 934924Swnj struct ip *ip, *jp; 944924Swnj int off; 954924Swnj { 964924Swnj register u_char *cp, *dp; 974924Swnj int opt, optlen, cnt; 984924Swnj 994952Swnj COUNT(IP_OPTCOPY); 1004924Swnj cp = (u_char *)(ip + 1); 1014924Swnj dp = (u_char *)(jp + 1); 1024924Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1034924Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 1044924Swnj opt = cp[0]; 1054924Swnj if (opt == IPOPT_EOL) 1064924Swnj break; 1074924Swnj if (opt == IPOPT_NOP) 1084924Swnj optlen = 1; 1094924Swnj else 1104924Swnj optlen = cp[1]; 1114924Swnj if (optlen > cnt) /* XXX */ 1124924Swnj optlen = cnt; /* XXX */ 1134924Swnj if (off == 0 || IPOPT_COPIED(opt)) { 1144952Swnj bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 1154924Swnj dp += optlen; 1164674Swnj } 1174545Swnj } 1184924Swnj for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 1194924Swnj *dp++ = IPOPT_EOL; 1204924Swnj return (optlen); 1214496Swnj } 1224496Swnj 1234952Swnj /* REST OF CODE HERE IS GARBAGE */ 1244952Swnj 1254693Swnj ip_send(ip) 1264924Swnj register struct ip *ip; 1274496Swnj { 1284496Swnj register struct mbuf *m; 1294496Swnj register struct imp *l; 1304924Swnj int hlen = ip->ip_hl << 2; 1314545Swnj int s; 1324496Swnj COUNT(IP_SEND); 1334496Swnj 1344693Swnj m = dtom(ip); 1354908Swnj l = (struct imp *)(mtod(m, caddr_t) - L1822); 1364693Swnj l->i_shost = ip->ip_src.s_host; 1374693Swnj l->i_dhost = ip->ip_dst.s_host; 1384496Swnj l->i_type = IPTYPE; 1394693Swnj ip->ip_sum = 0; 1404908Swnj ip->ip_len = htons((u_short)ip->ip_len); 1414693Swnj ip->ip_id = htons(ip->ip_id); 1424908Swnj ip->ip_off = htons((u_short)ip->ip_off); 1434924Swnj ip->ip_sum = inet_cksum(m, hlen); 1444693Swnj m->m_off -= L1822; 1454496Swnj m->m_len += L1822; 1464545Swnj m->m_act = NULL; 1474545Swnj #ifndef IMPLOOP 1484662Swnj s = splimp(); 1494545Swnj if (imp_stat.outq_head != NULL) 1504545Swnj imp_stat.outq_tail->m_act = m; 1514545Swnj else 1524545Swnj imp_stat.outq_head = m; 1534545Swnj imp_stat.outq_tail = m; 1544545Swnj splx(s); 1554545Swnj if (!imp_stat.outactive) 1564688Swnj enstart(0); 1574545Swnj #else 1584545Swnj if (imp_stat.inq_head != NULL) 1594545Swnj imp_stat.inq_tail->m_act = m; 1604545Swnj else 1614545Swnj imp_stat.inq_head = m; 1624545Swnj imp_stat.inq_tail = m; 1634724Swnj setsoftnet(); 1644545Swnj #endif IMPLOOP 1654496Swnj } 1664952Swnj 1674952Swnj /* END GARBAGE */ 168