xref: /csrg-svn/sys/netinet/ip_output.c (revision 4571)
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