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