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