|
|
1.1 root 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 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_input.c 7.10 (Berkeley) 6/29/88
18: */
19:
20: #include "param.h"
21: #include "systm.h"
22: #include "mbuf.h"
23: #include "domain.h"
24: #include "protosw.h"
25: #include "socket.h"
26: #include "errno.h"
27: #include "time.h"
28: #include "kernel.h"
29:
30: #include "../net/if.h"
31: #include "../net/route.h"
32:
33: #include "in.h"
34: #include "in_pcb.h"
35: #include "in_systm.h"
36: #include "in_var.h"
37: #include "ip.h"
38: #include "ip_var.h"
39: #include "ip_icmp.h"
40: #include "tcp.h"
41:
42: u_char ip_protox[IPPROTO_MAX];
43: int ipqmaxlen = IFQ_MAXLEN;
44: struct in_ifaddr *in_ifaddr; /* first inet address */
45:
46: /*
47: * We need to save the IP options in case a protocol wants to respond
48: * to an incoming packet over the same route if the packet got here
49: * using IP source routing. This allows connection establishment and
50: * maintenance when the remote end is on a network that is not known
51: * to us.
52: */
53: int ip_nhops = 0;
54: static struct ip_srcrt {
55: char nop; /* one NOP to align */
56: char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */
57: struct in_addr route[MAX_IPOPTLEN];
58: } ip_srcrt;
59:
60: /*
61: * IP initialization: fill in IP protocol switch table.
62: * All protocols not implemented in kernel go to raw IP protocol handler.
63: */
64: ip_init()
65: {
66: register struct protosw *pr;
67: register int i;
68:
69: pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
70: if (pr == 0)
71: panic("ip_init");
72: for (i = 0; i < IPPROTO_MAX; i++)
73: ip_protox[i] = pr - inetsw;
74: for (pr = inetdomain.dom_protosw;
75: pr < inetdomain.dom_protoswNPROTOSW; pr++)
76: if (pr->pr_domain->dom_family == PF_INET &&
77: pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
78: ip_protox[pr->pr_protocol] = pr - inetsw;
79: ipq.next = ipq.prev = &ipq;
80: ip_id = time.tv_sec & 0xffff;
81: ipintrq.ifq_maxlen = ipqmaxlen;
82: }
83:
84: u_char ipcksum = 1;
85: struct ip *ip_reass();
86: struct sockaddr_in ipaddr = { AF_INET };
87: struct route ipforward_rt;
88:
89: /*
90: * Ip input routine. Checksum and byte swap header. If fragmented
91: * try to reassamble. If complete and fragment queue exists, discard.
92: * Process options. Pass to next level.
93: */
94: ipintr()
95: {
96: register struct ip *ip;
97: register struct mbuf *m;
98: struct mbuf *m0;
99: register int i;
100: register struct ipq *fp;
101: register struct in_ifaddr *ia;
102: struct ifnet *ifp;
103: int hlen, s;
104:
105: next:
106: /*
107: * Get next datagram off input queue and get IP header
108: * in first mbuf.
109: */
110: s = splimp();
111: IF_DEQUEUEIF(&ipintrq, m, ifp);
112: splx(s);
113: if (m == 0)
114: return;
115: /*
116: * If no IP addresses have been set yet but the interfaces
117: * are receiving, can't do anything with incoming packets yet.
118: */
119: if (in_ifaddr == NULL)
120: goto bad;
121: ipstat.ips_total++;
122: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
123: (m = m_pullup(m, sizeof (struct ip))) == 0) {
124: ipstat.ips_toosmall++;
125: goto next;
126: }
127: ip = mtod(m, struct ip *);
128: hlen = ip->ip_hl << 2;
129: if (hlen < sizeof(struct ip)) { /* minimum header length */
130: ipstat.ips_badhlen++;
131: goto bad;
132: }
133: if (hlen > m->m_len) {
134: if ((m = m_pullup(m, hlen)) == 0) {
135: ipstat.ips_badhlen++;
136: goto next;
137: }
138: ip = mtod(m, struct ip *);
139: }
140: if (ipcksum)
141: if (ip->ip_sum = in_cksum(m, hlen)) {
142: ipstat.ips_badsum++;
143: goto bad;
144: }
145:
146: /*
147: * Convert fields to host representation.
148: */
149: ip->ip_len = ntohs((u_short)ip->ip_len);
150: if (ip->ip_len < hlen) {
151: ipstat.ips_badlen++;
152: goto bad;
153: }
154: ip->ip_id = ntohs(ip->ip_id);
155: ip->ip_off = ntohs((u_short)ip->ip_off);
156:
157: /*
158: * Check that the amount of data in the buffers
159: * is as at least much as the IP header would have us expect.
160: * Trim mbufs if longer than we expect.
161: * Drop packet if shorter than we expect.
162: */
163: i = -(u_short)ip->ip_len;
164: m0 = m;
165: for (;;) {
166: i += m->m_len;
167: if (m->m_next == 0)
168: break;
169: m = m->m_next;
170: }
171: if (i != 0) {
172: if (i < 0) {
173: ipstat.ips_tooshort++;
174: m = m0;
175: goto bad;
176: }
177: if (i <= m->m_len)
178: m->m_len -= i;
179: else
180: m_adj(m0, -i);
181: }
182: m = m0;
183:
184: /*
185: * Process options and, if not destined for us,
186: * ship it on. ip_dooptions returns 1 when an
187: * error was detected (causing an icmp message
188: * to be sent and the original packet to be freed).
189: */
190: ip_nhops = 0; /* for source routed packets */
191: if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp))
192: goto next;
193:
194: /*
195: * Check our list of addresses, to see if the packet is for us.
196: */
197: for (ia = in_ifaddr; ia; ia = ia->ia_next) {
198: #define satosin(sa) ((struct sockaddr_in *)(sa))
199:
200: if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
201: goto ours;
202: if (
203: #ifdef DIRECTED_BROADCAST
204: ia->ia_ifp == ifp &&
205: #endif
206: (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
207: u_long t;
208:
209: if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
210: ip->ip_dst.s_addr)
211: goto ours;
212: if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
213: goto ours;
214: /*
215: * Look for all-0's host part (old broadcast addr),
216: * either for subnet or net.
217: */
218: t = ntohl(ip->ip_dst.s_addr);
219: if (t == ia->ia_subnet)
220: goto ours;
221: if (t == ia->ia_net)
222: goto ours;
223: }
224: }
225: if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
226: goto ours;
227: if (ip->ip_dst.s_addr == INADDR_ANY)
228: goto ours;
229:
230: /*
231: * Not for us; forward if possible and desirable.
232: */
233: ip_forward(ip, ifp);
234: goto next;
235:
236: ours:
237: /*
238: * If offset or IP_MF are set, must reassemble.
239: * Otherwise, nothing need be done.
240: * (We could look in the reassembly queue to see
241: * if the packet was previously fragmented,
242: * but it's not worth the time; just let them time out.)
243: */
244: if (ip->ip_off &~ IP_DF) {
245: /*
246: * Look for queue of fragments
247: * of this datagram.
248: */
249: for (fp = ipq.next; fp != &ipq; fp = fp->next)
250: if (ip->ip_id == fp->ipq_id &&
251: ip->ip_src.s_addr == fp->ipq_src.s_addr &&
252: ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
253: ip->ip_p == fp->ipq_p)
254: goto found;
255: fp = 0;
256: found:
257:
258: /*
259: * Adjust ip_len to not reflect header,
260: * set ip_mff if more fragments are expected,
261: * convert offset of this to bytes.
262: */
263: ip->ip_len -= hlen;
264: ((struct ipasfrag *)ip)->ipf_mff = 0;
265: if (ip->ip_off & IP_MF)
266: ((struct ipasfrag *)ip)->ipf_mff = 1;
267: ip->ip_off <<= 3;
268:
269: /*
270: * If datagram marked as having more fragments
271: * or if this is not the first fragment,
272: * attempt reassembly; if it succeeds, proceed.
273: */
274: if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
275: ipstat.ips_fragments++;
276: ip = ip_reass((struct ipasfrag *)ip, fp);
277: if (ip == 0)
278: goto next;
279: m = dtom(ip);
280: } else
281: if (fp)
282: ip_freef(fp);
283: } else
284: ip->ip_len -= hlen;
285:
286: /*
287: * Switch out to protocol's input routine.
288: */
289: (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp);
290: goto next;
291: bad:
292: m_freem(m);
293: goto next;
294: }
295:
296: /*
297: * Take incoming datagram fragment and try to
298: * reassemble it into whole datagram. If a chain for
299: * reassembly of this datagram already exists, then it
300: * is given as fp; otherwise have to make a chain.
301: */
302: struct ip *
303: ip_reass(ip, fp)
304: register struct ipasfrag *ip;
305: register struct ipq *fp;
306: {
307: register struct mbuf *m = dtom(ip);
308: register struct ipasfrag *q;
309: struct mbuf *t;
310: int hlen = ip->ip_hl << 2;
311: int i, next;
312:
313: /*
314: * Presence of header sizes in mbufs
315: * would confuse code below.
316: */
317: m->m_off += hlen;
318: m->m_len -= hlen;
319:
320: /*
321: * If first fragment to arrive, create a reassembly queue.
322: */
323: if (fp == 0) {
324: if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
325: goto dropfrag;
326: fp = mtod(t, struct ipq *);
327: insque(fp, &ipq);
328: fp->ipq_ttl = IPFRAGTTL;
329: fp->ipq_p = ip->ip_p;
330: fp->ipq_id = ip->ip_id;
331: fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
332: fp->ipq_src = ((struct ip *)ip)->ip_src;
333: fp->ipq_dst = ((struct ip *)ip)->ip_dst;
334: q = (struct ipasfrag *)fp;
335: goto insert;
336: }
337:
338: /*
339: * Find a segment which begins after this one does.
340: */
341: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
342: if (q->ip_off > ip->ip_off)
343: break;
344:
345: /*
346: * If there is a preceding segment, it may provide some of
347: * our data already. If so, drop the data from the incoming
348: * segment. If it provides all of our data, drop us.
349: */
350: if (q->ipf_prev != (struct ipasfrag *)fp) {
351: i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
352: if (i > 0) {
353: if (i >= ip->ip_len)
354: goto dropfrag;
355: m_adj(dtom(ip), i);
356: ip->ip_off += i;
357: ip->ip_len -= i;
358: }
359: }
360:
361: /*
362: * While we overlap succeeding segments trim them or,
363: * if they are completely covered, dequeue them.
364: */
365: while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
366: i = (ip->ip_off + ip->ip_len) - q->ip_off;
367: if (i < q->ip_len) {
368: q->ip_len -= i;
369: q->ip_off += i;
370: m_adj(dtom(q), i);
371: break;
372: }
373: q = q->ipf_next;
374: m_freem(dtom(q->ipf_prev));
375: ip_deq(q->ipf_prev);
376: }
377:
378: insert:
379: /*
380: * Stick new segment in its place;
381: * check for complete reassembly.
382: */
383: ip_enq(ip, q->ipf_prev);
384: next = 0;
385: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
386: if (q->ip_off != next)
387: return (0);
388: next += q->ip_len;
389: }
390: if (q->ipf_prev->ipf_mff)
391: return (0);
392:
393: /*
394: * Reassembly is complete; concatenate fragments.
395: */
396: q = fp->ipq_next;
397: m = dtom(q);
398: t = m->m_next;
399: m->m_next = 0;
400: m_cat(m, t);
401: q = q->ipf_next;
402: while (q != (struct ipasfrag *)fp) {
403: t = dtom(q);
404: q = q->ipf_next;
405: m_cat(m, t);
406: }
407:
408: /*
409: * Create header for new ip packet by
410: * modifying header of first packet;
411: * dequeue and discard fragment reassembly header.
412: * Make header visible.
413: */
414: ip = fp->ipq_next;
415: ip->ip_len = next;
416: ((struct ip *)ip)->ip_src = fp->ipq_src;
417: ((struct ip *)ip)->ip_dst = fp->ipq_dst;
418: remque(fp);
419: (void) m_free(dtom(fp));
420: m = dtom(ip);
421: m->m_len += (ip->ip_hl << 2);
422: m->m_off -= (ip->ip_hl << 2);
423: return ((struct ip *)ip);
424:
425: dropfrag:
426: ipstat.ips_fragdropped++;
427: m_freem(m);
428: return (0);
429: }
430:
431: /*
432: * Free a fragment reassembly header and all
433: * associated datagrams.
434: */
435: ip_freef(fp)
436: struct ipq *fp;
437: {
438: register struct ipasfrag *q, *p;
439:
440: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
441: p = q->ipf_next;
442: ip_deq(q);
443: m_freem(dtom(q));
444: }
445: remque(fp);
446: (void) m_free(dtom(fp));
447: }
448:
449: /*
450: * Put an ip fragment on a reassembly chain.
451: * Like insque, but pointers in middle of structure.
452: */
453: ip_enq(p, prev)
454: register struct ipasfrag *p, *prev;
455: {
456:
457: p->ipf_prev = prev;
458: p->ipf_next = prev->ipf_next;
459: prev->ipf_next->ipf_prev = p;
460: prev->ipf_next = p;
461: }
462:
463: /*
464: * To ip_enq as remque is to insque.
465: */
466: ip_deq(p)
467: register struct ipasfrag *p;
468: {
469:
470: p->ipf_prev->ipf_next = p->ipf_next;
471: p->ipf_next->ipf_prev = p->ipf_prev;
472: }
473:
474: /*
475: * IP timer processing;
476: * if a timer expires on a reassembly
477: * queue, discard it.
478: */
479: ip_slowtimo()
480: {
481: register struct ipq *fp;
482: int s = splnet();
483:
484: fp = ipq.next;
485: if (fp == 0) {
486: splx(s);
487: return;
488: }
489: while (fp != &ipq) {
490: --fp->ipq_ttl;
491: fp = fp->next;
492: if (fp->prev->ipq_ttl == 0) {
493: ipstat.ips_fragtimeout++;
494: ip_freef(fp->prev);
495: }
496: }
497: splx(s);
498: }
499:
500: /*
501: * Drain off all datagram fragments.
502: */
503: ip_drain()
504: {
505:
506: while (ipq.next != &ipq) {
507: ipstat.ips_fragdropped++;
508: ip_freef(ipq.next);
509: }
510: }
511:
512: extern struct in_ifaddr *ifptoia();
513: struct in_ifaddr *ip_rtaddr();
514:
515: /*
516: * Do option processing on a datagram,
517: * possibly discarding it if bad options
518: * are encountered.
519: */
520: ip_dooptions(ip, ifp)
521: register struct ip *ip;
522: struct ifnet *ifp;
523: {
524: register u_char *cp;
525: int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB;
526: register struct ip_timestamp *ipt;
527: register struct in_ifaddr *ia;
528: struct in_addr *sin;
529: n_time ntime;
530:
531: cp = (u_char *)(ip + 1);
532: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
533: for (; cnt > 0; cnt -= optlen, cp += optlen) {
534: opt = cp[IPOPT_OPTVAL];
535: if (opt == IPOPT_EOL)
536: break;
537: if (opt == IPOPT_NOP)
538: optlen = 1;
539: else {
540: optlen = cp[IPOPT_OLEN];
541: if (optlen <= 0 || optlen > cnt) {
542: code = &cp[IPOPT_OLEN] - (u_char *)ip;
543: goto bad;
544: }
545: }
546: switch (opt) {
547:
548: default:
549: break;
550:
551: /*
552: * Source routing with record.
553: * Find interface with current destination address.
554: * If none on this machine then drop if strictly routed,
555: * or do nothing if loosely routed.
556: * Record interface address and bring up next address
557: * component. If strictly routed make sure next
558: * address on directly accessible net.
559: */
560: case IPOPT_LSRR:
561: case IPOPT_SSRR:
562: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
563: code = &cp[IPOPT_OFFSET] - (u_char *)ip;
564: goto bad;
565: }
566: ipaddr.sin_addr = ip->ip_dst;
567: ia = (struct in_ifaddr *)
568: ifa_ifwithaddr((struct sockaddr *)&ipaddr);
569: if (ia == 0) {
570: if (opt == IPOPT_SSRR) {
571: type = ICMP_UNREACH;
572: code = ICMP_UNREACH_SRCFAIL;
573: goto bad;
574: }
575: /*
576: * Loose routing, and not at next destination
577: * yet; nothing to do except forward.
578: */
579: break;
580: }
581: off--; /* 0 origin */
582: if (off > optlen - sizeof(struct in_addr)) {
583: /*
584: * End of source route. Should be for us.
585: */
586: save_rte(cp, ip->ip_src);
587: break;
588: }
589: /*
590: * locate outgoing interface
591: */
592: bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
593: sizeof(ipaddr.sin_addr));
594: if ((opt == IPOPT_SSRR &&
595: in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
596: (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
597: type = ICMP_UNREACH;
598: code = ICMP_UNREACH_SRCFAIL;
599: goto bad;
600: }
601: ip->ip_dst = ipaddr.sin_addr;
602: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
603: (caddr_t)(cp + off), sizeof(struct in_addr));
604: cp[IPOPT_OFFSET] += sizeof(struct in_addr);
605: break;
606:
607: case IPOPT_RR:
608: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
609: code = &cp[IPOPT_OFFSET] - (u_char *)ip;
610: goto bad;
611: }
612: /*
613: * If no space remains, ignore.
614: */
615: off--; /* 0 origin */
616: if (off > optlen - sizeof(struct in_addr))
617: break;
618: bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
619: sizeof(ipaddr.sin_addr));
620: /*
621: * locate outgoing interface
622: */
623: if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
624: type = ICMP_UNREACH;
625: code = ICMP_UNREACH_HOST;
626: goto bad;
627: }
628: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
629: (caddr_t)(cp + off), sizeof(struct in_addr));
630: cp[IPOPT_OFFSET] += sizeof(struct in_addr);
631: break;
632:
633: case IPOPT_TS:
634: code = cp - (u_char *)ip;
635: ipt = (struct ip_timestamp *)cp;
636: if (ipt->ipt_len < 5)
637: goto bad;
638: if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
639: if (++ipt->ipt_oflw == 0)
640: goto bad;
641: break;
642: }
643: sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
644: switch (ipt->ipt_flg) {
645:
646: case IPOPT_TS_TSONLY:
647: break;
648:
649: case IPOPT_TS_TSANDADDR:
650: if (ipt->ipt_ptr + sizeof(n_time) +
651: sizeof(struct in_addr) > ipt->ipt_len)
652: goto bad;
653: ia = ifptoia(ifp);
654: bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
655: (caddr_t)sin, sizeof(struct in_addr));
656: ipt->ipt_ptr += sizeof(struct in_addr);
657: break;
658:
659: case IPOPT_TS_PRESPEC:
660: if (ipt->ipt_ptr + sizeof(n_time) +
661: sizeof(struct in_addr) > ipt->ipt_len)
662: goto bad;
663: bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
664: sizeof(struct in_addr));
665: if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
666: continue;
667: ipt->ipt_ptr += sizeof(struct in_addr);
668: break;
669:
670: default:
671: goto bad;
672: }
673: ntime = iptime();
674: bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
675: sizeof(n_time));
676: ipt->ipt_ptr += sizeof(n_time);
677: }
678: }
679: return (0);
680: bad:
681: icmp_error(ip, type, code, ifp);
682: return (1);
683: }
684:
685: /*
686: * Given address of next destination (final or next hop),
687: * return internet address info of interface to be used to get there.
688: */
689: struct in_ifaddr *
690: ip_rtaddr(dst)
691: struct in_addr dst;
692: {
693: register struct sockaddr_in *sin;
694: register struct in_ifaddr *ia;
695:
696: sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
697:
698: if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
699: if (ipforward_rt.ro_rt) {
700: RTFREE(ipforward_rt.ro_rt);
701: ipforward_rt.ro_rt = 0;
702: }
703: sin->sin_family = AF_INET;
704: sin->sin_addr = dst;
705:
706: rtalloc(&ipforward_rt);
707: }
708: if (ipforward_rt.ro_rt == 0)
709: return ((struct in_ifaddr *)0);
710: /*
711: * Find address associated with outgoing interface.
712: */
713: for (ia = in_ifaddr; ia; ia = ia->ia_next)
714: if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp)
715: break;
716: return (ia);
717: }
718:
719: /*
720: * Save incoming source route for use in replies,
721: * to be picked up later by ip_srcroute if the receiver is interested.
722: */
723: save_rte(option, dst)
724: u_char *option;
725: struct in_addr dst;
726: {
727: unsigned olen;
728: extern ipprintfs;
729:
730: olen = option[IPOPT_OLEN];
731: if (olen > sizeof(ip_srcrt) - 1) {
732: if (ipprintfs)
733: printf("save_rte: olen %d\n", olen);
734: return;
735: }
736: bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
737: ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
738: ip_srcrt.route[ip_nhops++] = dst;
739: }
740:
741: /*
742: * Retrieve incoming source route for use in replies,
743: * in the same form used by setsockopt.
744: * The first hop is placed before the options, will be removed later.
745: */
746: struct mbuf *
747: ip_srcroute()
748: {
749: register struct in_addr *p, *q;
750: register struct mbuf *m;
751:
752: if (ip_nhops == 0)
753: return ((struct mbuf *)0);
754: m = m_get(M_DONTWAIT, MT_SOOPTS);
755: if (m == 0)
756: return ((struct mbuf *)0);
757: m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
758:
759: /*
760: * First save first hop for return route
761: */
762: p = &ip_srcrt.route[ip_nhops - 1];
763: *(mtod(m, struct in_addr *)) = *p--;
764:
765: /*
766: * Copy option fields and padding (nop) to mbuf.
767: */
768: ip_srcrt.nop = IPOPT_NOP;
769: bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr),
770: IPOPT_OFFSET + 1 + 1);
771: q = (struct in_addr *)(mtod(m, caddr_t) +
772: sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1);
773: /*
774: * Record return path as an IP source route,
775: * reversing the path (pointers are now aligned).
776: */
777: while (p >= ip_srcrt.route)
778: *q++ = *p--;
779: return (m);
780: }
781:
782: /*
783: * Strip out IP options, at higher
784: * level protocol in the kernel.
785: * Second argument is buffer to which options
786: * will be moved, and return value is their length.
787: */
788: ip_stripoptions(ip, mopt)
789: struct ip *ip;
790: struct mbuf *mopt;
791: {
792: register int i;
793: register struct mbuf *m;
794: register caddr_t opts;
795: int olen;
796:
797: olen = (ip->ip_hl<<2) - sizeof (struct ip);
798: m = dtom(ip);
799: opts = (caddr_t)(ip + 1);
800: if (mopt) {
801: mopt->m_len = olen;
802: mopt->m_off = MMINOFF;
803: bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen);
804: }
805: i = m->m_len - (sizeof (struct ip) + olen);
806: bcopy(opts + olen, opts, (unsigned)i);
807: m->m_len -= olen;
808: ip->ip_hl = sizeof(struct ip) >> 2;
809: }
810:
811: u_char inetctlerrmap[PRC_NCMDS] = {
812: 0, 0, 0, 0,
813: 0, 0, EHOSTDOWN, EHOSTUNREACH,
814: ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
815: EMSGSIZE, EHOSTUNREACH, 0, 0,
816: 0, 0, 0, 0,
817: ENOPROTOOPT
818: };
819:
820: #ifndef IPFORWARDING
821: #define IPFORWARDING 1
822: #endif
823: #ifndef IPSENDREDIRECTS
824: #define IPSENDREDIRECTS 1
825: #endif
826: int ipprintfs = 0;
827: int ipforwarding = IPFORWARDING;
828: extern int in_interfaces;
829: int ipsendredirects = IPSENDREDIRECTS;
830:
831: /*
832: * Forward a packet. If some error occurs return the sender
833: * an icmp packet. Note we can't always generate a meaningful
834: * icmp message because icmp doesn't have a large enough repertoire
835: * of codes and types.
836: *
837: * If not forwarding (possibly because we have only a single external
838: * network), just drop the packet. This could be confusing if ipforwarding
839: * was zero but some routing protocol was advancing us as a gateway
840: * to somewhere. However, we must let the routing protocol deal with that.
841: */
842: ip_forward(ip, ifp)
843: register struct ip *ip;
844: struct ifnet *ifp;
845: {
846: register int error, type = 0, code;
847: register struct sockaddr_in *sin;
848: struct mbuf *mcopy;
849: struct in_addr dest;
850:
851: dest.s_addr = 0;
852: if (ipprintfs)
853: printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
854: ip->ip_dst, ip->ip_ttl);
855: ip->ip_id = htons(ip->ip_id);
856: if (ipforwarding == 0 || in_interfaces <= 1) {
857: ipstat.ips_cantforward++;
858: #ifdef GATEWAY
859: type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
860: goto sendicmp;
861: #else
862: m_freem(dtom(ip));
863: return;
864: #endif
865: }
866: if (in_canforward(ip->ip_dst) == 0) {
867: m_freem(dtom(ip));
868: return;
869: }
870: if (ip->ip_ttl <= IPTTLDEC) {
871: type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
872: goto sendicmp;
873: }
874: ip->ip_ttl -= IPTTLDEC;
875:
876: /*
877: * Save at most 64 bytes of the packet in case
878: * we need to generate an ICMP message to the src.
879: */
880: mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
881:
882: sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
883: if (ipforward_rt.ro_rt == 0 ||
884: ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
885: if (ipforward_rt.ro_rt) {
886: RTFREE(ipforward_rt.ro_rt);
887: ipforward_rt.ro_rt = 0;
888: }
889: sin->sin_family = AF_INET;
890: sin->sin_addr = ip->ip_dst;
891:
892: rtalloc(&ipforward_rt);
893: }
894: /*
895: * If forwarding packet using same interface that it came in on,
896: * perhaps should send a redirect to sender to shortcut a hop.
897: * Only send redirect if source is sending directly to us,
898: * and if packet was not source routed (or has any options).
899: * Also, don't send redirect if forwarding using a default route
900: * or a route modfied by a redirect.
901: */
902: #define satosin(sa) ((struct sockaddr_in *)(sa))
903: if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
904: (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
905: satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 &&
906: ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
907: struct in_ifaddr *ia;
908: u_long src = ntohl(ip->ip_src.s_addr);
909: u_long dst = ntohl(ip->ip_dst.s_addr);
910:
911: if ((ia = ifptoia(ifp)) &&
912: (src & ia->ia_subnetmask) == ia->ia_subnet) {
913: if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY)
914: dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr;
915: else
916: dest = ip->ip_dst;
917: /*
918: * If the destination is reached by a route to host,
919: * is on a subnet of a local net, or is directly
920: * on the attached net (!), use host redirect.
921: * (We may be the correct first hop for other subnets.)
922: */
923: type = ICMP_REDIRECT;
924: code = ICMP_REDIRECT_NET;
925: if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) ||
926: (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0)
927: code = ICMP_REDIRECT_HOST;
928: else for (ia = in_ifaddr; ia = ia->ia_next; )
929: if ((dst & ia->ia_netmask) == ia->ia_net) {
930: if (ia->ia_subnetmask != ia->ia_netmask)
931: code = ICMP_REDIRECT_HOST;
932: break;
933: }
934: if (ipprintfs)
935: printf("redirect (%d) to %x\n", code, dest);
936: }
937: }
938:
939: error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt,
940: IP_FORWARDING);
941: if (error)
942: ipstat.ips_cantforward++;
943: else if (type)
944: ipstat.ips_redirectsent++;
945: else {
946: if (mcopy)
947: m_freem(mcopy);
948: ipstat.ips_forward++;
949: return;
950: }
951: if (mcopy == NULL)
952: return;
953: ip = mtod(mcopy, struct ip *);
954: type = ICMP_UNREACH;
955: switch (error) {
956:
957: case 0: /* forwarded, but need redirect */
958: type = ICMP_REDIRECT;
959: /* code set above */
960: break;
961:
962: case ENETUNREACH:
963: case ENETDOWN:
964: if (in_localaddr(ip->ip_dst))
965: code = ICMP_UNREACH_HOST;
966: else
967: code = ICMP_UNREACH_NET;
968: break;
969:
970: case EMSGSIZE:
971: code = ICMP_UNREACH_NEEDFRAG;
972: break;
973:
974: case EPERM:
975: code = ICMP_UNREACH_PORT;
976: break;
977:
978: case ENOBUFS:
979: type = ICMP_SOURCEQUENCH;
980: break;
981:
982: case EHOSTDOWN:
983: case EHOSTUNREACH:
984: code = ICMP_UNREACH_HOST;
985: break;
986: }
987: sendicmp:
988: icmp_error(ip, type, code, ifp, dest);
989: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.