xref: /csrg-svn/sys/netinet/ip_output.c (revision 34500)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  *
12  *	@(#)ip_output.c	7.11 (Berkeley) 05/26/88
13  */
14 
15 #include "param.h"
16 #include "mbuf.h"
17 #include "errno.h"
18 #include "protosw.h"
19 #include "socket.h"
20 #include "socketvar.h"
21 
22 #include "../net/if.h"
23 #include "../net/route.h"
24 
25 #include "in.h"
26 #include "in_pcb.h"
27 #include "in_systm.h"
28 #include "in_var.h"
29 #include "ip.h"
30 #include "ip_var.h"
31 
32 #ifdef vax
33 #include "../machine/mtpr.h"
34 #endif
35 
36 struct mbuf *ip_insertoptions();
37 
38 /*
39  * IP output.  The packet in mbuf chain m contains a skeletal IP
40  * header (with len, off, ttl, proto, tos, src, dst).
41  * The mbuf chain containing the packet will be freed.
42  * The mbuf opt, if present, will not be freed.
43  */
44 ip_output(m0, opt, ro, flags)
45 	struct mbuf *m0;
46 	struct mbuf *opt;
47 	struct route *ro;
48 	int flags;
49 {
50 	register struct ip *ip, *mhip;
51 	register struct ifnet *ifp;
52 	register struct mbuf *m = m0;
53 	register int hlen = sizeof (struct ip);
54 	int len, off, error = 0;
55 	struct route iproute;
56 	struct sockaddr_in *dst;
57 
58 	if (opt) {
59 		m = ip_insertoptions(m, opt, &len);
60 		hlen = len;
61 	}
62 	ip = mtod(m, struct ip *);
63 	/*
64 	 * Fill in IP header.
65 	 */
66 	if ((flags & IP_FORWARDING) == 0) {
67 		ip->ip_v = IPVERSION;
68 		ip->ip_off &= IP_DF;
69 		ip->ip_id = htons(ip_id++);
70 		ip->ip_hl = hlen >> 2;
71 	} else
72 		hlen = ip->ip_hl << 2;
73 
74 	/*
75 	 * Route packet.
76 	 */
77 	if (ro == 0) {
78 		ro = &iproute;
79 		bzero((caddr_t)ro, sizeof (*ro));
80 	}
81 	dst = (struct sockaddr_in *)&ro->ro_dst;
82 	/*
83 	 * If there is a cached route,
84 	 * check that it is to the same destination
85 	 * and is still up.  If not, free it and try again.
86 	 */
87 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
88 	   dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
89 		RTFREE(ro->ro_rt);
90 		ro->ro_rt = (struct rtentry *)0;
91 	}
92 	if (ro->ro_rt == 0) {
93 		dst->sin_family = AF_INET;
94 		dst->sin_addr = ip->ip_dst;
95 	}
96 	/*
97 	 * If routing to interface only,
98 	 * short circuit routing lookup.
99 	 */
100 	if (flags & IP_ROUTETOIF) {
101 		struct in_ifaddr *ia;
102 
103 		ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
104 		if (ia == 0)
105 			ia = in_iaonnetof(in_netof(ip->ip_dst));
106 		if (ia == 0) {
107 			error = ENETUNREACH;
108 			goto bad;
109 		}
110 		ifp = ia->ia_ifp;
111 	} else {
112 		if (ro->ro_rt == 0)
113 			rtalloc(ro);
114 		if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
115 			if (in_localaddr(ip->ip_dst))
116 				error = EHOSTUNREACH;
117 			else
118 				error = ENETUNREACH;
119 			goto bad;
120 		}
121 		ro->ro_rt->rt_use++;
122 		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
123 			dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
124 	}
125 #ifndef notdef
126 	/*
127 	 * If source address not specified yet, use address
128 	 * of outgoing interface.
129 	 */
130 	if (ip->ip_src.s_addr == INADDR_ANY) {
131 		register struct in_ifaddr *ia;
132 
133 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
134 			if (ia->ia_ifp == ifp) {
135 				ip->ip_src = IA_SIN(ia)->sin_addr;
136 				break;
137 			}
138 	}
139 #endif
140 	/*
141 	 * Look for broadcast address and
142 	 * and verify user is allowed to send
143 	 * such a packet.
144 	 */
145 	if (in_broadcast(dst->sin_addr)) {
146 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
147 			error = EADDRNOTAVAIL;
148 			goto bad;
149 		}
150 		if ((flags & IP_ALLOWBROADCAST) == 0) {
151 			error = EACCES;
152 			goto bad;
153 		}
154 		/* don't allow broadcast messages to be fragmented */
155 		if (ip->ip_len > ifp->if_mtu) {
156 			error = EMSGSIZE;
157 			goto bad;
158 		}
159 	}
160 
161 	/*
162 	 * If small enough for interface, can just send directly.
163 	 */
164 	if (ip->ip_len <= ifp->if_mtu) {
165 		ip->ip_len = htons((u_short)ip->ip_len);
166 		ip->ip_off = htons((u_short)ip->ip_off);
167 		ip->ip_sum = 0;
168 		ip->ip_sum = in_cksum(m, hlen);
169 		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
170 		goto done;
171 	}
172 
173 	/*
174 	 * Too large for interface; fragment if possible.
175 	 * Must be able to put at least 8 bytes per fragment.
176 	 */
177 	if (ip->ip_off & IP_DF) {
178 		error = EMSGSIZE;
179 		goto bad;
180 	}
181 	len = (ifp->if_mtu - hlen) &~ 7;
182 	if (len < 8) {
183 		error = EMSGSIZE;
184 		goto bad;
185 	}
186 
187     {
188 	int mhlen, firstlen = len;
189 	struct mbuf **mnext = &m->m_act;
190 
191 	/*
192 	 * Loop through length of segment after first fragment,
193 	 * make new header and copy data of each part and link onto chain.
194 	 */
195 	m0 = m;
196 	mhlen = sizeof (struct ip);
197 	for (off = hlen + len; off < ip->ip_len; off += len) {
198 		MGET(m, M_DONTWAIT, MT_HEADER);
199 		if (m == 0) {
200 			error = ENOBUFS;
201 			goto bad;
202 		}
203 		m->m_off = MMAXOFF - hlen;
204 		mhip = mtod(m, struct ip *);
205 		*mhip = *ip;
206 		if (hlen > sizeof (struct ip)) {
207 			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
208 			mhip->ip_hl = mhlen >> 2;
209 		}
210 		m->m_len = mhlen;
211 		mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
212 		if (ip->ip_off & IP_MF)
213 			mhip->ip_off |= IP_MF;
214 		if (off + len >= ip->ip_len)
215 			len = ip->ip_len - off;
216 		else
217 			mhip->ip_off |= IP_MF;
218 		mhip->ip_len = htons((u_short)(len + mhlen));
219 		m->m_next = m_copy(m0, off, len);
220 		if (m->m_next == 0) {
221 			error = ENOBUFS;	/* ??? */
222 			goto sendorfree;
223 		}
224 		mhip->ip_off = htons((u_short)mhip->ip_off);
225 		mhip->ip_sum = 0;
226 		mhip->ip_sum = in_cksum(m, mhlen);
227 		*mnext = m;
228 		mnext = &m->m_act;
229 	}
230 	/*
231 	 * Update first fragment by trimming what's been copied out
232 	 * and updating header, then send each fragment (in order).
233 	 */
234 	m_adj(m0, hlen + firstlen - ip->ip_len);
235 	ip->ip_len = htons((u_short)(hlen + firstlen));
236 	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
237 	ip->ip_sum = 0;
238 	ip->ip_sum = in_cksum(m0, hlen);
239 sendorfree:
240 	for (m = m0; m; m = m0) {
241 		m0 = m->m_act;
242 		m->m_act = 0;
243 		if (error == 0)
244 			error = (*ifp->if_output)(ifp, m,
245 			    (struct sockaddr *)dst);
246 		else
247 			m_freem(m);
248 	}
249     }
250 done:
251 	if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
252 		RTFREE(ro->ro_rt);
253 	return (error);
254 bad:
255 	m_freem(m0);
256 	goto done;
257 }
258 
259 /*
260  * Insert IP options into preformed packet.
261  * Adjust IP destination as required for IP source routing,
262  * as indicated by a non-zero in_addr at the start of the options.
263  */
264 struct mbuf *
265 ip_insertoptions(m, opt, phlen)
266 	register struct mbuf *m;
267 	struct mbuf *opt;
268 	int *phlen;
269 {
270 	register struct ipoption *p = mtod(opt, struct ipoption *);
271 	struct mbuf *n;
272 	register struct ip *ip = mtod(m, struct ip *);
273 	unsigned optlen;
274 
275 	optlen = opt->m_len - sizeof(p->ipopt_dst);
276 	if (p->ipopt_dst.s_addr)
277 		ip->ip_dst = p->ipopt_dst;
278 	if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) {
279 		MGET(n, M_DONTWAIT, MT_HEADER);
280 		if (n == 0)
281 			return (m);
282 		m->m_len -= sizeof(struct ip);
283 		m->m_off += sizeof(struct ip);
284 		n->m_next = m;
285 		m = n;
286 		m->m_off = MMAXOFF - sizeof(struct ip) - optlen;
287 		m->m_len = optlen + sizeof(struct ip);
288 		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
289 	} else {
290 		m->m_off -= optlen;
291 		m->m_len += optlen;
292 		ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
293 	}
294 	ip = mtod(m, struct ip *);
295 	bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
296 	*phlen = sizeof(struct ip) + optlen;
297 	ip->ip_len += optlen;
298 	return (m);
299 }
300 
301 /*
302  * Copy options from ip to jp,
303  * omitting those not copied during fragmentation.
304  */
305 ip_optcopy(ip, jp)
306 	struct ip *ip, *jp;
307 {
308 	register u_char *cp, *dp;
309 	int opt, optlen, cnt;
310 
311 	cp = (u_char *)(ip + 1);
312 	dp = (u_char *)(jp + 1);
313 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
314 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
315 		opt = cp[0];
316 		if (opt == IPOPT_EOL)
317 			break;
318 		if (opt == IPOPT_NOP)
319 			optlen = 1;
320 		else
321 			optlen = cp[IPOPT_OLEN];
322 		/* bogus lengths should have been caught by ip_dooptions */
323 		if (optlen > cnt)
324 			optlen = cnt;
325 		if (IPOPT_COPIED(opt)) {
326 			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
327 			dp += optlen;
328 		}
329 	}
330 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
331 		*dp++ = IPOPT_EOL;
332 	return (optlen);
333 }
334 
335 /*
336  * IP socket option processing.
337  */
338 ip_ctloutput(op, so, level, optname, m)
339 	int op;
340 	struct socket *so;
341 	int level, optname;
342 	struct mbuf **m;
343 {
344 	int error = 0;
345 	struct inpcb *inp = sotoinpcb(so);
346 
347 	if (level != IPPROTO_IP)
348 		error = EINVAL;
349 	else switch (op) {
350 
351 	case PRCO_SETOPT:
352 		switch (optname) {
353 		case IP_OPTIONS:
354 			return (ip_pcbopts(&inp->inp_options, *m));
355 
356 		default:
357 			error = EINVAL;
358 			break;
359 		}
360 		break;
361 
362 	case PRCO_GETOPT:
363 		switch (optname) {
364 		case IP_OPTIONS:
365 			*m = m_get(M_WAIT, MT_SOOPTS);
366 			if (inp->inp_options) {
367 				(*m)->m_off = inp->inp_options->m_off;
368 				(*m)->m_len = inp->inp_options->m_len;
369 				bcopy(mtod(inp->inp_options, caddr_t),
370 				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
371 			} else
372 				(*m)->m_len = 0;
373 			break;
374 		default:
375 			error = EINVAL;
376 			break;
377 		}
378 		break;
379 	}
380 	if (op == PRCO_SETOPT && *m)
381 		(void)m_free(*m);
382 	return (error);
383 }
384 
385 /*
386  * Set up IP options in pcb for insertion in output packets.
387  * Store in mbuf with pointer in pcbopt, adding pseudo-option
388  * with destination address if source routed.
389  */
390 ip_pcbopts(pcbopt, m)
391 	struct mbuf **pcbopt;
392 	register struct mbuf *m;
393 {
394 	register cnt, optlen;
395 	register u_char *cp;
396 	u_char opt;
397 
398 	/* turn off any old options */
399 	if (*pcbopt)
400 		(void)m_free(*pcbopt);
401 	*pcbopt = 0;
402 	if (m == (struct mbuf *)0 || m->m_len == 0) {
403 		/*
404 		 * Only turning off any previous options.
405 		 */
406 		if (m)
407 			(void)m_free(m);
408 		return (0);
409 	}
410 
411 #ifndef	vax
412 	if (m->m_len % sizeof(long))
413 		goto bad;
414 #endif
415 	/*
416 	 * IP first-hop destination address will be stored before
417 	 * actual options; move other options back
418 	 * and clear it when none present.
419 	 */
420 #if	MAX_IPOPTLEN >= MMAXOFF - MMINOFF
421 	if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN)
422 		goto bad;
423 #else
424 	if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF)
425 		goto bad;
426 #endif
427 	cnt = m->m_len;
428 	m->m_len += sizeof(struct in_addr);
429 	cp = mtod(m, u_char *) + sizeof(struct in_addr);
430 	ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
431 	bzero(mtod(m, caddr_t), sizeof(struct in_addr));
432 
433 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
434 		opt = cp[IPOPT_OPTVAL];
435 		if (opt == IPOPT_EOL)
436 			break;
437 		if (opt == IPOPT_NOP)
438 			optlen = 1;
439 		else {
440 			optlen = cp[IPOPT_OLEN];
441 			if (optlen <= IPOPT_OLEN || optlen > cnt)
442 				goto bad;
443 		}
444 		switch (opt) {
445 
446 		default:
447 			break;
448 
449 		case IPOPT_LSRR:
450 		case IPOPT_SSRR:
451 			/*
452 			 * user process specifies route as:
453 			 *	->A->B->C->D
454 			 * D must be our final destination (but we can't
455 			 * check that since we may not have connected yet).
456 			 * A is first hop destination, which doesn't appear in
457 			 * actual IP option, but is stored before the options.
458 			 */
459 			if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
460 				goto bad;
461 			m->m_len -= sizeof(struct in_addr);
462 			cnt -= sizeof(struct in_addr);
463 			optlen -= sizeof(struct in_addr);
464 			cp[IPOPT_OLEN] = optlen;
465 			/*
466 			 * Move first hop before start of options.
467 			 */
468 			bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
469 			    sizeof(struct in_addr));
470 			/*
471 			 * Then copy rest of options back
472 			 * to close up the deleted entry.
473 			 */
474 			ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
475 			    sizeof(struct in_addr)),
476 			    (caddr_t)&cp[IPOPT_OFFSET+1],
477 			    (unsigned)cnt + sizeof(struct in_addr));
478 			break;
479 		}
480 	}
481 	*pcbopt = m;
482 	return (0);
483 
484 bad:
485 	(void)m_free(m);
486 	return (EINVAL);
487 }
488