The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/icmp6.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Internet Control Message Protocol for IPv6
    3  */
    4 #include "u.h"
    5 #include "../port/lib.h"
    6 #include "mem.h"
    7 #include "dat.h"
    8 #include "fns.h"
    9 #include "../port/error.h"
   10 #include "ip.h"
   11 #include "ipv6.h"
   12 
   13 enum
   14 {
   15         InMsgs6,
   16         InErrors6,
   17         OutMsgs6,
   18         CsumErrs6,
   19         LenErrs6,
   20         HlenErrs6,
   21         HoplimErrs6,
   22         IcmpCodeErrs6,
   23         TargetErrs6,
   24         OptlenErrs6,
   25         AddrmxpErrs6,
   26         RouterAddrErrs6,
   27 
   28         Nstats6,
   29 };
   30 
   31 enum {
   32         ICMP_USEAD6     = 40,
   33 };
   34 
   35 enum {
   36         Oflag   = 1<<5,
   37         Sflag   = 1<<6,
   38         Rflag   = 1<<7,
   39 };
   40 
   41 enum {
   42         /* ICMPv6 types */
   43         EchoReply       = 0,
   44         UnreachableV6   = 1,
   45         PacketTooBigV6  = 2,
   46         TimeExceedV6    = 3,
   47         SrcQuench       = 4,
   48         ParamProblemV6  = 4,
   49         Redirect        = 5,
   50         EchoRequest     = 8,
   51         TimeExceed      = 11,
   52         InParmProblem   = 12,
   53         Timestamp       = 13,
   54         TimestampReply  = 14,
   55         InfoRequest     = 15,
   56         InfoReply       = 16,
   57         AddrMaskRequest = 17,
   58         AddrMaskReply   = 18,
   59         EchoRequestV6   = 128,
   60         EchoReplyV6     = 129,
   61         RouterSolicit   = 133,
   62         RouterAdvert    = 134,
   63         NbrSolicit      = 135,
   64         NbrAdvert       = 136,
   65         RedirectV6      = 137,
   66 
   67         Maxtype6        = 137,
   68 };
   69 
   70 typedef struct ICMPpkt ICMPpkt;
   71 typedef struct IPICMP IPICMP;
   72 typedef struct Ndpkt Ndpkt;
   73 typedef struct NdiscC NdiscC;
   74 
   75 struct ICMPpkt {
   76         uchar   type;
   77         uchar   code;
   78         uchar   cksum[2];
   79         uchar   icmpid[2];
   80         uchar   seq[2];
   81 };
   82 
   83 struct IPICMP {
   84         Ip6hdr;
   85         ICMPpkt;
   86 };
   87 
   88 struct NdiscC
   89 {
   90         IPICMP;
   91         uchar   target[IPaddrlen];
   92 };
   93 
   94 struct Ndpkt
   95 {
   96         NdiscC;
   97         uchar   otype;
   98         uchar   olen;           /* length in units of 8 octets(incl type, code),
   99                                  * 1 for IEEE 802 addresses */
  100         uchar   lnaddr[6];      /* link-layer address */
  101 };
  102 
  103 typedef struct Icmppriv6
  104 {
  105         ulong   stats[Nstats6];
  106 
  107         /* message counts */
  108         ulong   in[Maxtype6+1];
  109         ulong   out[Maxtype6+1];
  110 } Icmppriv6;
  111 
  112 typedef struct Icmpcb6
  113 {
  114         QLock;
  115         uchar   headers;
  116 } Icmpcb6;
  117 
  118 char *icmpnames6[Maxtype6+1] =
  119 {
  120 [EchoReply]             "EchoReply",
  121 [UnreachableV6]         "UnreachableV6",
  122 [PacketTooBigV6]        "PacketTooBigV6",
  123 [TimeExceedV6]          "TimeExceedV6",
  124 [SrcQuench]             "SrcQuench",
  125 [Redirect]              "Redirect",
  126 [EchoRequest]           "EchoRequest",
  127 [TimeExceed]            "TimeExceed",
  128 [InParmProblem]         "InParmProblem",
  129 [Timestamp]             "Timestamp",
  130 [TimestampReply]        "TimestampReply",
  131 [InfoRequest]           "InfoRequest",
  132 [InfoReply]             "InfoReply",
  133 [AddrMaskRequest]       "AddrMaskRequest",
  134 [AddrMaskReply]         "AddrMaskReply",
  135 [EchoRequestV6]         "EchoRequestV6",
  136 [EchoReplyV6]           "EchoReplyV6",
  137 [RouterSolicit]         "RouterSolicit",
  138 [RouterAdvert]          "RouterAdvert",
  139 [NbrSolicit]            "NbrSolicit",
  140 [NbrAdvert]             "NbrAdvert",
  141 [RedirectV6]            "RedirectV6",
  142 };
  143 
  144 static char *statnames6[Nstats6] =
  145 {
  146 [InMsgs6]       "InMsgs",
  147 [InErrors6]     "InErrors",
  148 [OutMsgs6]      "OutMsgs",
  149 [CsumErrs6]     "CsumErrs",
  150 [LenErrs6]      "LenErrs",
  151 [HlenErrs6]     "HlenErrs",
  152 [HoplimErrs6]   "HoplimErrs",
  153 [IcmpCodeErrs6] "IcmpCodeErrs",
  154 [TargetErrs6]   "TargetErrs",
  155 [OptlenErrs6]   "OptlenErrs",
  156 [AddrmxpErrs6]  "AddrmxpErrs",
  157 [RouterAddrErrs6]       "RouterAddrErrs",
  158 };
  159 
  160 static char *unreachcode[] =
  161 {
  162 [Icmp6_no_route]        "no route to destination",
  163 [Icmp6_ad_prohib]       "comm with destination administratively prohibited",
  164 [Icmp6_out_src_scope]   "beyond scope of source address",
  165 [Icmp6_adr_unreach]     "address unreachable",
  166 [Icmp6_port_unreach]    "port unreachable",
  167 [Icmp6_gress_src_fail]  "source address failed ingress/egress policy",
  168 [Icmp6_rej_route]       "reject route to destination",
  169 [Icmp6_unknown]         "icmp unreachable: unknown code",
  170 };
  171 
  172 static void icmpkick6(void *x, Block *bp);
  173 
  174 static void
  175 icmpcreate6(Conv *c)
  176 {
  177         c->rq = qopen(64*1024, Qmsg, 0, c);
  178         c->wq = qbypass(icmpkick6, c);
  179 }
  180 
  181 static void
  182 set_cksum(Block *bp)
  183 {
  184         IPICMP *p = (IPICMP *)(bp->rp);
  185 
  186         hnputl(p->vcf, 0);      /* borrow IP header as pseudoheader */
  187         hnputs(p->ploadlen, blocklen(bp) - IP6HDR);
  188         p->proto = 0;
  189         p->ttl = ICMPv6;        /* ttl gets set later */
  190         hnputs(p->cksum, 0);
  191         hnputs(p->cksum, ptclcsum(bp, 0, blocklen(bp)));
  192         p->proto = ICMPv6;
  193 }
  194 
  195 static Block *
  196 newIPICMP(int packetlen)
  197 {
  198         Block *nbp;
  199 
  200         nbp = allocb(packetlen);
  201         nbp->wp += packetlen;
  202         memset(nbp->rp, 0, packetlen);
  203         return nbp;
  204 }
  205 
  206 void
  207 icmpadvise6(Proto *icmp, Block *bp, char *msg)
  208 {
  209         ushort recid;
  210         Conv **c, *s;
  211         IPICMP *p;
  212 
  213         p = (IPICMP *)bp->rp;
  214         recid = nhgets(p->icmpid);
  215 
  216         for(c = icmp->conv; *c; c++) {
  217                 s = *c;
  218                 if(s->lport == recid && ipcmp(s->raddr, p->dst) == 0){
  219                         qhangup(s->rq, msg);
  220                         qhangup(s->wq, msg);
  221                         break;
  222                 }
  223         }
  224         freeblist(bp);
  225 }
  226 
  227 static void
  228 icmpkick6(void *x, Block *bp)
  229 {
  230         uchar laddr[IPaddrlen], raddr[IPaddrlen];
  231         Conv *c = x;
  232         IPICMP *p;
  233         Icmppriv6 *ipriv = c->p->priv;
  234         Icmpcb6 *icb = (Icmpcb6*)c->ptcl;
  235 
  236         if(bp == nil)
  237                 return;
  238 
  239         if(icb->headers==6) {
  240                 /* get user specified addresses */
  241                 bp = pullupblock(bp, ICMP_USEAD6);
  242                 if(bp == nil)
  243                         return;
  244                 bp->rp += 8;
  245                 ipmove(laddr, bp->rp);
  246                 bp->rp += IPaddrlen;
  247                 ipmove(raddr, bp->rp);
  248                 bp->rp += IPaddrlen;
  249                 bp = padblock(bp, sizeof(Ip6hdr));
  250         }
  251 
  252         if(blocklen(bp) < sizeof(IPICMP)){
  253                 freeblist(bp);
  254                 return;
  255         }
  256         p = (IPICMP *)(bp->rp);
  257         if(icb->headers == 6) {
  258                 ipmove(p->dst, raddr);
  259                 ipmove(p->src, laddr);
  260         } else {
  261                 ipmove(p->dst, c->raddr);
  262                 ipmove(p->src, c->laddr);
  263                 hnputs(p->icmpid, c->lport);
  264         }
  265 
  266         set_cksum(bp);
  267         p->vcf[0] = 0x06 << 4;
  268         if(p->type <= Maxtype6)
  269                 ipriv->out[p->type]++;
  270         ipoput6(c->p->f, bp, 0, c->ttl, c->tos, nil);
  271 }
  272 
  273 char*
  274 icmpctl6(Conv *c, char **argv, int argc)
  275 {
  276         Icmpcb6 *icb;
  277 
  278         icb = (Icmpcb6*) c->ptcl;
  279         if(argc==1 && strcmp(argv[0], "headers")==0) {
  280                 icb->headers = 6;
  281                 return nil;
  282         }
  283         return "unknown control request";
  284 }
  285 
  286 static void
  287 goticmpkt6(Proto *icmp, Block *bp, int muxkey)
  288 {
  289         ushort recid;
  290         uchar *addr;
  291         Conv **c, *s;
  292         IPICMP *p = (IPICMP *)bp->rp;
  293 
  294         if(muxkey == 0) {
  295                 recid = nhgets(p->icmpid);
  296                 addr = p->src;
  297         } else {
  298                 recid = muxkey;
  299                 addr = p->dst;
  300         }
  301 
  302         for(c = icmp->conv; *c; c++){
  303                 s = *c;
  304                 if(s->lport == recid && ipcmp(s->raddr, addr) == 0){
  305                         bp = concatblock(bp);
  306                         if(bp != nil)
  307                                 qpass(s->rq, bp);
  308                         return;
  309                 }
  310         }
  311 
  312         freeblist(bp);
  313 }
  314 
  315 static Block *
  316 mkechoreply6(Block *bp, Ipifc *ifc)
  317 {
  318         uchar addr[IPaddrlen];
  319         IPICMP *p = (IPICMP *)(bp->rp);
  320 
  321         ipmove(addr, p->src);
  322         if(!isv6mcast(p->dst))
  323                 ipmove(p->src, p->dst);
  324         else if (!ipv6anylocal(ifc, p->src))
  325                 return nil;
  326         ipmove(p->dst, addr);
  327         p->type = EchoReplyV6;
  328         set_cksum(bp);
  329         return bp;
  330 }
  331 
  332 /*
  333  * sends out an ICMPv6 neighbor solicitation
  334  *      suni == SRC_UNSPEC or SRC_UNI,
  335  *      tuni == TARG_MULTI => multicast for address resolution,
  336  *      and tuni == TARG_UNI => neighbor reachability.
  337  */
  338 extern void
  339 icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac)
  340 {
  341         Block *nbp;
  342         Ndpkt *np;
  343         Proto *icmp = f->t2p[ICMPv6];
  344         Icmppriv6 *ipriv = icmp->priv;
  345 
  346         nbp = newIPICMP(sizeof(Ndpkt));
  347         np = (Ndpkt*) nbp->rp;
  348 
  349         if(suni == SRC_UNSPEC)
  350                 memmove(np->src, v6Unspecified, IPaddrlen);
  351         else
  352                 memmove(np->src, src, IPaddrlen);
  353 
  354         if(tuni == TARG_UNI)
  355                 memmove(np->dst, targ, IPaddrlen);
  356         else
  357                 ipv62smcast(np->dst, targ);
  358 
  359         np->type = NbrSolicit;
  360         np->code = 0;
  361         memmove(np->target, targ, IPaddrlen);
  362         if(suni != SRC_UNSPEC) {
  363                 np->otype = SRC_LLADDR;
  364                 np->olen = 1;           /* 1+1+6 = 8 = 1 8-octet */
  365                 memmove(np->lnaddr, mac, sizeof(np->lnaddr));
  366         } else
  367                 nbp->wp -= sizeof(Ndpkt) - sizeof(NdiscC);
  368 
  369         set_cksum(nbp);
  370         np = (Ndpkt*)nbp->rp;
  371         np->ttl = HOP_LIMIT;
  372         np->vcf[0] = 0x06 << 4;
  373         ipriv->out[NbrSolicit]++;
  374         netlog(f, Logicmp, "sending neighbor solicitation %I\n", targ);
  375         ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  376 }
  377 
  378 /*
  379  * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags.
  380  */
  381 extern void
  382 icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags)
  383 {
  384         Block *nbp;
  385         Ndpkt *np;
  386         Proto *icmp = f->t2p[ICMPv6];
  387         Icmppriv6 *ipriv = icmp->priv;
  388 
  389         nbp = newIPICMP(sizeof(Ndpkt));
  390         np = (Ndpkt*)nbp->rp;
  391 
  392         memmove(np->src, src, IPaddrlen);
  393         memmove(np->dst, dst, IPaddrlen);
  394 
  395         np->type = NbrAdvert;
  396         np->code = 0;
  397         np->icmpid[0] = flags;
  398         memmove(np->target, targ, IPaddrlen);
  399 
  400         np->otype = TARGET_LLADDR;
  401         np->olen = 1;
  402         memmove(np->lnaddr, mac, sizeof(np->lnaddr));
  403 
  404         set_cksum(nbp);
  405         np = (Ndpkt*) nbp->rp;
  406         np->ttl = HOP_LIMIT;
  407         np->vcf[0] = 0x06 << 4;
  408         ipriv->out[NbrAdvert]++;
  409         netlog(f, Logicmp, "sending neighbor advertisement %I\n", src);
  410         ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  411 }
  412 
  413 extern void
  414 icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
  415 {
  416         int osz = BLEN(bp);
  417         int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  418         Block *nbp;
  419         IPICMP *np;
  420         Ip6hdr *p;
  421         Proto *icmp = f->t2p[ICMPv6];
  422         Icmppriv6 *ipriv = icmp->priv;
  423 
  424         p = (Ip6hdr *)bp->rp;
  425 
  426         if(isv6mcast(p->src))
  427                 goto clean;
  428 
  429         nbp = newIPICMP(sz);
  430         np = (IPICMP *)nbp->rp;
  431 
  432         rlock(ifc);
  433         if(ipv6anylocal(ifc, np->src))
  434                 netlog(f, Logicmp, "send icmphostunr -> s%I d%I\n",
  435                         p->src, p->dst);
  436         else {
  437                 netlog(f, Logicmp, "icmphostunr fail -> s%I d%I\n",
  438                         p->src, p->dst);
  439                 freeblist(nbp);
  440                 if(free)
  441                         goto clean;
  442                 else
  443                         return;
  444         }
  445 
  446         memmove(np->dst, p->src, IPaddrlen);
  447         np->type = UnreachableV6;
  448         np->code = code;
  449         memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  450         set_cksum(nbp);
  451         np->ttl = HOP_LIMIT;
  452         np->vcf[0] = 0x06 << 4;
  453         ipriv->out[UnreachableV6]++;
  454 
  455         if(free)
  456                 ipiput6(f, ifc, nbp);
  457         else {
  458                 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  459                 return;
  460         }
  461 
  462 clean:
  463         runlock(ifc);
  464         freeblist(bp);
  465 }
  466 
  467 extern void
  468 icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp)
  469 {
  470         int osz = BLEN(bp);
  471         int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  472         Block *nbp;
  473         IPICMP *np;
  474         Ip6hdr *p;
  475         Proto *icmp = f->t2p[ICMPv6];
  476         Icmppriv6 *ipriv = icmp->priv;
  477 
  478         p = (Ip6hdr *)bp->rp;
  479 
  480         if(isv6mcast(p->src))
  481                 return;
  482 
  483         nbp = newIPICMP(sz);
  484         np = (IPICMP *) nbp->rp;
  485 
  486         if(ipv6anylocal(ifc, np->src))
  487                 netlog(f, Logicmp, "send icmpttlexceeded6 -> s%I d%I\n",
  488                         p->src, p->dst);
  489         else {
  490                 netlog(f, Logicmp, "icmpttlexceeded6 fail -> s%I d%I\n",
  491                         p->src, p->dst);
  492                 return;
  493         }
  494 
  495         memmove(np->dst, p->src, IPaddrlen);
  496         np->type = TimeExceedV6;
  497         np->code = 0;
  498         memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  499         set_cksum(nbp);
  500         np->ttl = HOP_LIMIT;
  501         np->vcf[0] = 0x06 << 4;
  502         ipriv->out[TimeExceedV6]++;
  503         ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  504 }
  505 
  506 extern void
  507 icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
  508 {
  509         int osz = BLEN(bp);
  510         int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  511         Block *nbp;
  512         IPICMP *np;
  513         Ip6hdr *p;
  514         Proto *icmp = f->t2p[ICMPv6];
  515         Icmppriv6 *ipriv = icmp->priv;
  516 
  517         p = (Ip6hdr *)bp->rp;
  518 
  519         if(isv6mcast(p->src))
  520                 return;
  521 
  522         nbp = newIPICMP(sz);
  523         np = (IPICMP *)nbp->rp;
  524 
  525         if(ipv6anylocal(ifc, np->src))
  526                 netlog(f, Logicmp, "send icmppkttoobig6 -> s%I d%I\n",
  527                         p->src, p->dst);
  528         else {
  529                 netlog(f, Logicmp, "icmppkttoobig6 fail -> s%I d%I\n",
  530                         p->src, p->dst);
  531                 return;
  532         }
  533 
  534         memmove(np->dst, p->src, IPaddrlen);
  535         np->type = PacketTooBigV6;
  536         np->code = 0;
  537         hnputl(np->icmpid, ifc->maxtu - ifc->m->hsize);
  538         memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  539         set_cksum(nbp);
  540         np->ttl = HOP_LIMIT;
  541         np->vcf[0] = 0x06 << 4;
  542         ipriv->out[PacketTooBigV6]++;
  543         ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  544 }
  545 
  546 /*
  547  * RFC 2461, pages 39-40, pages 57-58.
  548  */
  549 static int
  550 valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv)
  551 {
  552         int sz, osz, unsp, n, ttl, iplen;
  553         int pktsz = BLEN(bp);
  554         uchar *packet = bp->rp;
  555         IPICMP *p = (IPICMP *) packet;
  556         Ndpkt *np;
  557 
  558         USED(ifc);
  559         n = blocklen(bp);
  560         if(n < sizeof(IPICMP)) {
  561                 ipriv->stats[HlenErrs6]++;
  562                 netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
  563                 goto err;
  564         }
  565 
  566         iplen = nhgets(p->ploadlen);
  567         if(iplen > n - IP6HDR || (iplen % 1) != 0) {
  568                 ipriv->stats[LenErrs6]++;
  569                 netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
  570                 goto err;
  571         }
  572 
  573         /* Rather than construct explicit pseudoheader, overwrite IPv6 header */
  574         if(p->proto != ICMPv6) {
  575                 /* This code assumes no extension headers!!! */
  576                 netlog(icmp->f, Logicmp, "icmp error: extension header\n");
  577                 goto err;
  578         }
  579         memset(packet, 0, 4);
  580         ttl = p->ttl;
  581         p->ttl = p->proto;
  582         p->proto = 0;
  583         if(ptclcsum(bp, 0, iplen + IP6HDR)) {
  584                 ipriv->stats[CsumErrs6]++;
  585                 netlog(icmp->f, Logicmp, "icmp checksum error\n");
  586                 goto err;
  587         }
  588         p->proto = p->ttl;
  589         p->ttl = ttl;
  590 
  591         /* additional tests for some pkt types */
  592         if (p->type == NbrSolicit   || p->type == NbrAdvert ||
  593             p->type == RouterAdvert || p->type == RouterSolicit ||
  594             p->type == RedirectV6) {
  595                 if(p->ttl != HOP_LIMIT) {
  596                         ipriv->stats[HoplimErrs6]++;
  597                         goto err;
  598                 }
  599                 if(p->code != 0) {
  600                         ipriv->stats[IcmpCodeErrs6]++;
  601                         goto err;
  602                 }
  603 
  604                 switch (p->type) {
  605                 case NbrSolicit:
  606                 case NbrAdvert:
  607                         np = (Ndpkt*) p;
  608                         if(isv6mcast(np->target)) {
  609                                 ipriv->stats[TargetErrs6]++;
  610                                 goto err;
  611                         }
  612                         if(optexsts(np) && np->olen == 0) {
  613                                 ipriv->stats[OptlenErrs6]++;
  614                                 goto err;
  615                         }
  616 
  617                         if (p->type == NbrSolicit &&
  618                             ipcmp(np->src, v6Unspecified) == 0)
  619                                 if(!issmcast(np->dst) || optexsts(np)) {
  620                                         ipriv->stats[AddrmxpErrs6]++;
  621                                         goto err;
  622                                 }
  623 
  624                         if(p->type == NbrAdvert)
  625                                 if(isv6mcast(np->dst) &&
  626                                     (nhgets(np->icmpid) & Sflag)){
  627                                         ipriv->stats[AddrmxpErrs6]++;
  628                                         goto err;
  629                                 }
  630                         break;
  631 
  632                 case RouterAdvert:
  633                         if(pktsz - sizeof(Ip6hdr) < 16) {
  634                                 ipriv->stats[HlenErrs6]++;
  635                                 goto err;
  636                         }
  637                         if(!islinklocal(p->src)) {
  638                                 ipriv->stats[RouterAddrErrs6]++;
  639                                 goto err;
  640                         }
  641                         sz = sizeof(IPICMP) + 8;
  642                         while (sz+1 < pktsz) {
  643                                 osz = packet[sz+1];
  644                                 if(osz <= 0) {
  645                                         ipriv->stats[OptlenErrs6]++;
  646                                         goto err;
  647                                 }
  648                                 sz += 8*osz;
  649                         }
  650                         break;
  651 
  652                 case RouterSolicit:
  653                         if(pktsz - sizeof(Ip6hdr) < 8) {
  654                                 ipriv->stats[HlenErrs6]++;
  655                                 goto err;
  656                         }
  657                         unsp = (ipcmp(p->src, v6Unspecified) == 0);
  658                         sz = sizeof(IPICMP) + 8;
  659                         while (sz+1 < pktsz) {
  660                                 osz = packet[sz+1];
  661                                 if(osz <= 0 ||
  662                                     (unsp && packet[sz] == SRC_LLADDR)) {
  663                                         ipriv->stats[OptlenErrs6]++;
  664                                         goto err;
  665                                 }
  666                                 sz += 8*osz;
  667                         }
  668                         break;
  669 
  670                 case RedirectV6:
  671                         /* to be filled in */
  672                         break;
  673 
  674                 default:
  675                         goto err;
  676                 }
  677         }
  678         return 1;
  679 err:
  680         ipriv->stats[InErrors6]++;
  681         return 0;
  682 }
  683 
  684 static int
  685 targettype(Fs *f, Ipifc *ifc, uchar *target)
  686 {
  687         Iplifc *lifc;
  688         int t;
  689 
  690         rlock(ifc);
  691         if(ipproxyifc(f, ifc, target)) {
  692                 runlock(ifc);
  693                 return Tuniproxy;
  694         }
  695 
  696         for(lifc = ifc->lifc; lifc; lifc = lifc->next)
  697                 if(ipcmp(lifc->local, target) == 0) {
  698                         t = (lifc->tentative)? Tunitent: Tunirany;
  699                         runlock(ifc);
  700                         return t;
  701                 }
  702 
  703         runlock(ifc);
  704         return 0;
  705 }
  706 
  707 static void
  708 icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
  709 {
  710         int refresh = 1;
  711         char *msg, m2[128];
  712         uchar pktflags;
  713         uchar *packet = bp->rp;
  714         uchar lsrc[IPaddrlen];
  715         Block *r;
  716         IPICMP *p = (IPICMP *)packet;
  717         Icmppriv6 *ipriv = icmp->priv;
  718         Iplifc *lifc;
  719         Ndpkt* np;
  720         Proto *pr;
  721 
  722         if(!valid(icmp, ipifc, bp, ipriv) || p->type > Maxtype6)
  723                 goto raise;
  724 
  725         ipriv->in[p->type]++;
  726 
  727         switch(p->type) {
  728         case EchoRequestV6:
  729                 r = mkechoreply6(bp, ipifc);
  730                 if(r == nil)
  731                         goto raise;
  732                 ipriv->out[EchoReply]++;
  733                 ipoput6(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
  734                 break;
  735 
  736         case UnreachableV6:
  737                 if(p->code >= nelem(unreachcode))
  738                         msg = unreachcode[Icmp6_unknown];
  739                 else
  740                         msg = unreachcode[p->code];
  741 
  742                 bp->rp += sizeof(IPICMP);
  743                 if(blocklen(bp) < 8){
  744                         ipriv->stats[LenErrs6]++;
  745                         goto raise;
  746                 }
  747                 p = (IPICMP *)bp->rp;
  748                 pr = Fsrcvpcolx(icmp->f, p->proto);
  749                 if(pr != nil && pr->advise != nil) {
  750                         (*pr->advise)(pr, bp, msg);
  751                         return;
  752                 }
  753 
  754                 bp->rp -= sizeof(IPICMP);
  755                 goticmpkt6(icmp, bp, 0);
  756                 break;
  757 
  758         case TimeExceedV6:
  759                 if(p->code == 0){
  760                         sprint(m2, "ttl exceeded at %I", p->src);
  761 
  762                         bp->rp += sizeof(IPICMP);
  763                         if(blocklen(bp) < 8){
  764                                 ipriv->stats[LenErrs6]++;
  765                                 goto raise;
  766                         }
  767                         p = (IPICMP *)bp->rp;
  768                         pr = Fsrcvpcolx(icmp->f, p->proto);
  769                         if(pr && pr->advise) {
  770                                 (*pr->advise)(pr, bp, m2);
  771                                 return;
  772                         }
  773                         bp->rp -= sizeof(IPICMP);
  774                 }
  775 
  776                 goticmpkt6(icmp, bp, 0);
  777                 break;
  778 
  779         case RouterAdvert:
  780         case RouterSolicit:
  781                 /* using lsrc as a temp, munge hdr for goticmp6 */
  782                 if (0) {
  783                         memmove(lsrc, p->src, IPaddrlen);
  784                         memmove(p->src, p->dst, IPaddrlen);
  785                         memmove(p->dst, lsrc, IPaddrlen);
  786                 }
  787                 goticmpkt6(icmp, bp, p->type);
  788                 break;
  789 
  790         case NbrSolicit:
  791                 np = (Ndpkt*) p;
  792                 pktflags = 0;
  793                 switch (targettype(icmp->f, ipifc, np->target)) {
  794                 case Tunirany:
  795                         pktflags |= Oflag;
  796                         /* fall through */
  797 
  798                 case Tuniproxy:
  799                         if(ipcmp(np->src, v6Unspecified) != 0) {
  800                                 arpenter(icmp->f, V6, np->src, np->lnaddr,
  801                                         8*np->olen-2, 0);
  802                                 pktflags |= Sflag;
  803                         }
  804                         if(ipv6local(ipifc, lsrc))
  805                                 icmpna(icmp->f, lsrc,
  806                                         (ipcmp(np->src, v6Unspecified) == 0?
  807                                                 v6allnodesL: np->src),
  808                                         np->target, ipifc->mac, pktflags);
  809                         else
  810                                 freeblist(bp);
  811                         break;
  812 
  813                 case Tunitent:
  814                         /* not clear what needs to be done. send up
  815                          * an icmp mesg saying don't use this address? */
  816                 default:
  817                         freeblist(bp);
  818                 }
  819                 break;
  820 
  821         case NbrAdvert:
  822                 np = (Ndpkt*) p;
  823 
  824                 /*
  825                  * if the target address matches one of the local interface
  826                  * addresses and the local interface address has tentative bit
  827                  * set, insert into ARP table. this is so the duplicate address
  828                  * detection part of ipconfig can discover duplication through
  829                  * the arp table.
  830                  */
  831                 lifc = iplocalonifc(ipifc, np->target);
  832                 if(lifc && lifc->tentative)
  833                         refresh = 0;
  834                 arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2,
  835                         refresh);
  836                 freeblist(bp);
  837                 break;
  838 
  839         case PacketTooBigV6:
  840         default:
  841                 goticmpkt6(icmp, bp, 0);
  842                 break;
  843         }
  844         return;
  845 raise:
  846         freeblist(bp);
  847 }
  848 
  849 int
  850 icmpstats6(Proto *icmp6, char *buf, int len)
  851 {
  852         Icmppriv6 *priv;
  853         char *p, *e;
  854         int i;
  855 
  856         priv = icmp6->priv;
  857         p = buf;
  858         e = p+len;
  859         for(i = 0; i < Nstats6; i++)
  860                 p = seprint(p, e, "%s: %lud\n", statnames6[i], priv->stats[i]);
  861         for(i = 0; i <= Maxtype6; i++)
  862                 if(icmpnames6[i])
  863                         p = seprint(p, e, "%s: %lud %lud\n", icmpnames6[i],
  864                                 priv->in[i], priv->out[i]);
  865 /*              else
  866                         p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i],
  867                                 priv->out[i]);
  868  */
  869         return p - buf;
  870 }
  871 
  872 
  873 /* import from icmp.c */
  874 extern int      icmpstate(Conv *c, char *state, int n);
  875 extern char*    icmpannounce(Conv *c, char **argv, int argc);
  876 extern char*    icmpconnect(Conv *c, char **argv, int argc);
  877 extern void     icmpclose(Conv *c);
  878 
  879 void
  880 icmp6init(Fs *fs)
  881 {
  882         Proto *icmp6 = smalloc(sizeof(Proto));
  883 
  884         icmp6->priv = smalloc(sizeof(Icmppriv6));
  885         icmp6->name = "icmpv6";
  886         icmp6->connect = icmpconnect;
  887         icmp6->announce = icmpannounce;
  888         icmp6->state = icmpstate;
  889         icmp6->create = icmpcreate6;
  890         icmp6->close = icmpclose;
  891         icmp6->rcv = icmpiput6;
  892         icmp6->stats = icmpstats6;
  893         icmp6->ctl = icmpctl6;
  894         icmp6->advise = icmpadvise6;
  895         icmp6->gc = nil;
  896         icmp6->ipproto = ICMPv6;
  897         icmp6->nc = 16;
  898         icmp6->ptclsize = sizeof(Icmpcb6);
  899 
  900         Fsproto(fs, icmp6);
  901 }

Cache object: 045757a077913d7f2780720a84737445


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.