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