|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)ip_output.c 7.23 (Berkeley) 11/12/90
34: */
35:
36: #include "param.h"
37: #include "malloc.h"
38: #include "mbuf.h"
39: #include "errno.h"
40: #include "protosw.h"
41: #include "socket.h"
42: #include "socketvar.h"
43:
44: #include "../net/if.h"
45: #include "../net/route.h"
46:
47: #include "in.h"
48: #include "in_systm.h"
49: #include "ip.h"
50: #include "in_pcb.h"
51: #include "in_var.h"
52: #include "ip_var.h"
53:
54: #ifdef vax
55: #include "machine/mtpr.h"
56: #endif
57:
58: struct mbuf *ip_insertoptions();
59:
60: /*
61: * IP output. The packet in mbuf chain m contains a skeletal IP
62: * header (with len, off, ttl, proto, tos, src, dst).
63: * The mbuf chain containing the packet will be freed.
64: * The mbuf opt, if present, will not be freed.
65: */
66: ip_output(m0, opt, ro, flags)
67: struct mbuf *m0;
68: struct mbuf *opt;
69: struct route *ro;
70: int flags;
71: {
72: register struct ip *ip, *mhip;
73: register struct ifnet *ifp;
74: register struct mbuf *m = m0;
75: register int hlen = sizeof (struct ip);
76: int len, off, error = 0;
77: struct route iproute;
78: struct sockaddr_in *dst;
79: struct in_ifaddr *ia;
80:
81: #ifdef DIAGNOSTIC
82: if ((m->m_flags & M_PKTHDR) == 0)
83: panic("ip_output no HDR");
84: #endif
85: if (opt) {
86: m = ip_insertoptions(m, opt, &len);
87: hlen = len;
88: }
89: ip = mtod(m, struct ip *);
90: /*
91: * Fill in IP header.
92: */
93: if ((flags & IP_FORWARDING) == 0) {
94: ip->ip_v = IPVERSION;
95: ip->ip_off &= IP_DF;
96: ip->ip_id = htons(ip_id++);
97: ip->ip_hl = hlen >> 2;
98: } else {
99: hlen = ip->ip_hl << 2;
100: ipstat.ips_localout++;
101: }
102: /*
103: * Route packet.
104: */
105: if (ro == 0) {
106: ro = &iproute;
107: bzero((caddr_t)ro, sizeof (*ro));
108: }
109: dst = (struct sockaddr_in *)&ro->ro_dst;
110: /*
111: * If there is a cached route,
112: * check that it is to the same destination
113: * and is still up. If not, free it and try again.
114: */
115: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
116: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
117: RTFREE(ro->ro_rt);
118: ro->ro_rt = (struct rtentry *)0;
119: }
120: if (ro->ro_rt == 0) {
121: dst->sin_family = AF_INET;
122: dst->sin_len = sizeof(*dst);
123: dst->sin_addr = ip->ip_dst;
124: }
125: /*
126: * If routing to interface only,
127: * short circuit routing lookup.
128: */
129: if (flags & IP_ROUTETOIF) {
130:
131: ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
132: if (ia == 0)
133: ia = in_iaonnetof(in_netof(ip->ip_dst));
134: if (ia == 0) {
135: error = ENETUNREACH;
136: goto bad;
137: }
138: ifp = ia->ia_ifp;
139: } else {
140: if (ro->ro_rt == 0)
141: rtalloc(ro);
142: if (ro->ro_rt == 0) {
143: error = EHOSTUNREACH;
144: goto bad;
145: }
146: ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
147: ifp = ro->ro_rt->rt_ifp;
148: ro->ro_rt->rt_use++;
149: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
150: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
151: }
152: #ifndef notdef
153: /*
154: * If source address not specified yet, use address
155: * of outgoing interface.
156: */
157: if (ip->ip_src.s_addr == INADDR_ANY)
158: ip->ip_src = IA_SIN(ia)->sin_addr;
159: #endif
160: /*
161: * Look for broadcast address and
162: * and verify user is allowed to send
163: * such a packet.
164: */
165: if (in_broadcast(dst->sin_addr)) {
166: if ((ifp->if_flags & IFF_BROADCAST) == 0) {
167: error = EADDRNOTAVAIL;
168: goto bad;
169: }
170: if ((flags & IP_ALLOWBROADCAST) == 0) {
171: error = EACCES;
172: goto bad;
173: }
174: /* don't allow broadcast messages to be fragmented */
175: if ((u_short)ip->ip_len > ifp->if_mtu) {
176: error = EMSGSIZE;
177: goto bad;
178: }
179: m->m_flags |= M_BCAST;
180: }
181:
182: /*
183: * If small enough for interface, can just send directly.
184: */
185: if ((u_short)ip->ip_len <= ifp->if_mtu) {
186: ip->ip_len = htons((u_short)ip->ip_len);
187: ip->ip_off = htons((u_short)ip->ip_off);
188: ip->ip_sum = 0;
189: ip->ip_sum = in_cksum(m, hlen);
190: error = (*ifp->if_output)(ifp, m,
191: (struct sockaddr *)dst, ro->ro_rt);
192: goto done;
193: }
194: ipstat.ips_fragmented++;
195: /*
196: * Too large for interface; fragment if possible.
197: * Must be able to put at least 8 bytes per fragment.
198: */
199: if (ip->ip_off & IP_DF) {
200: error = EMSGSIZE;
201: goto bad;
202: }
203: len = (ifp->if_mtu - hlen) &~ 7;
204: if (len < 8) {
205: error = EMSGSIZE;
206: goto bad;
207: }
208:
209: {
210: int mhlen, firstlen = len;
211: struct mbuf **mnext = &m->m_nextpkt;
212:
213: /*
214: * Loop through length of segment after first fragment,
215: * make new header and copy data of each part and link onto chain.
216: */
217: m0 = m;
218: mhlen = sizeof (struct ip);
219: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
220: MGETHDR(m, M_DONTWAIT, MT_HEADER);
221: if (m == 0) {
222: error = ENOBUFS;
223: goto sendorfree;
224: }
225: m->m_data += max_linkhdr;
226: mhip = mtod(m, struct ip *);
227: *mhip = *ip;
228: if (hlen > sizeof (struct ip)) {
229: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
230: mhip->ip_hl = mhlen >> 2;
231: }
232: m->m_len = mhlen;
233: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
234: if (ip->ip_off & IP_MF)
235: mhip->ip_off |= IP_MF;
236: if (off + len >= (u_short)ip->ip_len)
237: len = (u_short)ip->ip_len - off;
238: else
239: mhip->ip_off |= IP_MF;
240: mhip->ip_len = htons((u_short)(len + mhlen));
241: m->m_next = m_copy(m0, off, len);
242: if (m->m_next == 0) {
243: error = ENOBUFS; /* ??? */
244: goto sendorfree;
245: }
246: m->m_pkthdr.len = mhlen + len;
247: m->m_pkthdr.rcvif = (struct ifnet *)0;
248: mhip->ip_off = htons((u_short)mhip->ip_off);
249: mhip->ip_sum = 0;
250: mhip->ip_sum = in_cksum(m, mhlen);
251: *mnext = m;
252: mnext = &m->m_nextpkt;
253: ipstat.ips_ofragments++;
254: }
255: /*
256: * Update first fragment by trimming what's been copied out
257: * and updating header, then send each fragment (in order).
258: */
259: m = m0;
260: m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
261: m->m_pkthdr.len = hlen + firstlen;
262: ip->ip_len = htons((u_short)m->m_pkthdr.len);
263: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
264: ip->ip_sum = 0;
265: ip->ip_sum = in_cksum(m, hlen);
266: sendorfree:
267: for (m = m0; m; m = m0) {
268: m0 = m->m_nextpkt;
269: m->m_nextpkt = 0;
270: if (error == 0)
271: error = (*ifp->if_output)(ifp, m,
272: (struct sockaddr *)dst, ro->ro_rt);
273: else
274: m_freem(m);
275: }
276: }
277: done:
278: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
279: RTFREE(ro->ro_rt);
280: return (error);
281: bad:
282: m_freem(m0);
283: goto done;
284: }
285:
286: /*
287: * Insert IP options into preformed packet.
288: * Adjust IP destination as required for IP source routing,
289: * as indicated by a non-zero in_addr at the start of the options.
290: */
291: struct mbuf *
292: ip_insertoptions(m, opt, phlen)
293: register struct mbuf *m;
294: struct mbuf *opt;
295: int *phlen;
296: {
297: register struct ipoption *p = mtod(opt, struct ipoption *);
298: struct mbuf *n;
299: register struct ip *ip = mtod(m, struct ip *);
300: unsigned optlen;
301:
302: optlen = opt->m_len - sizeof(p->ipopt_dst);
303: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
304: return (m); /* XXX should fail */
305: if (p->ipopt_dst.s_addr)
306: ip->ip_dst = p->ipopt_dst;
307: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
308: MGETHDR(n, M_DONTWAIT, MT_HEADER);
309: if (n == 0)
310: return (m);
311: n->m_pkthdr.len = m->m_pkthdr.len + optlen;
312: m->m_len -= sizeof(struct ip);
313: m->m_data += sizeof(struct ip);
314: n->m_next = m;
315: m = n;
316: m->m_len = optlen + sizeof(struct ip);
317: m->m_data += max_linkhdr;
318: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
319: } else {
320: m->m_data -= optlen;
321: m->m_len += optlen;
322: m->m_pkthdr.len += optlen;
323: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
324: }
325: ip = mtod(m, struct ip *);
326: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
327: *phlen = sizeof(struct ip) + optlen;
328: ip->ip_len += optlen;
329: return (m);
330: }
331:
332: /*
333: * Copy options from ip to jp,
334: * omitting those not copied during fragmentation.
335: */
336: ip_optcopy(ip, jp)
337: struct ip *ip, *jp;
338: {
339: register u_char *cp, *dp;
340: int opt, optlen, cnt;
341:
342: cp = (u_char *)(ip + 1);
343: dp = (u_char *)(jp + 1);
344: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
345: for (; cnt > 0; cnt -= optlen, cp += optlen) {
346: opt = cp[0];
347: if (opt == IPOPT_EOL)
348: break;
349: if (opt == IPOPT_NOP)
350: optlen = 1;
351: else
352: optlen = cp[IPOPT_OLEN];
353: /* bogus lengths should have been caught by ip_dooptions */
354: if (optlen > cnt)
355: optlen = cnt;
356: if (IPOPT_COPIED(opt)) {
357: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
358: dp += optlen;
359: }
360: }
361: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
362: *dp++ = IPOPT_EOL;
363: return (optlen);
364: }
365:
366: /*
367: * IP socket option processing.
368: */
369: ip_ctloutput(op, so, level, optname, mp)
370: int op;
371: struct socket *so;
372: int level, optname;
373: struct mbuf **mp;
374: {
375: register struct inpcb *inp = sotoinpcb(so);
376: register struct mbuf *m = *mp;
377: register int optval;
378: int error = 0;
379:
380: if (level != IPPROTO_IP)
381: error = EINVAL;
382: else switch (op) {
383:
384: case PRCO_SETOPT:
385: switch (optname) {
386: case IP_OPTIONS:
387: #ifdef notyet
388: case IP_RETOPTS:
389: return (ip_pcbopts(optname, &inp->inp_options, m));
390: #else
391: return (ip_pcbopts(&inp->inp_options, m));
392: #endif
393:
394: case IP_TOS:
395: case IP_TTL:
396: case IP_RECVOPTS:
397: case IP_RECVRETOPTS:
398: case IP_RECVDSTADDR:
399: if (m->m_len != sizeof(int))
400: error = EINVAL;
401: else {
402: optval = *mtod(m, int *);
403: switch (optname) {
404:
405: case IP_TOS:
406: inp->inp_ip.ip_tos = optval;
407: break;
408:
409: case IP_TTL:
410: inp->inp_ip.ip_ttl = optval;
411: break;
412: #define OPTSET(bit) \
413: if (optval) \
414: inp->inp_flags |= bit; \
415: else \
416: inp->inp_flags &= ~bit;
417:
418: case IP_RECVOPTS:
419: OPTSET(INP_RECVOPTS);
420: break;
421:
422: case IP_RECVRETOPTS:
423: OPTSET(INP_RECVRETOPTS);
424: break;
425:
426: case IP_RECVDSTADDR:
427: OPTSET(INP_RECVDSTADDR);
428: break;
429: }
430: }
431: break;
432: #undef OPTSET
433:
434: default:
435: error = EINVAL;
436: break;
437: }
438: if (m)
439: (void)m_free(m);
440: break;
441:
442: case PRCO_GETOPT:
443: switch (optname) {
444: case IP_OPTIONS:
445: case IP_RETOPTS:
446: *mp = m = m_get(M_WAIT, MT_SOOPTS);
447: if (inp->inp_options) {
448: m->m_len = inp->inp_options->m_len;
449: bcopy(mtod(inp->inp_options, caddr_t),
450: mtod(m, caddr_t), (unsigned)m->m_len);
451: } else
452: m->m_len = 0;
453: break;
454:
455: case IP_TOS:
456: case IP_TTL:
457: case IP_RECVOPTS:
458: case IP_RECVRETOPTS:
459: case IP_RECVDSTADDR:
460: *mp = m = m_get(M_WAIT, MT_SOOPTS);
461: m->m_len = sizeof(int);
462: switch (optname) {
463:
464: case IP_TOS:
465: optval = inp->inp_ip.ip_tos;
466: break;
467:
468: case IP_TTL:
469: optval = inp->inp_ip.ip_ttl;
470: break;
471:
472: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
473:
474: case IP_RECVOPTS:
475: optval = OPTBIT(INP_RECVOPTS);
476: break;
477:
478: case IP_RECVRETOPTS:
479: optval = OPTBIT(INP_RECVRETOPTS);
480: break;
481:
482: case IP_RECVDSTADDR:
483: optval = OPTBIT(INP_RECVDSTADDR);
484: break;
485: }
486: *mtod(m, int *) = optval;
487: break;
488:
489: default:
490: error = EINVAL;
491: break;
492: }
493: break;
494: }
495: return (error);
496: }
497:
498: /*
499: * Set up IP options in pcb for insertion in output packets.
500: * Store in mbuf with pointer in pcbopt, adding pseudo-option
501: * with destination address if source routed.
502: */
503: #ifdef notyet
504: ip_pcbopts(optname, pcbopt, m)
505: int optname;
506: #else
507: ip_pcbopts(pcbopt, m)
508: #endif
509: struct mbuf **pcbopt;
510: register struct mbuf *m;
511: {
512: register cnt, optlen;
513: register u_char *cp;
514: u_char opt;
515:
516: /* turn off any old options */
517: if (*pcbopt)
518: (void)m_free(*pcbopt);
519: *pcbopt = 0;
520: if (m == (struct mbuf *)0 || m->m_len == 0) {
521: /*
522: * Only turning off any previous options.
523: */
524: if (m)
525: (void)m_free(m);
526: return (0);
527: }
528:
529: #ifndef vax
530: if (m->m_len % sizeof(long))
531: goto bad;
532: #endif
533: /*
534: * IP first-hop destination address will be stored before
535: * actual options; move other options back
536: * and clear it when none present.
537: */
538: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
539: goto bad;
540: cnt = m->m_len;
541: m->m_len += sizeof(struct in_addr);
542: cp = mtod(m, u_char *) + sizeof(struct in_addr);
543: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
544: bzero(mtod(m, caddr_t), sizeof(struct in_addr));
545:
546: for (; cnt > 0; cnt -= optlen, cp += optlen) {
547: opt = cp[IPOPT_OPTVAL];
548: if (opt == IPOPT_EOL)
549: break;
550: if (opt == IPOPT_NOP)
551: optlen = 1;
552: else {
553: optlen = cp[IPOPT_OLEN];
554: if (optlen <= IPOPT_OLEN || optlen > cnt)
555: goto bad;
556: }
557: switch (opt) {
558:
559: default:
560: break;
561:
562: case IPOPT_LSRR:
563: case IPOPT_SSRR:
564: /*
565: * user process specifies route as:
566: * ->A->B->C->D
567: * D must be our final destination (but we can't
568: * check that since we may not have connected yet).
569: * A is first hop destination, which doesn't appear in
570: * actual IP option, but is stored before the options.
571: */
572: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
573: goto bad;
574: m->m_len -= sizeof(struct in_addr);
575: cnt -= sizeof(struct in_addr);
576: optlen -= sizeof(struct in_addr);
577: cp[IPOPT_OLEN] = optlen;
578: /*
579: * Move first hop before start of options.
580: */
581: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
582: sizeof(struct in_addr));
583: /*
584: * Then copy rest of options back
585: * to close up the deleted entry.
586: */
587: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
588: sizeof(struct in_addr)),
589: (caddr_t)&cp[IPOPT_OFFSET+1],
590: (unsigned)cnt + sizeof(struct in_addr));
591: break;
592: }
593: }
594: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
595: goto bad;
596: *pcbopt = m;
597: return (0);
598:
599: bad:
600: (void)m_free(m);
601: return (EINVAL);
602: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.