xref: /csrg-svn/sys/netinet/ip_output.c (revision 4802)
1*4802Swnj /* ip_output.c 1.11 81/11/08 */
24571Swnj 
34496Swnj #include "../h/param.h"
44662Swnj #include "../h/mbuf.h"
54724Swnj #include "../h/mtpr.h"
64662Swnj #include "../h/socket.h"
7*4802Swnj #include "../net/inet_cksum.h"
8*4802Swnj #include "../net/inet.h"
9*4802Swnj #include "../net/inet_systm.h"
10*4802Swnj #include "../net/imp.h"
11*4802Swnj #include "../net/inet_host.h"
12*4802Swnj #include "../net/ip.h"
13*4802Swnj #include "../net/tcp.h"
144496Swnj 
154496Swnj ip_output(mp)
164545Swnj 	struct mbuf *mp;
174496Swnj {
184496Swnj 	register i, rnd;
194496Swnj 	register struct mbuf *m, *n;
204496Swnj 	register struct ip *p;
214496Swnj 	struct mbuf *mm;
224496Swnj 	int hlen, adj, max, len, off;
234496Swnj 
244496Swnj COUNT(IP_OUTPUT);
254693Swnj 	p = mtod(mp, struct ip *);
264693Swnj 	hlen = sizeof (struct ip);
274496Swnj 
284545Swnj 	/*
294545Swnj 	 * Fill in and byte swap ip header.
304545Swnj 	 */
314545Swnj 	p->ip_v = IPVERSION;
324496Swnj 	p->ip_hl = hlen >> 2;
334662Swnj 	p->ip_off = 0 | (p->ip_off & IP_DF);
344496Swnj 	p->ip_ttl = MAXTTL;
354662Swnj 	p->ip_id = ip_id++;
364496Swnj 
374674Swnj 	if (p->ip_len <= MTU)
384674Swnj 		return (ip_send(p));
394674Swnj 	if (p->ip_off & IP_DF)
404674Swnj 		return (0);
414674Swnj 	max = MTU - hlen;
424674Swnj 	len = p->ip_len - hlen;
434674Swnj 	off = 0;
444674Swnj 	m = mp;
454674Swnj 	while (len > 0) {
464674Swnj 		p->ip_off |= off >> 3;
474674Swnj 		i = -hlen;
484674Swnj 		while (m != NULL) {
494674Swnj 			i += m->m_len;
504674Swnj 			if (i > max)
514496Swnj 				break;
524674Swnj 			n = m;
534674Swnj 			m = m->m_next;
544496Swnj 		}
554674Swnj 		if (i < max || m == NULL) {
564674Swnj 			p->ip_off = p->ip_off &~ IP_MF;
574674Swnj 			p->ip_len = i + hlen;
584674Swnj 			return (ip_send(p));
594674Swnj 		}
604674Swnj 		if ((mm = m_get(1)) == NULL)    /* no more bufs */
614674Swnj 			return(0);
624674Swnj 		p->ip_off |= IP_MF;
634674Swnj 		i -= m->m_len;
644674Swnj 		rnd = i & ~7;
654674Swnj 		adj = i - rnd;
664674Swnj 		p->ip_len = rnd + hlen;
674674Swnj 		n->m_next = NULL;
684674Swnj 		mm->m_next = m;
694674Swnj 		m = mm;
704674Swnj 		m->m_off = MMAXOFF - hlen - adj;
714674Swnj 		m->m_len = hlen + adj;
724674Swnj 		bcopy(p, (caddr_t)((int)m + m->m_off), hlen);
734674Swnj 		if (adj) {
744674Swnj 			n->m_len -= adj;
754674Swnj 			bcopy((caddr_t)((int)n + n->m_len + n->m_off),
764674Swnj 			      (caddr_t)((int)m + m->m_off + hlen), adj);
774674Swnj 		}
784674Swnj 		ip_send(p);
794674Swnj 		p = (struct ip *)((int)m + m->m_off);
804674Swnj 		len -= rnd;
814674Swnj 		off += rnd;
824545Swnj 	}
834496Swnj }
844496Swnj 
854693Swnj ip_send(ip)
864693Swnj 	register struct ip *ip;		/* known to be r11 */
874496Swnj {
884496Swnj 	register struct mbuf *m;
894496Swnj 	register struct imp *l;
904693Swnj 	register int hlen = ip->ip_hl << 2;
914545Swnj 	int s;
924496Swnj COUNT(IP_SEND);
934496Swnj 
944693Swnj 	m = dtom(ip);
954496Swnj 	l = (struct imp *)((int)m + m->m_off - L1822);
964693Swnj 	l->i_shost = ip->ip_src.s_host;
974693Swnj 	l->i_dhost = ip->ip_dst.s_host;
984496Swnj 	l->i_type = IPTYPE;
994693Swnj 	ip->ip_sum = 0;
1004693Swnj 	ip->ip_len = htons(ip->ip_len);
1014693Swnj 	ip->ip_id = htons(ip->ip_id);
1024693Swnj 	ip->ip_off = htons(ip->ip_off);
1034693Swnj 	CKSUM_IPSET(m, ip, r11, hlen);
1044693Swnj 	m->m_off -= L1822;
1054496Swnj 	m->m_len += L1822;
1064545Swnj 	m->m_act = NULL;
1074545Swnj #ifndef IMPLOOP
1084662Swnj 	s = splimp();
1094545Swnj 	if (imp_stat.outq_head != NULL)
1104545Swnj 		imp_stat.outq_tail->m_act = m;
1114545Swnj 	else
1124545Swnj 		imp_stat.outq_head = m;
1134545Swnj 	imp_stat.outq_tail = m;
1144545Swnj 	splx(s);
1154545Swnj 	if (!imp_stat.outactive)
1164688Swnj 		enstart(0);
1174545Swnj #else
1184545Swnj 	if (imp_stat.inq_head != NULL)
1194545Swnj 		imp_stat.inq_tail->m_act = m;
1204545Swnj 	else
1214545Swnj 		imp_stat.inq_head = m;
1224545Swnj 	imp_stat.inq_tail = m;
1234724Swnj 	setsoftnet();
1244545Swnj #endif IMPLOOP
1254545Swnj 	return (1);
1264496Swnj }
127