FreeBSD/Linux Kernel Cross Reference
sys/ip/icmp6.c
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
|