xref: /csrg-svn/sys/netinet/ip_output.c (revision 4688)
1*4688Swnj /* ip_output.c 1.7 81/10/31 */
24571Swnj 
34496Swnj #include "../h/param.h"
44662Swnj #include "../h/mbuf.h"
54662Swnj #include "../h/socket.h"
64662Swnj #include "../inet/inet.h"
74662Swnj #include "../inet/inet_systm.h"
84662Swnj #include "../inet/imp.h"
94662Swnj #include "../inet/inet_host.h"
104662Swnj #include "../inet/ip.h"
114662Swnj #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;
314662Swnj 	p->ip_off = 0 | (p->ip_off & IP_DF);
324496Swnj 	p->ip_ttl = MAXTTL;
334662Swnj 	p->ip_id = ip_id++;
344496Swnj 
354674Swnj 	if (p->ip_len <= MTU)
364674Swnj 		return (ip_send(p));
374674Swnj 	if (p->ip_off & IP_DF)
384674Swnj 		return (0);
394674Swnj 	max = MTU - hlen;
404674Swnj 	len = p->ip_len - hlen;
414674Swnj 	off = 0;
424674Swnj 	m = mp;
434674Swnj 	while (len > 0) {
444674Swnj 		p->ip_off |= off >> 3;
454674Swnj 		i = -hlen;
464674Swnj 		while (m != NULL) {
474674Swnj 			i += m->m_len;
484674Swnj 			if (i > max)
494496Swnj 				break;
504674Swnj 			n = m;
514674Swnj 			m = m->m_next;
524496Swnj 		}
534674Swnj 		if (i < max || m == NULL) {
544674Swnj 			p->ip_off = p->ip_off &~ IP_MF;
554674Swnj 			p->ip_len = i + hlen;
564674Swnj 			return (ip_send(p));
574674Swnj 		}
584674Swnj 		if ((mm = m_get(1)) == NULL)    /* no more bufs */
594674Swnj 			return(0);
604674Swnj 		p->ip_off |= IP_MF;
614674Swnj 		i -= m->m_len;
624674Swnj 		rnd = i & ~7;
634674Swnj 		adj = i - rnd;
644674Swnj 		p->ip_len = rnd + hlen;
654674Swnj 		n->m_next = NULL;
664674Swnj 		mm->m_next = m;
674674Swnj 		m = mm;
684674Swnj 		m->m_off = MMAXOFF - hlen - adj;
694674Swnj 		m->m_len = hlen + adj;
704674Swnj 		bcopy(p, (caddr_t)((int)m + m->m_off), hlen);
714674Swnj 		if (adj) {
724674Swnj 			n->m_len -= adj;
734674Swnj 			bcopy((caddr_t)((int)n + n->m_len + n->m_off),
744674Swnj 			      (caddr_t)((int)m + m->m_off + hlen), adj);
754674Swnj 		}
764674Swnj 		ip_send(p);
774674Swnj 		p = (struct ip *)((int)m + m->m_off);
784674Swnj 		len -= rnd;
794674Swnj 		off += rnd;
804545Swnj 	}
814496Swnj }
824496Swnj 
834674Swnj ip_send(p)
844674Swnj 	struct ip *p;
854496Swnj {
864496Swnj 	register struct mbuf *m;
874496Swnj 	register struct imp *l;
884545Swnj 	int s;
894496Swnj COUNT(IP_SEND);
904496Swnj 
914674Swnj 	m = dtom(p);
924496Swnj 	l = (struct imp *)((int)m + m->m_off - L1822);
934545Swnj 	if ((l->i_shost = p->ip_src.s_host) == 0)
944545Swnj 		l->i_shost = 253;
954545Swnj 	if ((l->i_dhost = p->ip_dst.s_host) == 0)
964545Swnj 		l->i_dhost = 253;
974496Swnj 	l->i_type = IPTYPE;
984496Swnj 	p->ip_sum = 0;
994662Swnj 	p->ip_len = htons(p->ip_len);
1004662Swnj 	p->ip_id = htons(p->ip_id);
1014662Swnj 	p->ip_off = htons(p->ip_off);
1024545Swnj 	p->ip_sum = cksum(m, sizeof(struct ip));
1034496Swnj 	m->m_off -= L1822;              /* -> 1822 leader */
1044496Swnj 	m->m_len += L1822;
1054545Swnj 	m->m_act = NULL;
1064545Swnj #ifndef IMPLOOP
1074662Swnj 	s = splimp();
1084545Swnj 	if (imp_stat.outq_head != NULL)
1094545Swnj 		imp_stat.outq_tail->m_act = m;
1104545Swnj 	else
1114545Swnj 		imp_stat.outq_head = m;
1124545Swnj 	imp_stat.outq_tail = m;
1134545Swnj 	splx(s);
1144545Swnj 	if (!imp_stat.outactive)
115*4688Swnj 		enstart(0);
1164545Swnj #else
1174545Swnj 	if (imp_stat.inq_head != NULL)
1184545Swnj 		imp_stat.inq_tail->m_act = m;
1194545Swnj 	else
1204545Swnj 		imp_stat.inq_head = m;
1214545Swnj 	imp_stat.inq_tail = m;
1224545Swnj #endif IMPLOOP
1234545Swnj 	return (1);
1244496Swnj }
125