1*4571Swnj /* ip_output.c 1.3 81/10/21 */ 2*4571Swnj 34496Swnj #include "../h/param.h" 44496Swnj #include "../bbnnet/net.h" 5*4571Swnj #include "../bbnnet/mbuf.h" 6*4571Swnj #include "../bbnnet/host.h" 74496Swnj #include "../bbnnet/tcp.h" 84496Swnj #include "../bbnnet/ip.h" 94496Swnj #include "../bbnnet/imp.h" 104496Swnj #include "../bbnnet/ucb.h" 114496Swnj 124496Swnj ip_output(mp) 134545Swnj struct mbuf *mp; 144496Swnj { 154496Swnj register i, rnd; 164496Swnj register struct mbuf *m, *n; 174496Swnj register struct ip *p; 184496Swnj struct mbuf *mm; 194496Swnj int hlen, adj, max, len, off; 204496Swnj 214496Swnj COUNT(IP_OUTPUT); 224496Swnj p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ 234545Swnj hlen = sizeof (struct ip); /* header length */ 244496Swnj 254545Swnj /* 264545Swnj * Fill in and byte swap ip header. 274545Swnj */ 284545Swnj p->ip_v = IPVERSION; 294496Swnj p->ip_hl = hlen >> 2; 304496Swnj p->ip_off = 0 | (p->ip_off & ip_df); 314496Swnj p->ip_ttl = MAXTTL; 324496Swnj p->ip_id = netcb.n_ip_cnt++; 334496Swnj 344496Swnj if (p->ip_len > MTU) { /* must fragment */ 354496Swnj if (p->ip_off & ip_df) 364545Swnj return (0); 374496Swnj max = MTU - hlen; /* maximum data length in fragment */ 384496Swnj len = p->ip_len - hlen; /* data length */ 394496Swnj off = 0; /* fragment offset */ 404496Swnj m = mp; 414496Swnj 424496Swnj while (len > 0) { 434496Swnj 444496Swnj /* correct the header */ 454496Swnj 464496Swnj p->ip_off |= off >> 3; 474496Swnj 484496Swnj /* find the end of the fragment */ 494496Swnj 504496Swnj i = -hlen; 514496Swnj while (m != NULL) { 524496Swnj i += m->m_len; 534496Swnj if (i > max) 544496Swnj break; 554496Swnj n = m; 564496Swnj m = m->m_next; 574496Swnj } 584496Swnj 594496Swnj if (i < max || m == NULL) { /* last fragment */ 604496Swnj p->ip_off = p->ip_off & ~ip_mf; 614496Swnj p->ip_len = i + hlen; 624496Swnj break; 634496Swnj 644496Swnj } else { /* more fragments */ 654496Swnj 664496Swnj /* allocate header mbuf for next fragment */ 674496Swnj 684496Swnj if ((mm = m_get(1)) == NULL) /* no more bufs */ 694545Swnj return(0); 704496Swnj 714496Swnj p->ip_off |= ip_mf; 724496Swnj 734496Swnj /* terminate fragment at 8 byte boundary (round down) */ 744496Swnj 754496Swnj i -= m->m_len; 764496Swnj rnd = i & ~7; /* fragment length */ 774496Swnj adj = i - rnd; /* leftover in mbuf */ 784545Swnj p->ip_len = rnd + hlen; 794496Swnj 804545Swnj /* setup header for next fragment and 814496Swnj append remaining fragment data */ 824496Swnj 834545Swnj n->m_next = NULL; 844545Swnj mm->m_next = m; 854496Swnj m = mm; 864496Swnj m->m_off = MSIZE - hlen - adj; 874496Swnj m->m_len = hlen + adj; 884496Swnj 894496Swnj /* copy old header to new */ 904496Swnj 914496Swnj bcopy(p, (caddr_t)((int)m + m->m_off), hlen); 924496Swnj 934496Swnj /* copy leftover data from previous frag */ 944496Swnj 954496Swnj if (adj) { 964496Swnj n->m_len -= adj; 974496Swnj bcopy((caddr_t)((int)n + n->m_len + n->m_off), 984496Swnj (caddr_t)((int)m + m->m_off + hlen), adj); 994496Swnj } 1004496Swnj } 1014496Swnj 1024496Swnj ip_send(p); /* pass frag to local net level */ 1034496Swnj 1044496Swnj p = (struct ip *)((int)m + m->m_off); /* -> new hdr */ 1054496Swnj len -= rnd; 1064496Swnj off += rnd; 1074496Swnj } 1084545Swnj } 1094496Swnj 1104496Swnj return(ip_send(p)); /* pass datagram to local net level */ 1114496Swnj } 1124496Swnj 1134496Swnj ip_send(p) /* format header and send message to 1822 level */ 1144496Swnj struct ip *p; 1154496Swnj { 1164496Swnj register struct mbuf *m; 1174496Swnj register struct imp *l; 1184545Swnj int s; 1194496Swnj COUNT(IP_SEND); 1204496Swnj 1214496Swnj m = dtom(p); /* ->header mbuf */ 1224496Swnj 1234496Swnj /* set up 1822 leader fields for transmit */ 1244496Swnj 1254496Swnj l = (struct imp *)((int)m + m->m_off - L1822); 1264496Swnj /* 1274496Swnj l->i_hst = p->ip_dst.s_host; 1284496Swnj l->i_impno = p->ip_dst.s_imp; 1294496Swnj l->i_mlen = p->ip_len + L1822; 1304496Swnj l->i_link = IPLINK; 1314496Swnj l->i_type = 0; 1324496Swnj l->i_htype = 0; 1334496Swnj l->i_stype = 0; 1344496Swnj */ 1354545Swnj if ((l->i_shost = p->ip_src.s_host) == 0) 1364545Swnj l->i_shost = 253; 1374545Swnj if ((l->i_dhost = p->ip_dst.s_host) == 0) 1384545Swnj l->i_dhost = 253; 1394496Swnj l->i_type = IPTYPE; 1404496Swnj 1414496Swnj /* finish ip leader by calculating checksum and doing 1424496Swnj necessary byte-swapping */ 1434496Swnj 1444496Swnj p->ip_sum = 0; 1454496Swnj ip_bswap(p); 1464545Swnj p->ip_sum = cksum(m, sizeof(struct ip)); 1474496Swnj 1484496Swnj m->m_off -= L1822; /* -> 1822 leader */ 1494496Swnj m->m_len += L1822; 1504496Swnj 1514545Swnj m->m_act = NULL; 1524545Swnj 1534545Swnj #ifndef IMPLOOP 1544545Swnj 1554545Swnj /* put output message on queue */ 1564545Swnj 1574545Swnj s = spl_imp(); 1584545Swnj if (imp_stat.outq_head != NULL) 1594545Swnj imp_stat.outq_tail->m_act = m; 1604545Swnj else 1614545Swnj imp_stat.outq_head = m; 1624545Swnj imp_stat.outq_tail = m; 1634545Swnj splx(s); 1644545Swnj 1654545Swnj /* if no outstanding output, start some */ 1664545Swnj 1674545Swnj if (!imp_stat.outactive) 1684545Swnj imp_output(0); 1694545Swnj 1704545Swnj #else 1714545Swnj /* software looping: put msg chain on input queue */ 1724545Swnj 1734545Swnj if (imp_stat.inq_head != NULL) 1744545Swnj imp_stat.inq_tail->m_act = m; 1754545Swnj else 1764545Swnj imp_stat.inq_head = m; 1774545Swnj imp_stat.inq_tail = m; 1784545Swnj 1794545Swnj #endif IMPLOOP 1804545Swnj return (1); 1814496Swnj } 1824496Swnj 1834496Swnj ip_setup(up, m, len) /* setup an ip header for raw write */ 1844496Swnj register struct ucb *up; 1854496Swnj register struct mbuf *m; 1864496Swnj int len; 1874496Swnj { 1884496Swnj register struct ip *ip; 1894496Swnj COUNT(IP_SETUP); 1904496Swnj 1914496Swnj m->m_off = MSIZE - sizeof(struct ip); 1924496Swnj m->m_len = sizeof(struct ip); 1934496Swnj 1944496Swnj ip = (struct ip *)((int)m + m->m_off); 1954496Swnj 1964496Swnj ip->ip_tos = 0; 1974496Swnj ip->ip_id = 0; 1984496Swnj ip->ip_off = 0; 1994496Swnj ip->ip_p = up->uc_lolink; 2004496Swnj ip->ip_len = len + sizeof(struct ip); 2014496Swnj 2024496Swnj ip->ip_src.s_addr = netcb.n_lhost.s_addr; 2034496Swnj ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr; 2044496Swnj } 205