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