xref: /csrg-svn/sys/netinet/ip_output.c (revision 4693)
1*4693Swnj /* ip_output.c 1.8 81/10/31 */
24571Swnj 
34496Swnj #include "../h/param.h"
44662Swnj #include "../h/mbuf.h"
54662Swnj #include "../h/socket.h"
6*4693Swnj #include "../inet/cksum.h"
74662Swnj #include "../inet/inet.h"
84662Swnj #include "../inet/inet_systm.h"
94662Swnj #include "../inet/imp.h"
104662Swnj #include "../inet/inet_host.h"
114662Swnj #include "../inet/ip.h"
124662Swnj #include "../inet/tcp.h"
134496Swnj 
144496Swnj ip_output(mp)
154545Swnj 	struct mbuf *mp;
164496Swnj {
174496Swnj 	register i, rnd;
184496Swnj 	register struct mbuf *m, *n;
194496Swnj 	register struct ip *p;
204496Swnj 	struct mbuf *mm;
214496Swnj 	int hlen, adj, max, len, off;
224496Swnj 
234496Swnj COUNT(IP_OUTPUT);
24*4693Swnj 	p = mtod(mp, struct ip *);
25*4693Swnj 	hlen = sizeof (struct ip);
264496Swnj 
274545Swnj 	/*
284545Swnj 	 * Fill in and byte swap ip header.
294545Swnj 	 */
304545Swnj 	p->ip_v = IPVERSION;
314496Swnj 	p->ip_hl = hlen >> 2;
324662Swnj 	p->ip_off = 0 | (p->ip_off & IP_DF);
334496Swnj 	p->ip_ttl = MAXTTL;
344662Swnj 	p->ip_id = ip_id++;
354496Swnj 
364674Swnj 	if (p->ip_len <= MTU)
374674Swnj 		return (ip_send(p));
384674Swnj 	if (p->ip_off & IP_DF)
394674Swnj 		return (0);
404674Swnj 	max = MTU - hlen;
414674Swnj 	len = p->ip_len - hlen;
424674Swnj 	off = 0;
434674Swnj 	m = mp;
444674Swnj 	while (len > 0) {
454674Swnj 		p->ip_off |= off >> 3;
464674Swnj 		i = -hlen;
474674Swnj 		while (m != NULL) {
484674Swnj 			i += m->m_len;
494674Swnj 			if (i > max)
504496Swnj 				break;
514674Swnj 			n = m;
524674Swnj 			m = m->m_next;
534496Swnj 		}
544674Swnj 		if (i < max || m == NULL) {
554674Swnj 			p->ip_off = p->ip_off &~ IP_MF;
564674Swnj 			p->ip_len = i + hlen;
574674Swnj 			return (ip_send(p));
584674Swnj 		}
594674Swnj 		if ((mm = m_get(1)) == NULL)    /* no more bufs */
604674Swnj 			return(0);
614674Swnj 		p->ip_off |= IP_MF;
624674Swnj 		i -= m->m_len;
634674Swnj 		rnd = i & ~7;
644674Swnj 		adj = i - rnd;
654674Swnj 		p->ip_len = rnd + hlen;
664674Swnj 		n->m_next = NULL;
674674Swnj 		mm->m_next = m;
684674Swnj 		m = mm;
694674Swnj 		m->m_off = MMAXOFF - hlen - adj;
704674Swnj 		m->m_len = hlen + adj;
714674Swnj 		bcopy(p, (caddr_t)((int)m + m->m_off), hlen);
724674Swnj 		if (adj) {
734674Swnj 			n->m_len -= adj;
744674Swnj 			bcopy((caddr_t)((int)n + n->m_len + n->m_off),
754674Swnj 			      (caddr_t)((int)m + m->m_off + hlen), adj);
764674Swnj 		}
774674Swnj 		ip_send(p);
784674Swnj 		p = (struct ip *)((int)m + m->m_off);
794674Swnj 		len -= rnd;
804674Swnj 		off += rnd;
814545Swnj 	}
824496Swnj }
834496Swnj 
84*4693Swnj ip_send(ip)
85*4693Swnj 	register struct ip *ip;		/* known to be r11 */
864496Swnj {
874496Swnj 	register struct mbuf *m;
884496Swnj 	register struct imp *l;
89*4693Swnj 	register int hlen = ip->ip_hl << 2;
904545Swnj 	int s;
914496Swnj COUNT(IP_SEND);
924496Swnj 
93*4693Swnj 	m = dtom(ip);
944496Swnj 	l = (struct imp *)((int)m + m->m_off - L1822);
95*4693Swnj 	l->i_shost = ip->ip_src.s_host;
96*4693Swnj 	l->i_dhost = ip->ip_dst.s_host;
974496Swnj 	l->i_type = IPTYPE;
98*4693Swnj 	ip->ip_sum = 0;
99*4693Swnj 	ip->ip_len = htons(ip->ip_len);
100*4693Swnj 	ip->ip_id = htons(ip->ip_id);
101*4693Swnj 	ip->ip_off = htons(ip->ip_off);
102*4693Swnj 	CKSUM_IPSET(m, ip, r11, hlen);
103*4693Swnj 	m->m_off -= L1822;
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)
1154688Swnj 		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