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