icmp6.c 19 KB

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