# 2.11BSD#431 - /usr/src/sys/netinet/ip_input.c

##### Functions

    ip_deq            X
    ip_dooptions      X
    ip_drain          X
    ip_enq            X
    ip_forward        X
    ip_freef          X
    ip_init           X
    ip_reass          X
    ip_rtaddr         X
    ip_slowtimo       X
    ip_srcroute       X
    ip_stripoptions   X
    ip_sysctl         X
    ipintr            X
    save_rte          X

##### Variables

    in_ifaddr         X
    inetctlerrmap     X
    ip_nhops          X
    ip_protox         X
    ipaddr            X
    ipcksum           X
    ipforward_rt      X
    ipprintfs         X
    ipqmaxlen         X

##### Macros

    satosin           X

##### struct's

    ip_srcrt          X

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

#### Defined functions

ip_deq defined in line 470; used 2 times

- in line 379, 446

ip_dooptions defined in line 524; used 1 times

- in line 191

ip_drain defined in line 507; never used
ip_enq defined in line 457; used 1 times

- in line 387

ip_forward defined in line 854; used 2 times

- in line 237, 694

ip_freef defined in line 439; used 3 times

- in line 286, 498, 512

ip_init defined in line 61; never used
ip_reass defined in line 306; used 2 times

- in line 85, 280

ip_rtaddr defined in line 708; used 3 times

- in line 517, 600, 632

ip_slowtimo defined in line 483; never used
ip_srcroute defined in line 764; never used
ip_stripoptions defined in line 806; never used
ip_sysctl defined in line 1002; never used
ipintr defined in line 94; never used
save_rte defined in line 742; used 1 times

- in line 590

#### Defined variables

in_ifaddr defined in line 41; used 4 times

- in line 119, 197, 732, 938

inetctlerrmap defined in line 829; never used
ip_nhops defined in line 50; used 6 times

- in line 190, 755-756(2), 770-780(3)

ip_protox defined in line 38; used 3 times

- in line 72-77(2), 293

ip_srcrt defined in line 55; used 7 times

- in line 749-756(3), 780, 786-787(2), 795

ipaddr defined in line 86; used 12 times

- in line 570-572(2), 596-605(5), 627-632(3), 672-674(2)

ipcksum defined in line 84; used 1 times

- in line 140

ipforward_rt defined in line 87; used 24 times

- in line 715-727(7), 733, 880-891(7), 913-915(4), 923-924(2), 935-936(2), 949

ipprintfs defined in line 40; used 3 times

- in line 750, 865, 944

ipqmaxlen defined in line 39; used 1 times

- in line 81

#### Defined struct's

ip_srcrt defined in line 51; never used

#### Defined macros

satosin defined in line 912; used 3 times

- in line 209, 915, 924

Last modified: 1995-10-12 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2553 |