xref: /csrg-svn/sys/netinet/ip_output.c (revision 4924)
1 /*	ip_output.c	1.14	81/11/18	*/
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/mtpr.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.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(m)
16 	struct mbuf *m;
17 {
18 	register struct ip *ip = mtod(m, struct ip *);
19 	int len, hlen = ip->ip_hl << 2, off;
20 
21 COUNT(IP_OUTPUT);
22 	/*
23 	 * Fill in IP header.
24 	 */
25 	ip->ip_v = IPVERSION;
26 	ip->ip_hl = hlen >> 2;
27 	ip->ip_off &= IP_DF;
28 	ip->ip_ttl = MAXTTL;
29 	ip->ip_id = ip_id++;
30 
31 	/*
32 	 * If small enough for interface, can just send directly.
33 	 */
34 	if (ip->ip_len <= MTU) {
35 		ip_send(ip);
36 		return;
37 	}
38 
39 	/*
40 	 * Too large for interface; fragment if possible.
41 	 * Must be able to put at least 8 bytes per fragment.
42 	 */
43 	if (ip->ip_off & IP_DF)
44 		goto bad;
45 	len = (MTU-hlen) &~ 7;
46 	if (len < 8)
47 		goto bad;
48 
49 	/*
50 	 * Discard IP header from logical mbuf for m_copy's sake.
51 	 * Loop through length of segment, make a copy of each
52 	 * part and output.
53 	 */
54 	m->m_len -= sizeof (struct ip);
55 	m->m_off += sizeof (struct ip);
56 	for (off = 0; off < ip->ip_len; off += len) {
57 		struct mbuf *mh = m_get(0);
58 		struct ip *mhip;
59 
60 		if (mh == 0)
61 			goto bad;
62 		mh->m_off = MMAXOFF - hlen;
63 		mhip = mtod(mh, struct ip *);
64 		*mhip = *ip;
65 		if (ip->ip_hl > sizeof (struct ip) >> 2) {
66 			int olen = ip_optcopy(ip, mhip, off);
67 			mh->m_len = sizeof (struct ip) + olen;
68 		} else
69 			mh->m_len = sizeof (struct ip);
70 		mhip->ip_off = off;
71 		if (off + len >= ip->ip_len)
72 			mhip->ip_len = ip->ip_len - off;
73 		else {
74 			mhip->ip_len = len;
75 			mhip->ip_off |= IP_MF;
76 		}
77 		mh->m_next = m_copy(m, off, len);
78 		if (mh->m_next == 0) {
79 			m_free(mh);
80 			goto bad;
81 		}
82 		ip_send(mh);
83 	}
84 bad:
85 	m_freem(m);
86 }
87 
88 /*
89  * Copy options from ip to jp.
90  * If off is 0 all options are copies
91  * otherwise copy selectively.
92  */
93 ip_optcopy(ip, jp, off)
94 	struct ip *ip, *jp;
95 	int off;
96 {
97 	register u_char *cp, *dp;
98 	int opt, optlen, cnt;
99 
100 	cp = (u_char *)(ip + 1);
101 	dp = (u_char *)(jp + 1);
102 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
103 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
104 		opt = cp[0];
105 		if (opt == IPOPT_EOL)
106 			break;
107 		if (opt == IPOPT_NOP)
108 			optlen = 1;
109 		else
110 			optlen = cp[1];
111 		if (optlen > cnt)			/* XXX */
112 			optlen = cnt;			/* XXX */
113 		if (off == 0 || IPOPT_COPIED(opt)) {
114 			bcopy(cp, dp, optlen);
115 			dp += optlen;
116 		}
117 	}
118 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
119 		*dp++ = IPOPT_EOL;
120 	return (optlen);
121 }
122 
123 ip_send(ip)
124 	register struct ip *ip;
125 {
126 	register struct mbuf *m;
127 	register struct imp *l;
128 	int hlen = ip->ip_hl << 2;
129 	int s;
130 COUNT(IP_SEND);
131 
132 	m = dtom(ip);
133 	l = (struct imp *)(mtod(m, caddr_t) - L1822);
134 	l->i_shost = ip->ip_src.s_host;
135 	l->i_dhost = ip->ip_dst.s_host;
136 	l->i_type = IPTYPE;
137 	ip->ip_sum = 0;
138 	ip->ip_len = htons((u_short)ip->ip_len);
139 	ip->ip_id = htons(ip->ip_id);
140 	ip->ip_off = htons((u_short)ip->ip_off);
141 	ip->ip_sum = inet_cksum(m, hlen);
142 	m->m_off -= L1822;
143 	m->m_len += L1822;
144 	m->m_act = NULL;
145 #ifndef IMPLOOP
146 	s = splimp();
147 	if (imp_stat.outq_head != NULL)
148 		imp_stat.outq_tail->m_act = m;
149 	else
150 		imp_stat.outq_head = m;
151 	imp_stat.outq_tail = m;
152 	splx(s);
153 	if (!imp_stat.outactive)
154 		enstart(0);
155 #else
156 	if (imp_stat.inq_head != NULL)
157 		imp_stat.inq_tail->m_act = m;
158 	else
159 		imp_stat.inq_head = m;
160 	imp_stat.inq_tail = m;
161 	setsoftnet();
162 #endif IMPLOOP
163 }
164