1*4662Swnj /* ip_output.c 1.5 81/10/29 */ 24571Swnj 34496Swnj #include "../h/param.h" 4*4662Swnj #include "../h/mbuf.h" 5*4662Swnj #include "../h/socket.h" 6*4662Swnj #include "../inet/inet.h" 7*4662Swnj #include "../inet/inet_systm.h" 8*4662Swnj #include "../inet/imp.h" 9*4662Swnj #include "../inet/inet_host.h" 10*4662Swnj #include "../inet/ip.h" 11*4662Swnj #include "../inet/tcp.h" 124496Swnj 134496Swnj ip_output(mp) 144545Swnj struct mbuf *mp; 154496Swnj { 164496Swnj register i, rnd; 174496Swnj register struct mbuf *m, *n; 184496Swnj register struct ip *p; 194496Swnj struct mbuf *mm; 204496Swnj int hlen, adj, max, len, off; 214496Swnj 224496Swnj COUNT(IP_OUTPUT); 234496Swnj p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ 244545Swnj hlen = sizeof (struct ip); /* header length */ 254496Swnj 264545Swnj /* 274545Swnj * Fill in and byte swap ip header. 284545Swnj */ 294545Swnj p->ip_v = IPVERSION; 304496Swnj p->ip_hl = hlen >> 2; 31*4662Swnj p->ip_off = 0 | (p->ip_off & IP_DF); 324496Swnj p->ip_ttl = MAXTTL; 33*4662Swnj p->ip_id = ip_id++; 344496Swnj 354496Swnj if (p->ip_len > MTU) { /* must fragment */ 36*4662Swnj if (p->ip_off & IP_DF) 374545Swnj return (0); 384496Swnj max = MTU - hlen; /* maximum data length in fragment */ 394496Swnj len = p->ip_len - hlen; /* data length */ 404496Swnj off = 0; /* fragment offset */ 414496Swnj m = mp; 424496Swnj 434496Swnj while (len > 0) { 444496Swnj 454496Swnj /* correct the header */ 464496Swnj 474496Swnj p->ip_off |= off >> 3; 484496Swnj 494496Swnj /* find the end of the fragment */ 504496Swnj 514496Swnj i = -hlen; 524496Swnj while (m != NULL) { 534496Swnj i += m->m_len; 544496Swnj if (i > max) 554496Swnj break; 564496Swnj n = m; 574496Swnj m = m->m_next; 584496Swnj } 594496Swnj 604496Swnj if (i < max || m == NULL) { /* last fragment */ 61*4662Swnj p->ip_off = p->ip_off &~ IP_MF; 624496Swnj p->ip_len = i + hlen; 634496Swnj break; 644496Swnj 654496Swnj } else { /* more fragments */ 664496Swnj 674496Swnj /* allocate header mbuf for next fragment */ 684496Swnj 694496Swnj if ((mm = m_get(1)) == NULL) /* no more bufs */ 704545Swnj return(0); 714496Swnj 72*4662Swnj p->ip_off |= IP_MF; 734496Swnj 744496Swnj /* terminate fragment at 8 byte boundary (round down) */ 754496Swnj 764496Swnj i -= m->m_len; 774496Swnj rnd = i & ~7; /* fragment length */ 784496Swnj adj = i - rnd; /* leftover in mbuf */ 794545Swnj p->ip_len = rnd + hlen; 804496Swnj 814545Swnj /* setup header for next fragment and 824496Swnj append remaining fragment data */ 834496Swnj 844545Swnj n->m_next = NULL; 854545Swnj mm->m_next = m; 864496Swnj m = mm; 874590Swnj m->m_off = MMAXOFF - hlen - adj; 884496Swnj m->m_len = hlen + adj; 894496Swnj 904496Swnj /* copy old header to new */ 914496Swnj 924496Swnj bcopy(p, (caddr_t)((int)m + m->m_off), hlen); 934496Swnj 944496Swnj /* copy leftover data from previous frag */ 954496Swnj 964496Swnj if (adj) { 974496Swnj n->m_len -= adj; 984496Swnj bcopy((caddr_t)((int)n + n->m_len + n->m_off), 994496Swnj (caddr_t)((int)m + m->m_off + hlen), adj); 1004496Swnj } 1014496Swnj } 1024496Swnj 1034496Swnj ip_send(p); /* pass frag to local net level */ 1044496Swnj 1054496Swnj p = (struct ip *)((int)m + m->m_off); /* -> new hdr */ 1064496Swnj len -= rnd; 1074496Swnj off += rnd; 1084496Swnj } 1094545Swnj } 1104496Swnj 1114496Swnj return(ip_send(p)); /* pass datagram to local net level */ 1124496Swnj } 1134496Swnj 1144496Swnj ip_send(p) /* format header and send message to 1822 level */ 1154496Swnj struct ip *p; 1164496Swnj { 1174496Swnj register struct mbuf *m; 1184496Swnj register struct imp *l; 1194545Swnj int s; 1204496Swnj COUNT(IP_SEND); 1214496Swnj 1224496Swnj m = dtom(p); /* ->header mbuf */ 1234496Swnj 1244496Swnj /* set up 1822 leader fields for transmit */ 1254496Swnj 1264496Swnj l = (struct imp *)((int)m + m->m_off - L1822); 1274496Swnj /* 1284496Swnj l->i_hst = p->ip_dst.s_host; 1294496Swnj l->i_impno = p->ip_dst.s_imp; 1304496Swnj l->i_mlen = p->ip_len + L1822; 1314496Swnj l->i_link = IPLINK; 1324496Swnj l->i_type = 0; 1334496Swnj l->i_htype = 0; 1344496Swnj l->i_stype = 0; 1354496Swnj */ 1364545Swnj if ((l->i_shost = p->ip_src.s_host) == 0) 1374545Swnj l->i_shost = 253; 1384545Swnj if ((l->i_dhost = p->ip_dst.s_host) == 0) 1394545Swnj l->i_dhost = 253; 1404496Swnj l->i_type = IPTYPE; 1414496Swnj 1424496Swnj /* finish ip leader by calculating checksum and doing 1434496Swnj necessary byte-swapping */ 1444496Swnj 1454496Swnj p->ip_sum = 0; 146*4662Swnj p->ip_len = htons(p->ip_len); 147*4662Swnj p->ip_id = htons(p->ip_id); 148*4662Swnj p->ip_off = htons(p->ip_off); 1494545Swnj p->ip_sum = cksum(m, sizeof(struct ip)); 1504496Swnj 1514496Swnj m->m_off -= L1822; /* -> 1822 leader */ 1524496Swnj m->m_len += L1822; 1534496Swnj 1544545Swnj m->m_act = NULL; 1554545Swnj 1564545Swnj #ifndef IMPLOOP 1574545Swnj 1584545Swnj /* put output message on queue */ 1594545Swnj 160*4662Swnj s = splimp(); 1614545Swnj if (imp_stat.outq_head != NULL) 1624545Swnj imp_stat.outq_tail->m_act = m; 1634545Swnj else 1644545Swnj imp_stat.outq_head = m; 1654545Swnj imp_stat.outq_tail = m; 1664545Swnj splx(s); 1674545Swnj 1684545Swnj /* if no outstanding output, start some */ 1694545Swnj 1704545Swnj if (!imp_stat.outactive) 1714545Swnj imp_output(0); 1724545Swnj 1734545Swnj #else 1744545Swnj /* software looping: put msg chain on input queue */ 1754545Swnj 1764545Swnj if (imp_stat.inq_head != NULL) 1774545Swnj imp_stat.inq_tail->m_act = m; 1784545Swnj else 1794545Swnj imp_stat.inq_head = m; 1804545Swnj imp_stat.inq_tail = m; 1814545Swnj 1824545Swnj #endif IMPLOOP 1834545Swnj return (1); 1844496Swnj } 1854496Swnj 1864496Swnj ip_setup(up, m, len) /* setup an ip header for raw write */ 1874496Swnj register struct ucb *up; 1884496Swnj register struct mbuf *m; 1894496Swnj int len; 1904496Swnj { 1914496Swnj register struct ip *ip; 1924496Swnj COUNT(IP_SETUP); 1934496Swnj 1944590Swnj m->m_off = MMAXOFF - sizeof(struct ip); 1954496Swnj m->m_len = sizeof(struct ip); 1964496Swnj 1974496Swnj ip = (struct ip *)((int)m + m->m_off); 1984496Swnj 1994496Swnj ip->ip_tos = 0; 2004496Swnj ip->ip_id = 0; 2014496Swnj ip->ip_off = 0; 2024496Swnj ip->ip_p = up->uc_lolink; 2034496Swnj ip->ip_len = len + sizeof(struct ip); 2044496Swnj 205*4662Swnj ip->ip_src.s_addr = n_lhost.s_addr; 2064496Swnj ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr; 2074496Swnj } 208