xref: /csrg-svn/sys/netinet/ip_output.c (revision 4899)
1 /* ip_output.c 1.12 81/11/15 */
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/mtpr.h"
6 #include "../h/socket.h"
7 #include "../net/inet_cksum.h"
8 #include "../net/inet.h"
9 #include "../net/inet_systm.h"
10 #include "../net/imp.h"
11 #include "../net/inet_host.h"
12 #include "../net/ip.h"
13 #include "../net/ip_var.h"
14 
15 ip_output(mp)
16 	struct mbuf *mp;
17 {
18 	register i, rnd;
19 	register struct mbuf *m, *n;
20 	register struct ip *p;
21 	struct mbuf *mm;
22 	int hlen, adj, max, len, off;
23 
24 COUNT(IP_OUTPUT);
25 	p = mtod(mp, struct ip *);
26 	hlen = sizeof (struct ip);
27 
28 	/*
29 	 * Fill in and byte swap ip header.
30 	 */
31 	p->ip_v = IPVERSION;
32 	p->ip_hl = hlen >> 2;
33 	p->ip_off = 0 | (p->ip_off & IP_DF);
34 	p->ip_ttl = MAXTTL;
35 /*###35 [cc] ip_id undefined %%%*/
36 	p->ip_id = ip_id++;
37 
38 	if (p->ip_len <= MTU)
39 		return (ip_send(p));
40 	if (p->ip_off & IP_DF)
41 		return (0);
42 	max = MTU - hlen;
43 	len = p->ip_len - hlen;
44 	off = 0;
45 	m = mp;
46 	while (len > 0) {
47 		p->ip_off |= off >> 3;
48 		i = -hlen;
49 		while (m != NULL) {
50 			i += m->m_len;
51 			if (i > max)
52 				break;
53 			n = m;
54 			m = m->m_next;
55 		}
56 		if (i < max || m == NULL) {
57 			p->ip_off = p->ip_off &~ IP_MF;
58 			p->ip_len = i + hlen;
59 			return (ip_send(p));
60 		}
61 		if ((mm = m_get(1)) == NULL)    /* no more bufs */
62 			return(0);
63 		p->ip_off |= IP_MF;
64 		i -= m->m_len;
65 		rnd = i & ~7;
66 		adj = i - rnd;
67 		p->ip_len = rnd + hlen;
68 		n->m_next = NULL;
69 		mm->m_next = m;
70 		m = mm;
71 		m->m_off = MMAXOFF - hlen - adj;
72 		m->m_len = hlen + adj;
73 		bcopy(p, (caddr_t)((int)m + m->m_off), hlen);
74 		if (adj) {
75 			n->m_len -= adj;
76 			bcopy((caddr_t)((int)n + n->m_len + n->m_off),
77 			      (caddr_t)((int)m + m->m_off + hlen), adj);
78 		}
79 		ip_send(p);
80 		p = (struct ip *)((int)m + m->m_off);
81 		len -= rnd;
82 		off += rnd;
83 	}
84 }
85 
86 ip_send(ip)
87 	register struct ip *ip;		/* known to be r11 */
88 {
89 	register struct mbuf *m;
90 	register struct imp *l;
91 	register int hlen = ip->ip_hl << 2;
92 	int s;
93 COUNT(IP_SEND);
94 
95 	m = dtom(ip);
96 	l = (struct imp *)((int)m + m->m_off - L1822);
97 	l->i_shost = ip->ip_src.s_host;
98 	l->i_dhost = ip->ip_dst.s_host;
99 	l->i_type = IPTYPE;
100 	ip->ip_sum = 0;
101 	ip->ip_len = htons(ip->ip_len);
102 	ip->ip_id = htons(ip->ip_id);
103 	ip->ip_off = htons(ip->ip_off);
104 	CKSUM_IPSET(m, ip, r11, hlen);
105 	m->m_off -= L1822;
106 	m->m_len += L1822;
107 	m->m_act = NULL;
108 #ifndef IMPLOOP
109 	s = splimp();
110 	if (imp_stat.outq_head != NULL)
111 		imp_stat.outq_tail->m_act = m;
112 	else
113 		imp_stat.outq_head = m;
114 	imp_stat.outq_tail = m;
115 	splx(s);
116 	if (!imp_stat.outactive)
117 		enstart(0);
118 #else
119 	if (imp_stat.inq_head != NULL)
120 		imp_stat.inq_tail->m_act = m;
121 	else
122 		imp_stat.inq_head = m;
123 	imp_stat.inq_tail = m;
124 	setsoftnet();
125 #endif IMPLOOP
126 	return (1);
127 }
128