/* * ipconfig for IPv6 * RS means Router Solicitation * RA means Router Advertisement */ #include <u.h>#include <libc.h>#include <bio.h>#include <ip.h>#include "ipconfig.h"#include "../icmp.h" #pragma varargck argpos ralog 1 #define RALOG "v6routeradv" #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])#define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \ ((uchar*)x)[2]<< 8 | ((uchar*)x)[3]) enum { ICMP6LEN= 4,}; typedef struct Hdr Hdr;struct Hdr /* ICMP v4 & v6 header */{ uchar type; uchar code; uchar cksum[2]; /* Checksum */ uchar data[];}; char *icmpmsg6[Maxtype6+1] ={[EchoReply] "EchoReply",[UnreachableV6] "UnreachableV6",[PacketTooBigV6] "PacketTooBigV6",[TimeExceedV6] "TimeExceedV6",[Redirect] "Redirect",[EchoRequest] "EchoRequest",[TimeExceed] "TimeExceed",[InParmProblem] "InParmProblem",[Timestamp] "Timestamp",[TimestampReply] "TimestampReply",[InfoRequest] "InfoRequest",[InfoReply] "InfoReply",[AddrMaskRequest] "AddrMaskRequest",[AddrMaskReply] "AddrMaskReply",[EchoRequestV6] "EchoRequestV6",[EchoReplyV6] "EchoReplyV6",[RouterSolicit] "RouterSolicit",[RouterAdvert] "RouterAdvert",[NbrSolicit] "NbrSolicit",[NbrAdvert] "NbrAdvert",[RedirectV6] "RedirectV6",}; static char *icmp6opts[] ={[0] "unknown option",[V6nd_srclladdr] "srcll_addr",[V6nd_targlladdr] "targll_addr",[V6nd_pfxinfo] "prefix",[V6nd_redirhdr] "redirect",[V6nd_mtu] "mtu",[V6nd_home] "home",[V6nd_srcaddrs] "src_addrs",[V6nd_ip] "ip",[V6nd_rdns] "rdns",[V6nd_9fs] "9fs",[V6nd_9auth] "9auth",}; uchar v6allroutersL[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}; uchar v6allnodesL[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}; uchar v6Unspecified[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uchar v6loopback[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; uchar v6glunicast[IPaddrlen] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uchar v6linklocal[IPaddrlen] = { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uchar v6solpfx[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* last 3 bytes filled with low-order bytes of addr being solicited */ 0xff, 0, 0, 0,}; uchar v6defmask[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}; enum{ Vadd, Vremove, Vunbind, Vaddpref6, Vra6,}; static voidralog(char *fmt, ...){ char msg[512]; va_list arg; va_start(arg, fmt); vseprint(msg, msg+sizeof msg, fmt, arg); va_end(arg); syslog(debug, RALOG, msg);} extern voidea2lla(uchar *lla, uchar *ea){ assert(IPaddrlen == 16); memset(lla, 0, IPaddrlen); lla[0] = 0xFE; lla[1] = 0x80; lla[8] = ea[0] | 0x2; lla[9] = ea[1]; lla[10] = ea[2]; lla[11] = 0xFF; lla[12] = 0xFE; lla[13] = ea[3]; lla[14] = ea[4]; lla[15] = ea[5];} extern voidipv62smcast(uchar *smcast, uchar *a){ assert(IPaddrlen == 16); memset(smcast, 0, IPaddrlen); smcast[0] = 0xFF; smcast[1] = 0x02; smcast[11] = 0x1; smcast[12] = 0xFF; smcast[13] = a[13]; smcast[14] = a[14]; smcast[15] = a[15];} voidv6paraminit(Conf *cf){ cf->sendra = cf->recvra = 0; cf->mflag = 0; cf->oflag = 0; cf->maxraint = Maxv6initraintvl; cf->minraint = Maxv6initraintvl / 4; cf->linkmtu = 1500; cf->reachtime = V6reachabletime; cf->rxmitra = V6retranstimer; cf->ttl = MAXTTL; cf->routerlt = 0; cf->prefixlen = 64; cf->onlink = 0; cf->autoflag = 0; cf->validlt = cf->preflt = ~0L;} static char *optname(unsigned opt){ static char buf[32]; if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) { snprint(buf, sizeof buf, "unknown option %d", opt); return buf; } else return icmp6opts[opt];} static char*opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe){ int otype, osz, pktsz; uchar *a; char *p = sps, *e = spe; a = ps; for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) { otype = a[0]; osz = a[1] * 8; switch (otype) { default: return seprint(p, e, " option=%s ", optname(otype)); case V6nd_srclladdr: case V6nd_targlladdr: if (pktsz < osz || osz != 8) return seprint(p, e, " option=%s bad size=%d", optname(otype), osz); p = seprint(p, e, " option=%s maddr=%E", optname(otype), a+2); break; case V6nd_pfxinfo: if (pktsz < osz || osz != 32) return seprint(p, e, " option=%s: bad size=%d", optname(otype), osz); p = seprint(p, e, " option=%s pref=%I preflen=%3.3d" " lflag=%1.1d aflag=%1.1d unused1=%1.1d" " validlt=%ud preflt=%ud unused2=%1.1d", optname(otype), a+16, (int)(*(a+2)), (*(a+3) & (1 << 7)) != 0, (*(a+3) & (1 << 6)) != 0, (*(a+3) & 63) != 0, NetL(a+4), NetL(a+8), NetL(a+12)!=0); break; } a += osz; } return p;} static voidpkt2str(uchar *ps, uchar *pe, char *sps, char *spe){ int pktlen; char *tn, *p, *e; uchar *a; Hdr *h; h = (Hdr*)ps; a = ps + 4; p = sps; e = spe; pktlen = pe - ps; if(pktlen < ICMP6LEN) { seprint(sps, spe, "short pkt"); return; } tn = icmpmsg6[h->type]; if(tn == nil) p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type, h->code, (ushort)NetS(h->cksum)); else p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn, h->code, (ushort)NetS(h->cksum)); switch(h->type){ case RouterSolicit: ps += 8; p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0); opt_seprint(ps, pe, p, e); break; case RouterAdvert: ps += 16; p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d" " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d", a[0], (*(a+1) & (1 << 7)) != 0, (*(a+1) & (1 << 6)) != 0, (*(a+1) & 63) != 0, NetS(a+2), NetL(a+4), NetL(a+8)); opt_seprint(ps, pe, p, e); break; default: seprint(p, e, " unexpected icmp6 pkt type"); break; }} static voidcatch(void *a, char *msg){ USED(a); if(strstr(msg, "alarm")) noted(NCONT); else noted(NDFLT);} /* * based on libthread's threadsetname, but drags in less library code. * actually just sets the arguments displayed. */voidprocsetname(char *fmt, ...){ int fd; char *cmdname; char buf[128]; va_list arg; va_start(arg, fmt); cmdname = vsmprint(fmt, arg); va_end(arg); if (cmdname == nil) return; snprint(buf, sizeof buf, "#p/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, cmdname, strlen(cmdname)+1); close(fd); } free(cmdname);} intdialicmp(uchar *dst, int dport, int *ctlfd){ int fd, cfd, n, m; char cmsg[100], name[128], connind[40]; char hdrs[] = "headers"; snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint); cfd = open(name, ORDWR); if(cfd < 0) sysfatal("dialicmp: can't open %s: %r", name); n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport); m = write(cfd, cmsg, n); if (m < n) sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name); seek(cfd, 0, 0); n = read(cfd, connind, sizeof connind); if (n < 0) connind[0] = 0; else if (n < sizeof connind) connind[n] = 0; else connind[sizeof connind - 1] = 0; snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind); fd = open(name, ORDWR); if(fd < 0) sysfatal("dialicmp: can't open %s: %r", name); n = sizeof hdrs - 1; if(write(cfd, hdrs, n) < n) sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name); *ctlfd = cfd; return fd;} /* add ipv6 addr to an interface */intip6cfg(int autoconf){ int dupfound = 0, n; char *p; char buf[256]; uchar ethaddr[6]; Biobuf *bp; if (autoconf) { /* create link-local addr */ if (myetheraddr(ethaddr, conf.dev) < 0) sysfatal("myetheraddr w/ %s failed: %r", conf.dev); ea2lla(conf.laddr, ethaddr); } if (dupl_disc) n = sprint(buf, "try"); else n = sprint(buf, "add"); n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr); if(!validip(conf.mask)) ipmove(conf.mask, v6defmask); n += snprint(buf+n, sizeof buf-n, " %M", conf.mask); if(validip(conf.raddr)){ n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr); if(conf.mtu != 0) n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu); } if(write(conf.cfd, buf, n) < 0){ warning("write(%s): %r", buf); return -1; } if (!dupl_disc) return 0; sleep(3000); /* read arp table, look for addr duplication */ snprint(buf, sizeof buf, "%s/arp", conf.mpoint); bp = Bopen(buf, OREAD); if (bp == 0) { warning("couldn't open %s: %r", buf); return -1; } snprint(buf, sizeof buf, "%I", conf.laddr); while(p = Brdline(bp, '\n')){ p[Blinelen(bp)-1] = 0; if(cistrstr(p, buf) != 0) { warning("found dup entry in arp cache"); dupfound = 1; break; } } Bterm(bp); if (dupfound) doremove(); else { n = sprint(buf, "add %I %M", conf.laddr, conf.mask); if(validip(conf.raddr)){ n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr); if(conf.mtu != 0) n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu); } write(conf.cfd, buf, n); } return 0;} static intrecvra6on(char *net, int conn){ Ipifc* ifc; ifc = readipifc(net, nil, conn); if (ifc == nil) return 0; else if (ifc->sendra6 > 0) return IsRouter; else if (ifc->recvra6 > 0) return IsHostRecv; else return IsHostNoRecv;} /* send icmpv6 router solicitation to multicast address for all routers */static voidsendrs(int fd){ Routersol *rs; uchar buff[sizeof *rs]; memset(buff, 0, sizeof buff); rs = (Routersol *)buff; memmove(rs->dst, v6allroutersL, IPaddrlen); memmove(rs->src, v6Unspecified, IPaddrlen); rs->type = ICMP6_RS; if(write(fd, rs, sizeof buff) < sizeof buff) ralog("sendrs: write failed, pkt size %d", sizeof buff); else ralog("sendrs: sent solicitation to %I from %I on %s", rs->dst, rs->src, conf.dev);} /* * a router receiving a router adv from another * router calls this; it is basically supposed to * log the information in the ra and raise a flag * if any parameter value is different from its configured values. *Lines 1–500 of 993. Load more
/* * ipconfig for IPv6 * RS means Router Solicitation * RA means Router Advertisement */ #include <u.h> #include <libc.h> #include <bio.h> #include <ip.h> #include "ipconfig.h" #include "../icmp.h" #pragma varargck argpos ralog 1 #define RALOG "v6routeradv" #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1]) #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \ ((uchar*)x)[2]<< 8 | ((uchar*)x)[3]) enum { ICMP6LEN= 4, }; typedef struct Hdr Hdr; struct Hdr /* ICMP v4 & v6 header */ { uchar type; uchar code; uchar cksum[2]; /* Checksum */ uchar data[]; }; char *icmpmsg6[Maxtype6+1] = { [EchoReply] "EchoReply", [UnreachableV6] "UnreachableV6", [PacketTooBigV6] "PacketTooBigV6", [TimeExceedV6] "TimeExceedV6", [Redirect] "Redirect", [EchoRequest] "EchoRequest", [TimeExceed] "TimeExceed", [InParmProblem] "InParmProblem", [Timestamp] "Timestamp", [TimestampReply] "TimestampReply", [InfoRequest] "InfoRequest", [InfoReply] "InfoReply", [AddrMaskRequest] "AddrMaskRequest", [AddrMaskReply] "AddrMaskReply", [EchoRequestV6] "EchoRequestV6", [EchoReplyV6] "EchoReplyV6", [RouterSolicit] "RouterSolicit", [RouterAdvert] "RouterAdvert", [NbrSolicit] "NbrSolicit", [NbrAdvert] "NbrAdvert", [RedirectV6] "RedirectV6", }; static char *icmp6opts[] = { [0] "unknown option", [V6nd_srclladdr] "srcll_addr", [V6nd_targlladdr] "targll_addr", [V6nd_pfxinfo] "prefix", [V6nd_redirhdr] "redirect", [V6nd_mtu] "mtu", [V6nd_home] "home", [V6nd_srcaddrs] "src_addrs", [V6nd_ip] "ip", [V6nd_rdns] "rdns", [V6nd_9fs] "9fs", [V6nd_9auth] "9auth", }; uchar v6allroutersL[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02 }; uchar v6allnodesL[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 }; uchar v6Unspecified[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uchar v6loopback[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; uchar v6glunicast[IPaddrlen] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uchar v6linklocal[IPaddrlen] = { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uchar v6solpfx[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* last 3 bytes filled with low-order bytes of addr being solicited */ 0xff, 0, 0, 0, }; uchar v6defmask[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0 }; enum { Vadd, Vremove, Vunbind, Vaddpref6, Vra6, }; static void ralog(char *fmt, ...) { char msg[512]; va_list arg; va_start(arg, fmt); vseprint(msg, msg+sizeof msg, fmt, arg); va_end(arg); syslog(debug, RALOG, msg); } extern void ea2lla(uchar *lla, uchar *ea) { assert(IPaddrlen == 16); memset(lla, 0, IPaddrlen); lla[0] = 0xFE; lla[1] = 0x80; lla[8] = ea[0] | 0x2; lla[9] = ea[1]; lla[10] = ea[2]; lla[11] = 0xFF; lla[12] = 0xFE; lla[13] = ea[3]; lla[14] = ea[4]; lla[15] = ea[5]; } extern void ipv62smcast(uchar *smcast, uchar *a) { assert(IPaddrlen == 16); memset(smcast, 0, IPaddrlen); smcast[0] = 0xFF; smcast[1] = 0x02; smcast[11] = 0x1; smcast[12] = 0xFF; smcast[13] = a[13]; smcast[14] = a[14]; smcast[15] = a[15]; } void v6paraminit(Conf *cf) { cf->sendra = cf->recvra = 0; cf->mflag = 0; cf->oflag = 0; cf->maxraint = Maxv6initraintvl; cf->minraint = Maxv6initraintvl / 4; cf->linkmtu = 1500; cf->reachtime = V6reachabletime; cf->rxmitra = V6retranstimer; cf->ttl = MAXTTL; cf->routerlt = 0; cf->prefixlen = 64; cf->onlink = 0; cf->autoflag = 0; cf->validlt = cf->preflt = ~0L; } static char * optname(unsigned opt) { static char buf[32]; if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) { snprint(buf, sizeof buf, "unknown option %d", opt); return buf; } else return icmp6opts[opt]; } static char* opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe) { int otype, osz, pktsz; uchar *a; char *p = sps, *e = spe; a = ps; for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) { otype = a[0]; osz = a[1] * 8; switch (otype) { default: return seprint(p, e, " option=%s ", optname(otype)); case V6nd_srclladdr: case V6nd_targlladdr: if (pktsz < osz || osz != 8) return seprint(p, e, " option=%s bad size=%d", optname(otype), osz); p = seprint(p, e, " option=%s maddr=%E", optname(otype), a+2); break; case V6nd_pfxinfo: if (pktsz < osz || osz != 32) return seprint(p, e, " option=%s: bad size=%d", optname(otype), osz); p = seprint(p, e, " option=%s pref=%I preflen=%3.3d" " lflag=%1.1d aflag=%1.1d unused1=%1.1d" " validlt=%ud preflt=%ud unused2=%1.1d", optname(otype), a+16, (int)(*(a+2)), (*(a+3) & (1 << 7)) != 0, (*(a+3) & (1 << 6)) != 0, (*(a+3) & 63) != 0, NetL(a+4), NetL(a+8), NetL(a+12)!=0); break; } a += osz; } return p; } static void pkt2str(uchar *ps, uchar *pe, char *sps, char *spe) { int pktlen; char *tn, *p, *e; uchar *a; Hdr *h; h = (Hdr*)ps; a = ps + 4; p = sps; e = spe; pktlen = pe - ps; if(pktlen < ICMP6LEN) { seprint(sps, spe, "short pkt"); return; } tn = icmpmsg6[h->type]; if(tn == nil) p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type, h->code, (ushort)NetS(h->cksum)); else p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn, h->code, (ushort)NetS(h->cksum)); switch(h->type){ case RouterSolicit: ps += 8; p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0); opt_seprint(ps, pe, p, e); break; case RouterAdvert: ps += 16; p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d" " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d", a[0], (*(a+1) & (1 << 7)) != 0, (*(a+1) & (1 << 6)) != 0, (*(a+1) & 63) != 0, NetS(a+2), NetL(a+4), NetL(a+8)); opt_seprint(ps, pe, p, e); break; default: seprint(p, e, " unexpected icmp6 pkt type"); break; } } static void catch(void *a, char *msg) { USED(a); if(strstr(msg, "alarm")) noted(NCONT); else noted(NDFLT); } /* * based on libthread's threadsetname, but drags in less library code. * actually just sets the arguments displayed. */ void procsetname(char *fmt, ...) { int fd; char *cmdname; char buf[128]; va_list arg; va_start(arg, fmt); cmdname = vsmprint(fmt, arg); va_end(arg); if (cmdname == nil) return; snprint(buf, sizeof buf, "#p/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, cmdname, strlen(cmdname)+1); close(fd); } free(cmdname); } int dialicmp(uchar *dst, int dport, int *ctlfd) { int fd, cfd, n, m; char cmsg[100], name[128], connind[40]; char hdrs[] = "headers"; snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint); cfd = open(name, ORDWR); if(cfd < 0) sysfatal("dialicmp: can't open %s: %r", name); n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport); m = write(cfd, cmsg, n); if (m < n) sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name); seek(cfd, 0, 0); n = read(cfd, connind, sizeof connind); if (n < 0) connind[0] = 0; else if (n < sizeof connind) connind[n] = 0; else connind[sizeof connind - 1] = 0; snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind); fd = open(name, ORDWR); if(fd < 0) sysfatal("dialicmp: can't open %s: %r", name); n = sizeof hdrs - 1; if(write(cfd, hdrs, n) < n) sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name); *ctlfd = cfd; return fd; } /* add ipv6 addr to an interface */ int ip6cfg(int autoconf) { int dupfound = 0, n; char *p; char buf[256]; uchar ethaddr[6]; Biobuf *bp; if (autoconf) { /* create link-local addr */ if (myetheraddr(ethaddr, conf.dev) < 0) sysfatal("myetheraddr w/ %s failed: %r", conf.dev); ea2lla(conf.laddr, ethaddr); } if (dupl_disc) n = sprint(buf, "try"); else n = sprint(buf, "add"); n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr); if(!validip(conf.mask)) ipmove(conf.mask, v6defmask); n += snprint(buf+n, sizeof buf-n, " %M", conf.mask); if(validip(conf.raddr)){ n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr); if(conf.mtu != 0) n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu); } if(write(conf.cfd, buf, n) < 0){ warning("write(%s): %r", buf); return -1; } if (!dupl_disc) return 0; sleep(3000); /* read arp table, look for addr duplication */ snprint(buf, sizeof buf, "%s/arp", conf.mpoint); bp = Bopen(buf, OREAD); if (bp == 0) { warning("couldn't open %s: %r", buf); return -1; } snprint(buf, sizeof buf, "%I", conf.laddr); while(p = Brdline(bp, '\n')){ p[Blinelen(bp)-1] = 0; if(cistrstr(p, buf) != 0) { warning("found dup entry in arp cache"); dupfound = 1; break; } } Bterm(bp); if (dupfound) doremove(); else { n = sprint(buf, "add %I %M", conf.laddr, conf.mask); if(validip(conf.raddr)){ n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr); if(conf.mtu != 0) n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu); } write(conf.cfd, buf, n); } return 0; } static int recvra6on(char *net, int conn) { Ipifc* ifc; ifc = readipifc(net, nil, conn); if (ifc == nil) return 0; else if (ifc->sendra6 > 0) return IsRouter; else if (ifc->recvra6 > 0) return IsHostRecv; else return IsHostNoRecv; } /* send icmpv6 router solicitation to multicast address for all routers */ static void sendrs(int fd) { Routersol *rs; uchar buff[sizeof *rs]; memset(buff, 0, sizeof buff); rs = (Routersol *)buff; memmove(rs->dst, v6allroutersL, IPaddrlen); memmove(rs->src, v6Unspecified, IPaddrlen); rs->type = ICMP6_RS; if(write(fd, rs, sizeof buff) < sizeof buff) ralog("sendrs: write failed, pkt size %d", sizeof buff); else ralog("sendrs: sent solicitation to %I from %I on %s", rs->dst, rs->src, conf.dev); } /* * a router receiving a router adv from another * router calls this; it is basically supposed to * log the information in the ra and raise a flag * if any parameter value is different from its configured values. *