ipv6.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /*
  2. * ipconfig for IPv6
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include <ip.h>
  8. typedef struct Block Block;
  9. typedef struct Fs Fs;
  10. #include "/sys/src/9/ip/ipv6.h"
  11. #include "ipconfig.h"
  12. #include "../icmp.h"
  13. #pragma varargck argpos ralog 1
  14. #define RALOG "v6routeradv"
  15. #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
  16. #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
  17. ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
  18. enum {
  19. ICMP6LEN= 4,
  20. };
  21. typedef struct Hdr Hdr;
  22. struct Hdr /* ICMP v4 & v6 header */
  23. {
  24. uchar type;
  25. uchar code;
  26. uchar cksum[2]; /* Checksum */
  27. uchar data[1];
  28. };
  29. char *icmpmsg6[Maxtype6+1] =
  30. {
  31. [EchoReply] "EchoReply",
  32. [UnreachableV6] "UnreachableV6",
  33. [PacketTooBigV6] "PacketTooBigV6",
  34. [TimeExceedV6] "TimeExceedV6",
  35. [Redirect] "Redirect",
  36. [EchoRequest] "EchoRequest",
  37. [TimeExceed] "TimeExceed",
  38. [InParmProblem] "InParmProblem",
  39. [Timestamp] "Timestamp",
  40. [TimestampReply] "TimestampReply",
  41. [InfoRequest] "InfoRequest",
  42. [InfoReply] "InfoReply",
  43. [AddrMaskRequest] "AddrMaskRequest",
  44. [AddrMaskReply] "AddrMaskReply",
  45. [EchoRequestV6] "EchoRequestV6",
  46. [EchoReplyV6] "EchoReplyV6",
  47. [RouterSolicit] "RouterSolicit",
  48. [RouterAdvert] "RouterAdvert",
  49. [NbrSolicit] "NbrSolicit",
  50. [NbrAdvert] "NbrAdvert",
  51. [RedirectV6] "RedirectV6",
  52. };
  53. static char *icmp6opts[] =
  54. {
  55. [0] "unknown opt",
  56. [SRC_LLADDR] "sll_addr",
  57. [TARGET_LLADDR] "tll_addr",
  58. [PREFIX_INFO] "pref_opt",
  59. [REDIR_HEADER] "redirect",
  60. [MTU_OPTION] "mtu_opt",
  61. };
  62. uchar v6allroutersL[IPaddrlen] = {
  63. 0xff, 0x02, 0, 0,
  64. 0, 0, 0, 0,
  65. 0, 0, 0, 0,
  66. 0, 0, 0, 0x02
  67. };
  68. uchar v6allnodesL[IPaddrlen] = {
  69. 0xff, 0x02, 0, 0,
  70. 0, 0, 0, 0,
  71. 0, 0, 0, 0,
  72. 0, 0, 0, 0x01
  73. };
  74. uchar v6Unspecified[IPaddrlen] = {
  75. 0, 0, 0, 0,
  76. 0, 0, 0, 0,
  77. 0, 0, 0, 0,
  78. 0, 0, 0, 0
  79. };
  80. uchar v6glunicast[IPaddrlen] = {
  81. 0x08, 0, 0, 0,
  82. 0, 0, 0, 0,
  83. 0, 0, 0, 0,
  84. 0, 0, 0, 0
  85. };
  86. uchar v6linklocal[IPaddrlen] = {
  87. 0xfe, 0x80, 0, 0,
  88. 0, 0, 0, 0,
  89. 0, 0, 0, 0,
  90. 0, 0, 0, 0
  91. };
  92. uchar v6solpfx[IPaddrlen] = {
  93. 0xff, 0x02, 0, 0,
  94. 0, 0, 0, 0,
  95. 0, 0, 0, 1,
  96. /* last 3 bytes filled with low-order bytes of addr being solicited */
  97. 0xff, 0, 0, 0,
  98. };
  99. uchar v6defmask[IPaddrlen] = {
  100. 0xff, 0xff, 0xff, 0xff,
  101. 0xff, 0xff, 0xff, 0xff,
  102. 0, 0, 0, 0,
  103. 0, 0, 0, 0
  104. };
  105. enum
  106. {
  107. Vadd,
  108. Vremove,
  109. Vunbind,
  110. Vaddpref6,
  111. Vra6,
  112. };
  113. static void
  114. ralog(char *fmt, ...)
  115. {
  116. char msg[512];
  117. va_list arg;
  118. va_start(arg, fmt);
  119. vseprint(msg, msg+sizeof msg, fmt, arg);
  120. va_end(arg);
  121. syslog(debug, RALOG, msg);
  122. }
  123. extern void
  124. ea2lla(uchar *lla, uchar *ea)
  125. {
  126. assert(IPaddrlen == 16);
  127. memset(lla, 0, IPaddrlen);
  128. lla[0] = 0xFE;
  129. lla[1] = 0x80;
  130. lla[8] = ea[0] | 0x2;
  131. lla[9] = ea[1];
  132. lla[10] = ea[2];
  133. lla[11] = 0xFF;
  134. lla[12] = 0xFE;
  135. lla[13] = ea[3];
  136. lla[14] = ea[4];
  137. lla[15] = ea[5];
  138. }
  139. extern void
  140. ipv62smcast(uchar *smcast, uchar *a)
  141. {
  142. assert(IPaddrlen == 16);
  143. memset(smcast, 0, IPaddrlen);
  144. smcast[0] = 0xFF;
  145. smcast[1] = 0x02;
  146. smcast[11] = 0x1;
  147. smcast[12] = 0xFF;
  148. smcast[13] = a[13];
  149. smcast[14] = a[14];
  150. smcast[15] = a[15];
  151. }
  152. void
  153. v6paraminit(Conf *cf)
  154. {
  155. cf->sendra = cf->recvra = 0;
  156. cf->mflag = 0;
  157. cf->oflag = 0;
  158. cf->maxraint = MAX_INIT_RTR_ADVERT_INTVL;
  159. cf->minraint = MAX_INIT_RTR_ADVERT_INTVL / 4;
  160. cf->linkmtu = 1500;
  161. cf->reachtime = REACHABLE_TIME;
  162. cf->rxmitra = RETRANS_TIMER;
  163. cf->ttl = MAXTTL;
  164. cf->routerlt = 0;
  165. cf->prefixlen = 64;
  166. cf->onlink = 0;
  167. cf->autoflag = 0;
  168. cf->validlt = cf->preflt = ~0L;
  169. }
  170. static char*
  171. opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
  172. {
  173. int otype, osz, pktsz;
  174. uchar *a;
  175. char *p = sps, *e = spe;
  176. a = ps;
  177. for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
  178. otype = a[0];
  179. osz = a[1] * 8;
  180. switch (otype) {
  181. default:
  182. return seprint(p, e, " option=%s ", icmp6opts[otype]);
  183. case SRC_LLADDR:
  184. case TARGET_LLADDR:
  185. if (pktsz < osz || osz != 8)
  186. return seprint(p, e, " option=%s bad size=%d",
  187. icmp6opts[otype], osz);
  188. p = seprint(p, e, " option=%s maddr=%E",
  189. icmp6opts[otype], a+2);
  190. break;
  191. case PREFIX_INFO:
  192. if (pktsz < osz || osz != 32)
  193. return seprint(p, e, " option=%s: bad size=%d",
  194. icmp6opts[otype], osz);
  195. p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
  196. " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
  197. " validlt=%ud preflt=%ud unused2=%1.1d",
  198. icmp6opts[otype], a+16, (int)(*(a+2)),
  199. (*(a+3) & (1 << 7)) != 0,
  200. (*(a+3) & (1 << 6)) != 0,
  201. (*(a+3) & 63) != 0,
  202. NetL(a+4), NetL(a+8), NetL(a+12)!=0);
  203. break;
  204. }
  205. a += osz;
  206. }
  207. return p;
  208. }
  209. static void
  210. pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
  211. {
  212. int pktlen;
  213. char *tn, *p, *e;
  214. uchar *a;
  215. Hdr *h;
  216. h = (Hdr*)ps;
  217. a = ps + 4;
  218. p = sps;
  219. e = spe;
  220. pktlen = pe - ps;
  221. if(pktlen < ICMP6LEN) {
  222. seprint(sps, spe, "short pkt");
  223. return;
  224. }
  225. tn = icmpmsg6[h->type];
  226. if(tn == nil)
  227. p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
  228. h->code, (ushort)NetS(h->cksum));
  229. else
  230. p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
  231. h->code, (ushort)NetS(h->cksum));
  232. switch(h->type){
  233. case RouterSolicit:
  234. ps += 8;
  235. p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
  236. opt_seprint(ps, pe, p, e);
  237. break;
  238. case RouterAdvert:
  239. ps += 16;
  240. p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
  241. " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
  242. a[0],
  243. (*(a+1) & (1 << 7)) != 0,
  244. (*(a+1) & (1 << 6)) != 0,
  245. (*(a+1) & 63) != 0,
  246. NetS(a+2), NetL(a+4), NetL(a+8));
  247. opt_seprint(ps, pe, p, e);
  248. break;
  249. default:
  250. seprint(p, e, " unexpected icmp6 pkt type");
  251. break;
  252. }
  253. }
  254. static void
  255. catch(void *a, char *msg)
  256. {
  257. USED(a);
  258. if(strstr(msg, "alarm"))
  259. noted(NCONT);
  260. else
  261. noted(NDFLT);
  262. }
  263. /*
  264. * based on libthread's threadsetname, but drags in less library code.
  265. * actually just sets the arguments displayed.
  266. */
  267. void
  268. procsetname(char *fmt, ...)
  269. {
  270. int fd;
  271. char *cmdname;
  272. char buf[128];
  273. va_list arg;
  274. va_start(arg, fmt);
  275. cmdname = vsmprint(fmt, arg);
  276. va_end(arg);
  277. if (cmdname == nil)
  278. return;
  279. snprint(buf, sizeof buf, "#p/%d/args", getpid());
  280. if((fd = open(buf, OWRITE)) >= 0){
  281. write(fd, cmdname, strlen(cmdname)+1);
  282. close(fd);
  283. }
  284. free(cmdname);
  285. }
  286. int
  287. dialicmp(uchar *dst, int dport, int *ctlfd)
  288. {
  289. int fd, cfd, n, m;
  290. char cmsg[100], name[128], connind[40];
  291. char hdrs[] = "headers";
  292. snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
  293. cfd = open(name, ORDWR);
  294. if(cfd < 0)
  295. sysfatal("dialicmp: can't open %s: %r", name);
  296. n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
  297. m = write(cfd, cmsg, n);
  298. if (m < n)
  299. sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
  300. seek(cfd, 0, 0);
  301. n = read(cfd, connind, sizeof connind);
  302. if (n < 0)
  303. connind[0] = 0;
  304. else if (n < sizeof connind)
  305. connind[n] = 0;
  306. else
  307. connind[sizeof connind - 1] = 0;
  308. snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
  309. fd = open(name, ORDWR);
  310. if(fd < 0)
  311. sysfatal("dialicmp: can't open %s: %r", name);
  312. n = sizeof hdrs - 1;
  313. if(write(cfd, hdrs, n) < n)
  314. sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
  315. *ctlfd = cfd;
  316. return fd;
  317. }
  318. /* add ipv6 addr to an interface */
  319. int
  320. ip6cfg(int autoconf)
  321. {
  322. int dupfound = 0, n;
  323. char *p;
  324. char buf[256];
  325. uchar ethaddr[6];
  326. Biobuf *bp;
  327. if (autoconf) { /* create link-local addr */
  328. if (myetheraddr(ethaddr, conf.dev) < 0)
  329. sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
  330. ea2lla(conf.laddr, ethaddr);
  331. }
  332. if (dupl_disc)
  333. n = sprint(buf, "try");
  334. else
  335. n = sprint(buf, "add");
  336. n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
  337. if(!validip(conf.mask))
  338. ipmove(conf.mask, v6defmask);
  339. n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
  340. if(validip(conf.raddr)){
  341. n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
  342. if(conf.mtu != 0)
  343. n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
  344. }
  345. if(write(conf.cfd, buf, n) < 0){
  346. fprint(2, "%s: write(%s): %r\n", argv0, buf);
  347. return -1;
  348. }
  349. if (!dupl_disc)
  350. return 0;
  351. sleep(3000);
  352. /* read arp table, look for addr duplication */
  353. snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
  354. bp = Bopen(buf, OREAD);
  355. if (bp == 0) {
  356. fprint(2, "%s: couldn't open %s/arp: %r\n", argv0, conf.mpoint);
  357. return -1;
  358. }
  359. snprint(buf, sizeof buf, "%I", conf.laddr);
  360. while(p = Brdline(bp, '\n')){
  361. p[Blinelen(bp)-1] = 0;
  362. if(cistrstr(p, buf) != 0) {
  363. fprint(2, "%s: found dup entry in arp cache\n", argv0);
  364. dupfound = 1;
  365. break;
  366. }
  367. }
  368. Bterm(bp);
  369. if (dupfound)
  370. doremove();
  371. else {
  372. n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
  373. if(validip(conf.raddr)){
  374. n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
  375. if(conf.mtu != 0)
  376. n += snprint(buf+n, sizeof buf-n, " %d",
  377. conf.mtu);
  378. }
  379. write(conf.cfd, buf, n);
  380. }
  381. return 0;
  382. }
  383. static int
  384. recvra6on(char *net, int conn)
  385. {
  386. Ipifc* ifc;
  387. ifc = readipifc(net, nil, conn);
  388. if (ifc == nil)
  389. return 0;
  390. else if (ifc->sendra6 > 0)
  391. return IsRouter;
  392. else if (ifc->recvra6 > 0)
  393. return IsHostRecv;
  394. else
  395. return IsHostNoRecv;
  396. }
  397. static void
  398. sendrs(int fd)
  399. {
  400. Routersol *rs;
  401. uchar buff[sizeof *rs];
  402. memset(buff, 0, sizeof buff);
  403. rs = (Routersol *)buff;
  404. memmove(rs->dst, v6allroutersL, IPaddrlen);
  405. memmove(rs->src, v6Unspecified, IPaddrlen);
  406. rs->type = ICMP6_RS;
  407. if(write(fd, rs, sizeof buff) < sizeof buff)
  408. ralog("sendrs: write failed, pkt size %d", sizeof buff);
  409. }
  410. /*
  411. * a router receiving a router adv from another
  412. * router calls this; it is basically supposed to
  413. * log the information in the ra and raise a flag
  414. * if any parameter value is different from its configured values.
  415. *
  416. * doing nothing for now since I don't know where to log this yet.
  417. */
  418. static void
  419. recvrarouter(uchar buf[], int pktlen)
  420. {
  421. USED(buf, pktlen);
  422. ralog("i am a router and got a router advert");
  423. }
  424. /* host receiving a router advertisement calls this */
  425. static void
  426. ewrite(int fd, char *str)
  427. {
  428. int n;
  429. n = strlen(str);
  430. if (write(fd, str, n) != n)
  431. ralog("write(%s) failed: %r", str);
  432. }
  433. static void
  434. issuebasera6(Conf *cf)
  435. {
  436. char *cfg;
  437. cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
  438. "ttl %d routerlt %d",
  439. cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
  440. cf->ttl, cf->routerlt);
  441. ewrite(cf->cfd, cfg);
  442. free(cfg);
  443. }
  444. static void
  445. issuerara6(Conf *cf)
  446. {
  447. char *cfg;
  448. cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
  449. "linkmtu %d",
  450. cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
  451. cf->linkmtu);
  452. ewrite(cf->cfd, cfg);
  453. free(cfg);
  454. }
  455. static void
  456. issueadd6(Conf *cf)
  457. {
  458. char *cfg;
  459. cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
  460. cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
  461. ewrite(cf->cfd, cfg);
  462. free(cfg);
  463. }
  464. static void
  465. recvrahost(uchar buf[], int pktlen)
  466. {
  467. int arpfd, m, n;
  468. char abuf[100];
  469. uchar optype;
  470. Lladdropt *llao;
  471. Mtuopt *mtuo;
  472. Prefixopt *prfo;
  473. Routeradv *ra;
  474. ra = (Routeradv*)buf;
  475. // memmove(conf.v6gaddr, ra->src, IPaddrlen);
  476. conf.ttl = ra->cttl;
  477. conf.mflag = (MFMASK & ra->mor);
  478. conf.oflag = (OCMASK & ra->mor);
  479. conf.routerlt = nhgets(ra->routerlt);
  480. conf.reachtime = nhgetl(ra->rchbltime);
  481. conf.rxmitra = nhgetl(ra->rxmtimer);
  482. // issueadd6(&conf); // for conf.v6gaddr?
  483. if (fprint(conf.cfd, "ra6 recvra 1") < 0)
  484. ralog("write(ra6 recvra 1) failed: %r");
  485. issuebasera6(&conf);
  486. m = sizeof *ra;
  487. while (pktlen - m > 0) {
  488. optype = buf[m];
  489. switch (optype) {
  490. case SRC_LLADDR:
  491. llao = (Lladdropt *)&buf[m];
  492. m += 8 * buf[m+1];
  493. if (llao->len != 1) {
  494. ralog(
  495. "recvrahost: illegal len(%d) for source link layer address option",
  496. llao->len);
  497. return;
  498. }
  499. if (memcmp(ra->src, v6linklocal, 2) != 0) {
  500. ralog(
  501. "recvrahost: non-linklocal src addr for router adv %I",
  502. ra->src);
  503. return;
  504. }
  505. snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
  506. arpfd = open(abuf, OWRITE);
  507. if (arpfd < 0) {
  508. ralog(
  509. "recvrahost: couldn't open %s/arp to write: %r",
  510. conf.mpoint);
  511. return;
  512. }
  513. n = snprint(abuf, sizeof abuf, "add ether %I %E",
  514. ra->src, llao->lladdr);
  515. if (write(arpfd, abuf, n) < n)
  516. ralog("recvrahost: couldn't write to %s/arp",
  517. conf.mpoint);
  518. close(arpfd);
  519. break;
  520. case TARGET_LLADDR:
  521. case REDIR_HEADER:
  522. m += 8 * buf[m+1];
  523. ralog("ignoring unexpected optype %s in Routeradv",
  524. icmp6opts[optype]);
  525. break;
  526. case MTU_OPTION:
  527. mtuo = (Mtuopt*)&buf[m];
  528. m += 8 * mtuo->len;
  529. conf.linkmtu = nhgetl(mtuo->mtu);
  530. break;
  531. case PREFIX_INFO:
  532. prfo = (Prefixopt*)&buf[m];
  533. m += 8 * prfo->len;
  534. if (prfo->len != 4) {
  535. ralog("illegal len(%d) for prefix option",
  536. prfo->len);
  537. return;
  538. }
  539. memmove(conf.v6pref, prfo->pref, IPaddrlen);
  540. conf.prefixlen = prfo->plen;
  541. conf.onlink = ((prfo->lar & OLMASK) != 0);
  542. conf.autoflag = ((prfo->lar & AFMASK) != 0);
  543. conf.validlt = nhgetl(prfo->validlt);
  544. conf.preflt = nhgetl(prfo->preflt);
  545. issueadd6(&conf);
  546. break;
  547. default:
  548. m += 8 * buf[m+1];
  549. ralog("ignoring optype %s in Routeradv", icmp6opts[0]);
  550. break;
  551. }
  552. }
  553. }
  554. /*
  555. * daemon to receive router adverisements
  556. */
  557. void
  558. recvra6(void)
  559. {
  560. int fd, cfd, n, sendrscnt, sleepfor;
  561. uchar buf[4096];
  562. fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
  563. if (fd < 0)
  564. sysfatal("can't open icmp_ra connection: %r");
  565. notify(catch);
  566. sendrscnt = MAX_RTR_SOLICITS;
  567. switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
  568. case -1:
  569. sysfatal("can't fork: %r");
  570. default:
  571. return;
  572. case 0:
  573. procsetname("recvra6 on %s", conf.dev);
  574. ralog("recvra6 on %s", conf.dev);
  575. sleepfor = nrand(10);
  576. for (;;) {
  577. alarm(sleepfor);
  578. n = read(fd, buf, sizeof buf);
  579. alarm(0);
  580. if (n <= 0) {
  581. if (sendrscnt > 0) {
  582. sendrscnt--;
  583. if (recvra6on(conf.mpoint, myifc) ==
  584. IsHostRecv)
  585. sendrs(fd);
  586. sleepfor = RTR_SOLICIT_INTVL+nrand(100);
  587. }
  588. if (sendrscnt == 0) {
  589. sendrscnt--;
  590. sleepfor = 0;
  591. ralog(
  592. "recvra6: no router advs after %d sols on %s",
  593. MAX_RTR_SOLICITS, conf.dev);
  594. }
  595. continue;
  596. }
  597. sleepfor = 0;
  598. switch (recvra6on(conf.mpoint, myifc)) {
  599. case IsRouter:
  600. recvrarouter(buf, n);
  601. break;
  602. case IsHostRecv:
  603. recvrahost(buf, n);
  604. break;
  605. case IsHostNoRecv:
  606. ralog("recvra6: recvra off, quitting");
  607. close(fd);
  608. exits(0);
  609. default:
  610. ralog(
  611. "recvra6: unable to read router status on %s",
  612. conf.dev);
  613. break;
  614. }
  615. }
  616. }
  617. }
  618. /*
  619. * return -1 -- error, reading/writing some file,
  620. * 0 -- no arptable updates
  621. * 1 -- successful arptable update
  622. */
  623. int
  624. recvrs(uchar *buf, int pktlen, uchar *sol)
  625. {
  626. int n, optsz, arpfd;
  627. char abuf[256];
  628. Routersol *rs;
  629. Lladdropt *llao;
  630. rs = (Routersol *)buf;
  631. n = sizeof *rs;
  632. optsz = pktlen - n;
  633. pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
  634. if (optsz != sizeof *llao)
  635. return 0;
  636. if (buf[n] != SRC_LLADDR || 8*buf[n+1] != sizeof *llao) {
  637. ralog("rs opt err %s", abuf);
  638. return -1;
  639. }
  640. ralog("rs recv %s", abuf);
  641. if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
  642. return 0;
  643. snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
  644. arpfd = open(abuf, OWRITE);
  645. if (arpfd < 0) {
  646. ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
  647. return -1;
  648. }
  649. llao = (Lladdropt *)buf[n];
  650. n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
  651. if (write(arpfd, abuf, n) < n) {
  652. ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
  653. close(arpfd);
  654. return -1;
  655. }
  656. memmove(sol, rs->src, IPaddrlen);
  657. close(arpfd);
  658. return 1;
  659. }
  660. void
  661. sendra(int fd, uchar *dst, int rlt)
  662. {
  663. int pktsz, preflen;
  664. char abuf[1024], tmp[40];
  665. uchar buf[1024], macaddr[6], src[IPaddrlen];
  666. Ipifc *ifc = nil;
  667. Iplifc *lifc, *nlifc;
  668. Lladdropt *llao;
  669. Prefixopt *prfo;
  670. Routeradv *ra;
  671. memset(buf, 0, sizeof buf);
  672. ra = (Routeradv *)buf;
  673. myetheraddr(macaddr, conf.dev);
  674. ea2lla(src, macaddr);
  675. memmove(ra->src, src, IPaddrlen);
  676. memmove(ra->dst, dst, IPaddrlen);
  677. ra->type = ICMP6_RA;
  678. ra->cttl = conf.ttl;
  679. if (conf.mflag > 0)
  680. ra->mor |= MFMASK;
  681. if (conf.oflag > 0)
  682. ra->mor |= OCMASK;
  683. if (rlt > 0)
  684. hnputs(ra->routerlt, conf.routerlt);
  685. else
  686. hnputs(ra->routerlt, 0);
  687. hnputl(ra->rchbltime, conf.reachtime);
  688. hnputl(ra->rxmtimer, conf.rxmitra);
  689. pktsz = sizeof *ra;
  690. /* include all global unicast prefixes on interface in prefix options */
  691. ifc = readipifc(conf.mpoint, ifc, myifc);
  692. for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
  693. nlifc = lifc->next;
  694. prfo = (Prefixopt *)(buf + pktsz);
  695. if (isv6global(lifc->ip)) {
  696. memmove(prfo->pref, lifc->net, IPaddrlen);
  697. /* hack to find prefix length */
  698. snprint(tmp, sizeof tmp, "%M", lifc->mask);
  699. preflen = atoi(&tmp[1]);
  700. prfo->plen = preflen & 0xff;
  701. if (prfo->plen == 0)
  702. continue;
  703. prfo->type = PREFIX_INFO;
  704. prfo->len = 4;
  705. prfo->lar = AFMASK;
  706. hnputl(prfo->validlt, lifc->validlt);
  707. hnputl(prfo->preflt, lifc->preflt);
  708. pktsz += sizeof *prfo;
  709. }
  710. }
  711. /*
  712. * include link layer address (mac address for now) in
  713. * link layer address option
  714. */
  715. llao = (Lladdropt *)(buf + pktsz);
  716. llao->type = SRC_LLADDR;
  717. llao->len = 1;
  718. memmove(llao->lladdr, macaddr, sizeof macaddr);
  719. pktsz += sizeof *llao;
  720. pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
  721. if(write(fd, buf, pktsz) < pktsz)
  722. ralog("ra wr fail %s", abuf);
  723. else
  724. ralog("ra wr succ %s", abuf);
  725. }
  726. /*
  727. * daemon to send router advertisements
  728. */
  729. void
  730. sendra6(void)
  731. {
  732. int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
  733. long lastra, ctime;
  734. uchar buf[4096], dst[IPaddrlen];
  735. Ipifc *ifc = nil;
  736. fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
  737. if (fd < 0)
  738. sysfatal("can't open icmp_rs connection: %r");
  739. notify(catch);
  740. sendracnt = MAX_INIT_RTR_ADVERTS;
  741. nquitmsgs = MAX_FINAL_RTR_ADVERTS;
  742. switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
  743. case -1:
  744. sysfatal("can't fork: %r");
  745. default:
  746. return;
  747. case 0:
  748. procsetname("sendra6 on %s", conf.dev);
  749. ralog("sendra6 on %s", conf.dev);
  750. sleepfor = nrand(10);
  751. for (;;) {
  752. lastra = time(0);
  753. alarm(sleepfor);
  754. n = read(fd, buf, sizeof buf);
  755. alarm(0);
  756. ifc = readipifc(conf.mpoint, ifc, myifc);
  757. if (ifc == nil) {
  758. ralog("sendra6: unable to read router pars on %s",
  759. conf.mpoint);
  760. continue;
  761. }
  762. if (ifc->sendra6 <= 0)
  763. if (nquitmsgs > 0) {
  764. sendra(fd, v6allnodesL, 0);
  765. nquitmsgs--;
  766. sleepfor = MIN_DELAY_BETWEEN_RAS +
  767. nrand(10);
  768. continue;
  769. } else {
  770. ralog("sendra6: quitting");
  771. exits(0);
  772. }
  773. nquitmsgs = MAX_FINAL_RTR_ADVERTS;
  774. if (n <= 0) { /* no router solicitations */
  775. if (sendracnt > 0)
  776. sendracnt--;
  777. sleepfor = ifc->rp.minraint +
  778. nrand(ifc->rp.maxraint + 1 -
  779. ifc->rp.minraint);
  780. } else { /* respond to router solicit'n */
  781. dstknown = recvrs(buf, n, dst);
  782. ctime = time(0);
  783. if (ctime - lastra < MIN_DELAY_BETWEEN_RAS) {
  784. /* too close, skip */
  785. sleepfor = lastra +
  786. MIN_DELAY_BETWEEN_RAS +
  787. nrand(10) - ctime;
  788. continue;
  789. }
  790. sleepfor = ifc->rp.minraint +
  791. nrand(ifc->rp.maxraint + 1 -
  792. ifc->rp.minraint);
  793. sleep(nrand(10));
  794. }
  795. if (dstknown > 0)
  796. sendra(fd, dst, 1);
  797. else
  798. sendra(fd, v6allnodesL, 1);
  799. }
  800. }
  801. }
  802. void
  803. startra6(void)
  804. {
  805. static char routeon[] = "iprouting 1";
  806. if (conf.recvra > 0)
  807. recvra6();
  808. if (conf.sendra > 0) {
  809. if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
  810. fprint(2, "%s: write (iprouting 1) failed\n", argv0);
  811. return;
  812. }
  813. sendra6();
  814. if (conf.recvra <= 0)
  815. recvra6();
  816. }
  817. }
  818. void
  819. doipv6(int what)
  820. {
  821. nip = nipifcs(conf.mpoint);
  822. if(!noconfig){
  823. lookforip(conf.mpoint);
  824. controldevice();
  825. binddevice();
  826. }
  827. switch (what) {
  828. default:
  829. fprint(2, "%s: unknown IPv6 verb\n", argv0);
  830. exits("usage");
  831. case Vaddpref6:
  832. issueadd6(&conf);
  833. break;
  834. case Vra6:
  835. issuebasera6(&conf);
  836. issuerara6(&conf);
  837. startra6();
  838. break;
  839. }
  840. }