1*4545Swnj /* ip_output.c 1.2 81/10/18 */ 24496Swnj #include "../h/param.h" 34496Swnj #include "../bbnnet/net.h" 44496Swnj #include "../bbnnet/tcp.h" 54496Swnj #include "../bbnnet/ip.h" 64496Swnj #include "../bbnnet/imp.h" 74496Swnj #include "../bbnnet/ucb.h" 84496Swnj 94496Swnj ip_output(mp) 10*4545Swnj struct mbuf *mp; 114496Swnj { 124496Swnj register i, rnd; 134496Swnj register struct mbuf *m, *n; 144496Swnj register struct ip *p; 154496Swnj struct mbuf *mm; 164496Swnj int hlen, adj, max, len, off; 174496Swnj 184496Swnj COUNT(IP_OUTPUT); 194496Swnj p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ 20*4545Swnj hlen = sizeof (struct ip); /* header length */ 214496Swnj 22*4545Swnj /* 23*4545Swnj * Fill in and byte swap ip header. 24*4545Swnj */ 25*4545Swnj p->ip_v = IPVERSION; 264496Swnj p->ip_hl = hlen >> 2; 274496Swnj p->ip_off = 0 | (p->ip_off & ip_df); 284496Swnj p->ip_ttl = MAXTTL; 294496Swnj p->ip_id = netcb.n_ip_cnt++; 304496Swnj 314496Swnj if (p->ip_len > MTU) { /* must fragment */ 324496Swnj if (p->ip_off & ip_df) 33*4545Swnj return (0); 344496Swnj max = MTU - hlen; /* maximum data length in fragment */ 354496Swnj len = p->ip_len - hlen; /* data length */ 364496Swnj off = 0; /* fragment offset */ 374496Swnj m = mp; 384496Swnj 394496Swnj while (len > 0) { 404496Swnj 414496Swnj /* correct the header */ 424496Swnj 434496Swnj p->ip_off |= off >> 3; 444496Swnj 454496Swnj /* find the end of the fragment */ 464496Swnj 474496Swnj i = -hlen; 484496Swnj while (m != NULL) { 494496Swnj i += m->m_len; 504496Swnj if (i > max) 514496Swnj break; 524496Swnj n = m; 534496Swnj m = m->m_next; 544496Swnj } 554496Swnj 564496Swnj if (i < max || m == NULL) { /* last fragment */ 574496Swnj p->ip_off = p->ip_off & ~ip_mf; 584496Swnj p->ip_len = i + hlen; 594496Swnj break; 604496Swnj 614496Swnj } else { /* more fragments */ 624496Swnj 634496Swnj /* allocate header mbuf for next fragment */ 644496Swnj 654496Swnj if ((mm = m_get(1)) == NULL) /* no more bufs */ 66*4545Swnj return(0); 674496Swnj 684496Swnj p->ip_off |= ip_mf; 694496Swnj 704496Swnj /* terminate fragment at 8 byte boundary (round down) */ 714496Swnj 724496Swnj i -= m->m_len; 734496Swnj rnd = i & ~7; /* fragment length */ 744496Swnj adj = i - rnd; /* leftover in mbuf */ 75*4545Swnj p->ip_len = rnd + hlen; 764496Swnj 77*4545Swnj /* setup header for next fragment and 784496Swnj append remaining fragment data */ 794496Swnj 80*4545Swnj n->m_next = NULL; 81*4545Swnj mm->m_next = m; 824496Swnj m = mm; 834496Swnj m->m_off = MSIZE - hlen - adj; 844496Swnj m->m_len = hlen + adj; 854496Swnj 864496Swnj /* copy old header to new */ 874496Swnj 884496Swnj bcopy(p, (caddr_t)((int)m + m->m_off), hlen); 894496Swnj 904496Swnj /* copy leftover data from previous frag */ 914496Swnj 924496Swnj if (adj) { 934496Swnj n->m_len -= adj; 944496Swnj bcopy((caddr_t)((int)n + n->m_len + n->m_off), 954496Swnj (caddr_t)((int)m + m->m_off + hlen), adj); 964496Swnj } 974496Swnj } 984496Swnj 994496Swnj ip_send(p); /* pass frag to local net level */ 1004496Swnj 1014496Swnj p = (struct ip *)((int)m + m->m_off); /* -> new hdr */ 1024496Swnj len -= rnd; 1034496Swnj off += rnd; 1044496Swnj } 105*4545Swnj } 1064496Swnj 1074496Swnj return(ip_send(p)); /* pass datagram to local net level */ 1084496Swnj } 1094496Swnj 1104496Swnj ip_send(p) /* format header and send message to 1822 level */ 1114496Swnj struct ip *p; 1124496Swnj { 1134496Swnj register struct mbuf *m; 1144496Swnj register struct imp *l; 115*4545Swnj int s; 1164496Swnj COUNT(IP_SEND); 1174496Swnj 1184496Swnj m = dtom(p); /* ->header mbuf */ 1194496Swnj 1204496Swnj /* set up 1822 leader fields for transmit */ 1214496Swnj 1224496Swnj l = (struct imp *)((int)m + m->m_off - L1822); 1234496Swnj /* 1244496Swnj l->i_hst = p->ip_dst.s_host; 1254496Swnj l->i_impno = p->ip_dst.s_imp; 1264496Swnj l->i_mlen = p->ip_len + L1822; 1274496Swnj l->i_link = IPLINK; 1284496Swnj l->i_type = 0; 1294496Swnj l->i_htype = 0; 1304496Swnj l->i_stype = 0; 1314496Swnj */ 132*4545Swnj if ((l->i_shost = p->ip_src.s_host) == 0) 133*4545Swnj l->i_shost = 253; 134*4545Swnj if ((l->i_dhost = p->ip_dst.s_host) == 0) 135*4545Swnj l->i_dhost = 253; 1364496Swnj l->i_type = IPTYPE; 1374496Swnj 1384496Swnj /* finish ip leader by calculating checksum and doing 1394496Swnj necessary byte-swapping */ 1404496Swnj 1414496Swnj p->ip_sum = 0; 1424496Swnj ip_bswap(p); 143*4545Swnj p->ip_sum = cksum(m, sizeof(struct ip)); 1444496Swnj 1454496Swnj m->m_off -= L1822; /* -> 1822 leader */ 1464496Swnj m->m_len += L1822; 1474496Swnj 148*4545Swnj m->m_act = NULL; 149*4545Swnj 150*4545Swnj #ifndef IMPLOOP 151*4545Swnj 152*4545Swnj /* put output message on queue */ 153*4545Swnj 154*4545Swnj s = spl_imp(); 155*4545Swnj if (imp_stat.outq_head != NULL) 156*4545Swnj imp_stat.outq_tail->m_act = m; 157*4545Swnj else 158*4545Swnj imp_stat.outq_head = m; 159*4545Swnj imp_stat.outq_tail = m; 160*4545Swnj splx(s); 161*4545Swnj 162*4545Swnj /* if no outstanding output, start some */ 163*4545Swnj 164*4545Swnj if (!imp_stat.outactive) 165*4545Swnj imp_output(0); 166*4545Swnj 167*4545Swnj #else 168*4545Swnj /* software looping: put msg chain on input queue */ 169*4545Swnj 170*4545Swnj if (imp_stat.inq_head != NULL) 171*4545Swnj imp_stat.inq_tail->m_act = m; 172*4545Swnj else 173*4545Swnj imp_stat.inq_head = m; 174*4545Swnj imp_stat.inq_tail = m; 175*4545Swnj 176*4545Swnj #endif IMPLOOP 177*4545Swnj return (1); 1784496Swnj } 1794496Swnj 1804496Swnj ip_setup(up, m, len) /* setup an ip header for raw write */ 1814496Swnj register struct ucb *up; 1824496Swnj register struct mbuf *m; 1834496Swnj int len; 1844496Swnj { 1854496Swnj register struct ip *ip; 1864496Swnj COUNT(IP_SETUP); 1874496Swnj 1884496Swnj m->m_off = MSIZE - sizeof(struct ip); 1894496Swnj m->m_len = sizeof(struct ip); 1904496Swnj 1914496Swnj ip = (struct ip *)((int)m + m->m_off); 1924496Swnj 1934496Swnj ip->ip_tos = 0; 1944496Swnj ip->ip_id = 0; 1954496Swnj ip->ip_off = 0; 1964496Swnj ip->ip_p = up->uc_lolink; 1974496Swnj ip->ip_len = len + sizeof(struct ip); 1984496Swnj 1994496Swnj ip->ip_src.s_addr = netcb.n_lhost.s_addr; 2004496Swnj ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr; 2014496Swnj } 202