1e47528f3SDavid du Colombier /*
2e47528f3SDavid du Colombier * ipconfig for IPv6
38c6ab946SDavid du Colombier * RS means Router Solicitation
48c6ab946SDavid du Colombier * RA means Router Advertisement
5e47528f3SDavid du Colombier */
6e47528f3SDavid du Colombier
7e47528f3SDavid du Colombier #include <u.h>
8e47528f3SDavid du Colombier #include <libc.h>
9e47528f3SDavid du Colombier #include <bio.h>
10e47528f3SDavid du Colombier #include <ip.h>
11e47528f3SDavid du Colombier #include "ipconfig.h"
12e47528f3SDavid du Colombier #include "../icmp.h"
13e47528f3SDavid du Colombier
14e47528f3SDavid du Colombier #pragma varargck argpos ralog 1
15e47528f3SDavid du Colombier
16e47528f3SDavid du Colombier #define RALOG "v6routeradv"
17e47528f3SDavid du Colombier
18e47528f3SDavid du Colombier #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
19e47528f3SDavid du Colombier #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
20e47528f3SDavid du Colombier ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
21e47528f3SDavid du Colombier
22e47528f3SDavid du Colombier enum {
23e47528f3SDavid du Colombier ICMP6LEN= 4,
24e47528f3SDavid du Colombier };
25e47528f3SDavid du Colombier
26e47528f3SDavid du Colombier typedef struct Hdr Hdr;
27e47528f3SDavid du Colombier struct Hdr /* ICMP v4 & v6 header */
28e47528f3SDavid du Colombier {
29e47528f3SDavid du Colombier uchar type;
30e47528f3SDavid du Colombier uchar code;
31e47528f3SDavid du Colombier uchar cksum[2]; /* Checksum */
3294aa1c4cSDavid du Colombier uchar data[];
33e47528f3SDavid du Colombier };
34e47528f3SDavid du Colombier
35e47528f3SDavid du Colombier char *icmpmsg6[Maxtype6+1] =
36e47528f3SDavid du Colombier {
37e47528f3SDavid du Colombier [EchoReply] "EchoReply",
38e47528f3SDavid du Colombier [UnreachableV6] "UnreachableV6",
39e47528f3SDavid du Colombier [PacketTooBigV6] "PacketTooBigV6",
40e47528f3SDavid du Colombier [TimeExceedV6] "TimeExceedV6",
41e47528f3SDavid du Colombier [Redirect] "Redirect",
42e47528f3SDavid du Colombier [EchoRequest] "EchoRequest",
43e47528f3SDavid du Colombier [TimeExceed] "TimeExceed",
44e47528f3SDavid du Colombier [InParmProblem] "InParmProblem",
45e47528f3SDavid du Colombier [Timestamp] "Timestamp",
46e47528f3SDavid du Colombier [TimestampReply] "TimestampReply",
47e47528f3SDavid du Colombier [InfoRequest] "InfoRequest",
48e47528f3SDavid du Colombier [InfoReply] "InfoReply",
49e47528f3SDavid du Colombier [AddrMaskRequest] "AddrMaskRequest",
50e47528f3SDavid du Colombier [AddrMaskReply] "AddrMaskReply",
51e47528f3SDavid du Colombier [EchoRequestV6] "EchoRequestV6",
52e47528f3SDavid du Colombier [EchoReplyV6] "EchoReplyV6",
53e47528f3SDavid du Colombier [RouterSolicit] "RouterSolicit",
54e47528f3SDavid du Colombier [RouterAdvert] "RouterAdvert",
55e47528f3SDavid du Colombier [NbrSolicit] "NbrSolicit",
56e47528f3SDavid du Colombier [NbrAdvert] "NbrAdvert",
57e47528f3SDavid du Colombier [RedirectV6] "RedirectV6",
58e47528f3SDavid du Colombier };
59e47528f3SDavid du Colombier
60e47528f3SDavid du Colombier static char *icmp6opts[] =
61e47528f3SDavid du Colombier {
62de1e7cd0SDavid du Colombier [0] "unknown option",
630a84db5eSDavid du Colombier [V6nd_srclladdr] "srcll_addr",
640a84db5eSDavid du Colombier [V6nd_targlladdr] "targll_addr",
650a84db5eSDavid du Colombier [V6nd_pfxinfo] "prefix",
668c6ab946SDavid du Colombier [V6nd_redirhdr] "redirect",
670a84db5eSDavid du Colombier [V6nd_mtu] "mtu",
680a84db5eSDavid du Colombier [V6nd_home] "home",
690a84db5eSDavid du Colombier [V6nd_srcaddrs] "src_addrs",
700a84db5eSDavid du Colombier [V6nd_ip] "ip",
710a84db5eSDavid du Colombier [V6nd_rdns] "rdns",
720a84db5eSDavid du Colombier [V6nd_9fs] "9fs",
730a84db5eSDavid du Colombier [V6nd_9auth] "9auth",
74e47528f3SDavid du Colombier };
75e47528f3SDavid du Colombier
76e47528f3SDavid du Colombier uchar v6allroutersL[IPaddrlen] = {
77e47528f3SDavid du Colombier 0xff, 0x02, 0, 0,
78e47528f3SDavid du Colombier 0, 0, 0, 0,
79e47528f3SDavid du Colombier 0, 0, 0, 0,
80e47528f3SDavid du Colombier 0, 0, 0, 0x02
81e47528f3SDavid du Colombier };
82e47528f3SDavid du Colombier
83e47528f3SDavid du Colombier uchar v6allnodesL[IPaddrlen] = {
84e47528f3SDavid du Colombier 0xff, 0x02, 0, 0,
85e47528f3SDavid du Colombier 0, 0, 0, 0,
86e47528f3SDavid du Colombier 0, 0, 0, 0,
87e47528f3SDavid du Colombier 0, 0, 0, 0x01
88e47528f3SDavid du Colombier };
89e47528f3SDavid du Colombier
90e47528f3SDavid du Colombier uchar v6Unspecified[IPaddrlen] = {
91e47528f3SDavid du Colombier 0, 0, 0, 0,
92e47528f3SDavid du Colombier 0, 0, 0, 0,
93e47528f3SDavid du Colombier 0, 0, 0, 0,
94e47528f3SDavid du Colombier 0, 0, 0, 0
95e47528f3SDavid du Colombier };
96e47528f3SDavid du Colombier
975e1edbcaSDavid du Colombier uchar v6loopback[IPaddrlen] = {
985e1edbcaSDavid du Colombier 0, 0, 0, 0,
995e1edbcaSDavid du Colombier 0, 0, 0, 0,
1005e1edbcaSDavid du Colombier 0, 0, 0, 0,
1015e1edbcaSDavid du Colombier 0, 0, 0, 1
1025e1edbcaSDavid du Colombier };
1035e1edbcaSDavid du Colombier
104e47528f3SDavid du Colombier uchar v6glunicast[IPaddrlen] = {
105e47528f3SDavid du Colombier 0x08, 0, 0, 0,
106e47528f3SDavid du Colombier 0, 0, 0, 0,
107e47528f3SDavid du Colombier 0, 0, 0, 0,
108e47528f3SDavid du Colombier 0, 0, 0, 0
109e47528f3SDavid du Colombier };
110e47528f3SDavid du Colombier
111e47528f3SDavid du Colombier uchar v6linklocal[IPaddrlen] = {
112e47528f3SDavid du Colombier 0xfe, 0x80, 0, 0,
113e47528f3SDavid du Colombier 0, 0, 0, 0,
114e47528f3SDavid du Colombier 0, 0, 0, 0,
115e47528f3SDavid du Colombier 0, 0, 0, 0
116e47528f3SDavid du Colombier };
117e47528f3SDavid du Colombier
118e47528f3SDavid du Colombier uchar v6solpfx[IPaddrlen] = {
119e47528f3SDavid du Colombier 0xff, 0x02, 0, 0,
120e47528f3SDavid du Colombier 0, 0, 0, 0,
121e47528f3SDavid du Colombier 0, 0, 0, 1,
122e47528f3SDavid du Colombier /* last 3 bytes filled with low-order bytes of addr being solicited */
123e47528f3SDavid du Colombier 0xff, 0, 0, 0,
124e47528f3SDavid du Colombier };
125e47528f3SDavid du Colombier
126e47528f3SDavid du Colombier uchar v6defmask[IPaddrlen] = {
127e47528f3SDavid du Colombier 0xff, 0xff, 0xff, 0xff,
128e47528f3SDavid du Colombier 0xff, 0xff, 0xff, 0xff,
129e47528f3SDavid du Colombier 0, 0, 0, 0,
130e47528f3SDavid du Colombier 0, 0, 0, 0
131e47528f3SDavid du Colombier };
132e47528f3SDavid du Colombier
133e47528f3SDavid du Colombier enum
134e47528f3SDavid du Colombier {
135e47528f3SDavid du Colombier Vadd,
136e47528f3SDavid du Colombier Vremove,
137e47528f3SDavid du Colombier Vunbind,
138e47528f3SDavid du Colombier Vaddpref6,
139e47528f3SDavid du Colombier Vra6,
140e47528f3SDavid du Colombier };
141e47528f3SDavid du Colombier
142e47528f3SDavid du Colombier static void
ralog(char * fmt,...)143e47528f3SDavid du Colombier ralog(char *fmt, ...)
144e47528f3SDavid du Colombier {
145e47528f3SDavid du Colombier char msg[512];
146e47528f3SDavid du Colombier va_list arg;
147e47528f3SDavid du Colombier
148e47528f3SDavid du Colombier va_start(arg, fmt);
149e47528f3SDavid du Colombier vseprint(msg, msg+sizeof msg, fmt, arg);
150e47528f3SDavid du Colombier va_end(arg);
151e47528f3SDavid du Colombier syslog(debug, RALOG, msg);
152e47528f3SDavid du Colombier }
153e47528f3SDavid du Colombier
154e47528f3SDavid du Colombier extern void
ea2lla(uchar * lla,uchar * ea)155e47528f3SDavid du Colombier ea2lla(uchar *lla, uchar *ea)
156e47528f3SDavid du Colombier {
157e47528f3SDavid du Colombier assert(IPaddrlen == 16);
158e47528f3SDavid du Colombier memset(lla, 0, IPaddrlen);
159e47528f3SDavid du Colombier lla[0] = 0xFE;
160e47528f3SDavid du Colombier lla[1] = 0x80;
161e47528f3SDavid du Colombier lla[8] = ea[0] | 0x2;
162e47528f3SDavid du Colombier lla[9] = ea[1];
163e47528f3SDavid du Colombier lla[10] = ea[2];
164e47528f3SDavid du Colombier lla[11] = 0xFF;
165e47528f3SDavid du Colombier lla[12] = 0xFE;
166e47528f3SDavid du Colombier lla[13] = ea[3];
167e47528f3SDavid du Colombier lla[14] = ea[4];
168e47528f3SDavid du Colombier lla[15] = ea[5];
169e47528f3SDavid du Colombier }
170e47528f3SDavid du Colombier
171e47528f3SDavid du Colombier extern void
ipv62smcast(uchar * smcast,uchar * a)172e47528f3SDavid du Colombier ipv62smcast(uchar *smcast, uchar *a)
173e47528f3SDavid du Colombier {
174e47528f3SDavid du Colombier assert(IPaddrlen == 16);
175e47528f3SDavid du Colombier memset(smcast, 0, IPaddrlen);
176e47528f3SDavid du Colombier smcast[0] = 0xFF;
177e47528f3SDavid du Colombier smcast[1] = 0x02;
178e47528f3SDavid du Colombier smcast[11] = 0x1;
179e47528f3SDavid du Colombier smcast[12] = 0xFF;
180e47528f3SDavid du Colombier smcast[13] = a[13];
181e47528f3SDavid du Colombier smcast[14] = a[14];
182e47528f3SDavid du Colombier smcast[15] = a[15];
183e47528f3SDavid du Colombier }
184e47528f3SDavid du Colombier
185e47528f3SDavid du Colombier void
v6paraminit(Conf * cf)186ccaac148SDavid du Colombier v6paraminit(Conf *cf)
187e47528f3SDavid du Colombier {
188ccaac148SDavid du Colombier cf->sendra = cf->recvra = 0;
189ccaac148SDavid du Colombier cf->mflag = 0;
190ccaac148SDavid du Colombier cf->oflag = 0;
1915e1edbcaSDavid du Colombier cf->maxraint = Maxv6initraintvl;
1925e1edbcaSDavid du Colombier cf->minraint = Maxv6initraintvl / 4;
193ccaac148SDavid du Colombier cf->linkmtu = 1500;
1945e1edbcaSDavid du Colombier cf->reachtime = V6reachabletime;
1955e1edbcaSDavid du Colombier cf->rxmitra = V6retranstimer;
196ccaac148SDavid du Colombier cf->ttl = MAXTTL;
197e47528f3SDavid du Colombier
198ccaac148SDavid du Colombier cf->routerlt = 0;
199e47528f3SDavid du Colombier
200ccaac148SDavid du Colombier cf->prefixlen = 64;
201ccaac148SDavid du Colombier cf->onlink = 0;
202ccaac148SDavid du Colombier cf->autoflag = 0;
203ccaac148SDavid du Colombier cf->validlt = cf->preflt = ~0L;
204e47528f3SDavid du Colombier }
205e47528f3SDavid du Colombier
206e47528f3SDavid du Colombier static char *
optname(unsigned opt)2070a84db5eSDavid du Colombier optname(unsigned opt)
2080a84db5eSDavid du Colombier {
2090a84db5eSDavid du Colombier static char buf[32];
2100a84db5eSDavid du Colombier
2110a84db5eSDavid du Colombier if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
2120a84db5eSDavid du Colombier snprint(buf, sizeof buf, "unknown option %d", opt);
2130a84db5eSDavid du Colombier return buf;
2140a84db5eSDavid du Colombier } else
2150a84db5eSDavid du Colombier return icmp6opts[opt];
2160a84db5eSDavid du Colombier }
2170a84db5eSDavid du Colombier
2180a84db5eSDavid du Colombier static char*
opt_seprint(uchar * ps,uchar * pe,char * sps,char * spe)219e47528f3SDavid du Colombier opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
220e47528f3SDavid du Colombier {
221e47528f3SDavid du Colombier int otype, osz, pktsz;
222e47528f3SDavid du Colombier uchar *a;
223e47528f3SDavid du Colombier char *p = sps, *e = spe;
224e47528f3SDavid du Colombier
225e47528f3SDavid du Colombier a = ps;
226e47528f3SDavid du Colombier for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
227e47528f3SDavid du Colombier otype = a[0];
228e47528f3SDavid du Colombier osz = a[1] * 8;
229e47528f3SDavid du Colombier
230e47528f3SDavid du Colombier switch (otype) {
231e47528f3SDavid du Colombier default:
2320a84db5eSDavid du Colombier return seprint(p, e, " option=%s ", optname(otype));
2338c6ab946SDavid du Colombier case V6nd_srclladdr:
2348c6ab946SDavid du Colombier case V6nd_targlladdr:
235e47528f3SDavid du Colombier if (pktsz < osz || osz != 8)
236e47528f3SDavid du Colombier return seprint(p, e, " option=%s bad size=%d",
2370a84db5eSDavid du Colombier optname(otype), osz);
2380a84db5eSDavid du Colombier p = seprint(p, e, " option=%s maddr=%E", optname(otype),
2390a84db5eSDavid du Colombier a+2);
240e47528f3SDavid du Colombier break;
2418c6ab946SDavid du Colombier case V6nd_pfxinfo:
242e47528f3SDavid du Colombier if (pktsz < osz || osz != 32)
243e47528f3SDavid du Colombier return seprint(p, e, " option=%s: bad size=%d",
2440a84db5eSDavid du Colombier optname(otype), osz);
245e47528f3SDavid du Colombier
246e47528f3SDavid du Colombier p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
247e47528f3SDavid du Colombier " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
248e47528f3SDavid du Colombier " validlt=%ud preflt=%ud unused2=%1.1d",
2490a84db5eSDavid du Colombier optname(otype), a+16, (int)(*(a+2)),
250e47528f3SDavid du Colombier (*(a+3) & (1 << 7)) != 0,
251e47528f3SDavid du Colombier (*(a+3) & (1 << 6)) != 0,
252e47528f3SDavid du Colombier (*(a+3) & 63) != 0,
253e47528f3SDavid du Colombier NetL(a+4), NetL(a+8), NetL(a+12)!=0);
254e47528f3SDavid du Colombier break;
255e47528f3SDavid du Colombier }
256e47528f3SDavid du Colombier a += osz;
257e47528f3SDavid du Colombier }
258e47528f3SDavid du Colombier return p;
259e47528f3SDavid du Colombier }
260e47528f3SDavid du Colombier
261e47528f3SDavid du Colombier static void
pkt2str(uchar * ps,uchar * pe,char * sps,char * spe)262e47528f3SDavid du Colombier pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
263e47528f3SDavid du Colombier {
264e47528f3SDavid du Colombier int pktlen;
265e47528f3SDavid du Colombier char *tn, *p, *e;
266e47528f3SDavid du Colombier uchar *a;
267e47528f3SDavid du Colombier Hdr *h;
268e47528f3SDavid du Colombier
269e47528f3SDavid du Colombier h = (Hdr*)ps;
270e47528f3SDavid du Colombier a = ps + 4;
271e47528f3SDavid du Colombier p = sps;
272e47528f3SDavid du Colombier e = spe;
273e47528f3SDavid du Colombier
274e47528f3SDavid du Colombier pktlen = pe - ps;
275e47528f3SDavid du Colombier if(pktlen < ICMP6LEN) {
276e47528f3SDavid du Colombier seprint(sps, spe, "short pkt");
277e47528f3SDavid du Colombier return;
278e47528f3SDavid du Colombier }
279e47528f3SDavid du Colombier
280e47528f3SDavid du Colombier tn = icmpmsg6[h->type];
281e47528f3SDavid du Colombier if(tn == nil)
282e47528f3SDavid du Colombier p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
283e47528f3SDavid du Colombier h->code, (ushort)NetS(h->cksum));
284e47528f3SDavid du Colombier else
285e47528f3SDavid du Colombier p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
286e47528f3SDavid du Colombier h->code, (ushort)NetS(h->cksum));
287e47528f3SDavid du Colombier
288e47528f3SDavid du Colombier switch(h->type){
289e47528f3SDavid du Colombier case RouterSolicit:
290e47528f3SDavid du Colombier ps += 8;
291e47528f3SDavid du Colombier p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
292e47528f3SDavid du Colombier opt_seprint(ps, pe, p, e);
293e47528f3SDavid du Colombier break;
294e47528f3SDavid du Colombier case RouterAdvert:
295e47528f3SDavid du Colombier ps += 16;
296e47528f3SDavid du Colombier p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
297e47528f3SDavid du Colombier " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
298e47528f3SDavid du Colombier a[0],
299e47528f3SDavid du Colombier (*(a+1) & (1 << 7)) != 0,
300e47528f3SDavid du Colombier (*(a+1) & (1 << 6)) != 0,
301e47528f3SDavid du Colombier (*(a+1) & 63) != 0,
302e47528f3SDavid du Colombier NetS(a+2), NetL(a+4), NetL(a+8));
303e47528f3SDavid du Colombier opt_seprint(ps, pe, p, e);
304e47528f3SDavid du Colombier break;
305e47528f3SDavid du Colombier default:
306e47528f3SDavid du Colombier seprint(p, e, " unexpected icmp6 pkt type");
307e47528f3SDavid du Colombier break;
308e47528f3SDavid du Colombier }
309e47528f3SDavid du Colombier }
310e47528f3SDavid du Colombier
311e47528f3SDavid du Colombier static void
catch(void * a,char * msg)312e47528f3SDavid du Colombier catch(void *a, char *msg)
313e47528f3SDavid du Colombier {
314e47528f3SDavid du Colombier USED(a);
315e47528f3SDavid du Colombier if(strstr(msg, "alarm"))
316e47528f3SDavid du Colombier noted(NCONT);
317e47528f3SDavid du Colombier else
318e47528f3SDavid du Colombier noted(NDFLT);
319e47528f3SDavid du Colombier }
320e47528f3SDavid du Colombier
321e47528f3SDavid du Colombier /*
322e47528f3SDavid du Colombier * based on libthread's threadsetname, but drags in less library code.
323e47528f3SDavid du Colombier * actually just sets the arguments displayed.
324e47528f3SDavid du Colombier */
325e47528f3SDavid du Colombier void
procsetname(char * fmt,...)326e47528f3SDavid du Colombier procsetname(char *fmt, ...)
327e47528f3SDavid du Colombier {
328e47528f3SDavid du Colombier int fd;
329e47528f3SDavid du Colombier char *cmdname;
330e47528f3SDavid du Colombier char buf[128];
331e47528f3SDavid du Colombier va_list arg;
332e47528f3SDavid du Colombier
333e47528f3SDavid du Colombier va_start(arg, fmt);
334e47528f3SDavid du Colombier cmdname = vsmprint(fmt, arg);
335e47528f3SDavid du Colombier va_end(arg);
336e47528f3SDavid du Colombier if (cmdname == nil)
337e47528f3SDavid du Colombier return;
338e47528f3SDavid du Colombier snprint(buf, sizeof buf, "#p/%d/args", getpid());
339e47528f3SDavid du Colombier if((fd = open(buf, OWRITE)) >= 0){
340e47528f3SDavid du Colombier write(fd, cmdname, strlen(cmdname)+1);
341e47528f3SDavid du Colombier close(fd);
342e47528f3SDavid du Colombier }
343e47528f3SDavid du Colombier free(cmdname);
344e47528f3SDavid du Colombier }
345e47528f3SDavid du Colombier
346e47528f3SDavid du Colombier int
dialicmp(uchar * dst,int dport,int * ctlfd)347e47528f3SDavid du Colombier dialicmp(uchar *dst, int dport, int *ctlfd)
348e47528f3SDavid du Colombier {
349e47528f3SDavid du Colombier int fd, cfd, n, m;
350e47528f3SDavid du Colombier char cmsg[100], name[128], connind[40];
351e47528f3SDavid du Colombier char hdrs[] = "headers";
352e47528f3SDavid du Colombier
353e47528f3SDavid du Colombier snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
354e47528f3SDavid du Colombier cfd = open(name, ORDWR);
355e47528f3SDavid du Colombier if(cfd < 0)
356e47528f3SDavid du Colombier sysfatal("dialicmp: can't open %s: %r", name);
357e47528f3SDavid du Colombier
358e47528f3SDavid du Colombier n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
359e47528f3SDavid du Colombier m = write(cfd, cmsg, n);
360e47528f3SDavid du Colombier if (m < n)
361e47528f3SDavid du Colombier sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
362e47528f3SDavid du Colombier
363e47528f3SDavid du Colombier seek(cfd, 0, 0);
364e47528f3SDavid du Colombier n = read(cfd, connind, sizeof connind);
365e47528f3SDavid du Colombier if (n < 0)
366e47528f3SDavid du Colombier connind[0] = 0;
367e47528f3SDavid du Colombier else if (n < sizeof connind)
368e47528f3SDavid du Colombier connind[n] = 0;
369e47528f3SDavid du Colombier else
370e47528f3SDavid du Colombier connind[sizeof connind - 1] = 0;
371e47528f3SDavid du Colombier
372e47528f3SDavid du Colombier snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
373e47528f3SDavid du Colombier fd = open(name, ORDWR);
374e47528f3SDavid du Colombier if(fd < 0)
375e47528f3SDavid du Colombier sysfatal("dialicmp: can't open %s: %r", name);
376e47528f3SDavid du Colombier
377e47528f3SDavid du Colombier n = sizeof hdrs - 1;
378e47528f3SDavid du Colombier if(write(cfd, hdrs, n) < n)
379e47528f3SDavid du Colombier sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
380e47528f3SDavid du Colombier *ctlfd = cfd;
381e47528f3SDavid du Colombier return fd;
382e47528f3SDavid du Colombier }
383e47528f3SDavid du Colombier
384e47528f3SDavid du Colombier /* add ipv6 addr to an interface */
385e47528f3SDavid du Colombier int
ip6cfg(int autoconf)386e47528f3SDavid du Colombier ip6cfg(int autoconf)
387e47528f3SDavid du Colombier {
388e47528f3SDavid du Colombier int dupfound = 0, n;
389e47528f3SDavid du Colombier char *p;
390e47528f3SDavid du Colombier char buf[256];
391e47528f3SDavid du Colombier uchar ethaddr[6];
392e47528f3SDavid du Colombier Biobuf *bp;
393e47528f3SDavid du Colombier
394e47528f3SDavid du Colombier if (autoconf) { /* create link-local addr */
395e47528f3SDavid du Colombier if (myetheraddr(ethaddr, conf.dev) < 0)
396e47528f3SDavid du Colombier sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
397e47528f3SDavid du Colombier ea2lla(conf.laddr, ethaddr);
398e47528f3SDavid du Colombier }
399e47528f3SDavid du Colombier
400e47528f3SDavid du Colombier if (dupl_disc)
401e47528f3SDavid du Colombier n = sprint(buf, "try");
402e47528f3SDavid du Colombier else
403e47528f3SDavid du Colombier n = sprint(buf, "add");
404e47528f3SDavid du Colombier
405e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
406e47528f3SDavid du Colombier if(!validip(conf.mask))
407e47528f3SDavid du Colombier ipmove(conf.mask, v6defmask);
408e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
409e47528f3SDavid du Colombier if(validip(conf.raddr)){
410e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
411e47528f3SDavid du Colombier if(conf.mtu != 0)
412e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
413e47528f3SDavid du Colombier }
414e47528f3SDavid du Colombier
415e47528f3SDavid du Colombier if(write(conf.cfd, buf, n) < 0){
4168c6ab946SDavid du Colombier warning("write(%s): %r", buf);
417e47528f3SDavid du Colombier return -1;
418e47528f3SDavid du Colombier }
419e47528f3SDavid du Colombier
420e47528f3SDavid du Colombier if (!dupl_disc)
421e47528f3SDavid du Colombier return 0;
422e47528f3SDavid du Colombier
423e47528f3SDavid du Colombier sleep(3000);
424e47528f3SDavid du Colombier
425e47528f3SDavid du Colombier /* read arp table, look for addr duplication */
426e47528f3SDavid du Colombier snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
427e47528f3SDavid du Colombier bp = Bopen(buf, OREAD);
428e47528f3SDavid du Colombier if (bp == 0) {
4298c6ab946SDavid du Colombier warning("couldn't open %s: %r", buf);
430e47528f3SDavid du Colombier return -1;
431e47528f3SDavid du Colombier }
432e47528f3SDavid du Colombier
433e47528f3SDavid du Colombier snprint(buf, sizeof buf, "%I", conf.laddr);
434e47528f3SDavid du Colombier while(p = Brdline(bp, '\n')){
435e47528f3SDavid du Colombier p[Blinelen(bp)-1] = 0;
436e47528f3SDavid du Colombier if(cistrstr(p, buf) != 0) {
4378c6ab946SDavid du Colombier warning("found dup entry in arp cache");
438e47528f3SDavid du Colombier dupfound = 1;
439e47528f3SDavid du Colombier break;
440e47528f3SDavid du Colombier }
441e47528f3SDavid du Colombier }
442e47528f3SDavid du Colombier Bterm(bp);
443e47528f3SDavid du Colombier
444e47528f3SDavid du Colombier if (dupfound)
445e47528f3SDavid du Colombier doremove();
446e47528f3SDavid du Colombier else {
447e47528f3SDavid du Colombier n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
448e47528f3SDavid du Colombier if(validip(conf.raddr)){
449e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
450e47528f3SDavid du Colombier if(conf.mtu != 0)
451e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %d",
452e47528f3SDavid du Colombier conf.mtu);
453e47528f3SDavid du Colombier }
454e47528f3SDavid du Colombier write(conf.cfd, buf, n);
455e47528f3SDavid du Colombier }
456e47528f3SDavid du Colombier return 0;
457e47528f3SDavid du Colombier }
458e47528f3SDavid du Colombier
459e47528f3SDavid du Colombier static int
recvra6on(char * net,int conn)460e47528f3SDavid du Colombier recvra6on(char *net, int conn)
461e47528f3SDavid du Colombier {
462e47528f3SDavid du Colombier Ipifc* ifc;
463e47528f3SDavid du Colombier
464e47528f3SDavid du Colombier ifc = readipifc(net, nil, conn);
465e47528f3SDavid du Colombier if (ifc == nil)
466e47528f3SDavid du Colombier return 0;
467e47528f3SDavid du Colombier else if (ifc->sendra6 > 0)
468e47528f3SDavid du Colombier return IsRouter;
469e47528f3SDavid du Colombier else if (ifc->recvra6 > 0)
470e47528f3SDavid du Colombier return IsHostRecv;
471e47528f3SDavid du Colombier else
472e47528f3SDavid du Colombier return IsHostNoRecv;
473e47528f3SDavid du Colombier }
474e47528f3SDavid du Colombier
4750a84db5eSDavid du Colombier /* send icmpv6 router solicitation to multicast address for all routers */
476e47528f3SDavid du Colombier static void
sendrs(int fd)477e47528f3SDavid du Colombier sendrs(int fd)
478e47528f3SDavid du Colombier {
479e47528f3SDavid du Colombier Routersol *rs;
480e47528f3SDavid du Colombier uchar buff[sizeof *rs];
481e47528f3SDavid du Colombier
482e47528f3SDavid du Colombier memset(buff, 0, sizeof buff);
483e47528f3SDavid du Colombier rs = (Routersol *)buff;
484e47528f3SDavid du Colombier memmove(rs->dst, v6allroutersL, IPaddrlen);
485e47528f3SDavid du Colombier memmove(rs->src, v6Unspecified, IPaddrlen);
486e47528f3SDavid du Colombier rs->type = ICMP6_RS;
487e47528f3SDavid du Colombier
488e47528f3SDavid du Colombier if(write(fd, rs, sizeof buff) < sizeof buff)
489e47528f3SDavid du Colombier ralog("sendrs: write failed, pkt size %d", sizeof buff);
4900a84db5eSDavid du Colombier else
4910a84db5eSDavid du Colombier ralog("sendrs: sent solicitation to %I from %I on %s",
4920a84db5eSDavid du Colombier rs->dst, rs->src, conf.dev);
493e47528f3SDavid du Colombier }
494e47528f3SDavid du Colombier
495e47528f3SDavid du Colombier /*
496e47528f3SDavid du Colombier * a router receiving a router adv from another
497e47528f3SDavid du Colombier * router calls this; it is basically supposed to
498e47528f3SDavid du Colombier * log the information in the ra and raise a flag
499e47528f3SDavid du Colombier * if any parameter value is different from its configured values.
500e47528f3SDavid du Colombier *
501e47528f3SDavid du Colombier * doing nothing for now since I don't know where to log this yet.
502e47528f3SDavid du Colombier */
503e47528f3SDavid du Colombier static void
recvrarouter(uchar buf[],int pktlen)504e47528f3SDavid du Colombier recvrarouter(uchar buf[], int pktlen)
505e47528f3SDavid du Colombier {
506e47528f3SDavid du Colombier USED(buf, pktlen);
507e47528f3SDavid du Colombier ralog("i am a router and got a router advert");
508e47528f3SDavid du Colombier }
509e47528f3SDavid du Colombier
510e47528f3SDavid du Colombier /* host receiving a router advertisement calls this */
511e47528f3SDavid du Colombier
512e47528f3SDavid du Colombier static void
ewrite(int fd,char * str)513ccaac148SDavid du Colombier ewrite(int fd, char *str)
514ccaac148SDavid du Colombier {
515ccaac148SDavid du Colombier int n;
516ccaac148SDavid du Colombier
517ccaac148SDavid du Colombier n = strlen(str);
518ccaac148SDavid du Colombier if (write(fd, str, n) != n)
519ccaac148SDavid du Colombier ralog("write(%s) failed: %r", str);
520ccaac148SDavid du Colombier }
521ccaac148SDavid du Colombier
522ccaac148SDavid du Colombier static void
issuebasera6(Conf * cf)523ccaac148SDavid du Colombier issuebasera6(Conf *cf)
524ccaac148SDavid du Colombier {
525ccaac148SDavid du Colombier char *cfg;
526ccaac148SDavid du Colombier
527ccaac148SDavid du Colombier cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
528ccaac148SDavid du Colombier "ttl %d routerlt %d",
529ccaac148SDavid du Colombier cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
530ccaac148SDavid du Colombier cf->ttl, cf->routerlt);
531ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
532ccaac148SDavid du Colombier free(cfg);
533ccaac148SDavid du Colombier }
534ccaac148SDavid du Colombier
535ccaac148SDavid du Colombier static void
issuerara6(Conf * cf)536ccaac148SDavid du Colombier issuerara6(Conf *cf)
537ccaac148SDavid du Colombier {
538ccaac148SDavid du Colombier char *cfg;
539ccaac148SDavid du Colombier
540ccaac148SDavid du Colombier cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
541ccaac148SDavid du Colombier "linkmtu %d",
542ccaac148SDavid du Colombier cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
543ccaac148SDavid du Colombier cf->linkmtu);
544ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
545ccaac148SDavid du Colombier free(cfg);
546ccaac148SDavid du Colombier }
547ccaac148SDavid du Colombier
548ccaac148SDavid du Colombier static void
issueadd6(Conf * cf)549ccaac148SDavid du Colombier issueadd6(Conf *cf)
550ccaac148SDavid du Colombier {
551ccaac148SDavid du Colombier char *cfg;
552ccaac148SDavid du Colombier
553ccaac148SDavid du Colombier cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
554ccaac148SDavid du Colombier cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
555ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
556ccaac148SDavid du Colombier free(cfg);
557ccaac148SDavid du Colombier }
558ccaac148SDavid du Colombier
559ccaac148SDavid du Colombier static void
recvrahost(uchar buf[],int pktlen)560e47528f3SDavid du Colombier recvrahost(uchar buf[], int pktlen)
561e47528f3SDavid du Colombier {
562e47528f3SDavid du Colombier int arpfd, m, n;
563ccaac148SDavid du Colombier char abuf[100];
564e47528f3SDavid du Colombier uchar optype;
565e47528f3SDavid du Colombier Lladdropt *llao;
566e47528f3SDavid du Colombier Mtuopt *mtuo;
567e47528f3SDavid du Colombier Prefixopt *prfo;
568e47528f3SDavid du Colombier Routeradv *ra;
5690a84db5eSDavid du Colombier static int first = 1;
570e47528f3SDavid du Colombier
571e47528f3SDavid du Colombier ra = (Routeradv*)buf;
572ccaac148SDavid du Colombier // memmove(conf.v6gaddr, ra->src, IPaddrlen);
573e47528f3SDavid du Colombier conf.ttl = ra->cttl;
574e47528f3SDavid du Colombier conf.mflag = (MFMASK & ra->mor);
575e47528f3SDavid du Colombier conf.oflag = (OCMASK & ra->mor);
576e47528f3SDavid du Colombier conf.routerlt = nhgets(ra->routerlt);
577e47528f3SDavid du Colombier conf.reachtime = nhgetl(ra->rchbltime);
578e47528f3SDavid du Colombier conf.rxmitra = nhgetl(ra->rxmtimer);
579e47528f3SDavid du Colombier
5800a84db5eSDavid du Colombier // issueadd6(&conf); /* for conf.v6gaddr? */
581ccaac148SDavid du Colombier if (fprint(conf.cfd, "ra6 recvra 1") < 0)
582ccaac148SDavid du Colombier ralog("write(ra6 recvra 1) failed: %r");
583ccaac148SDavid du Colombier issuebasera6(&conf);
584e47528f3SDavid du Colombier
585e47528f3SDavid du Colombier m = sizeof *ra;
586e47528f3SDavid du Colombier while (pktlen - m > 0) {
587e47528f3SDavid du Colombier optype = buf[m];
588e47528f3SDavid du Colombier switch (optype) {
5898c6ab946SDavid du Colombier case V6nd_srclladdr:
590e47528f3SDavid du Colombier llao = (Lladdropt *)&buf[m];
591e47528f3SDavid du Colombier m += 8 * buf[m+1];
592e47528f3SDavid du Colombier if (llao->len != 1) {
5930a84db5eSDavid du Colombier ralog("recvrahost: illegal len (%d) for source "
5940a84db5eSDavid du Colombier "link layer address option", llao->len);
595e47528f3SDavid du Colombier return;
596e47528f3SDavid du Colombier }
5970a84db5eSDavid du Colombier if (!ISIPV6LINKLOCAL(ra->src)) {
5980a84db5eSDavid du Colombier ralog("recvrahost: non-link-local src addr for "
5990a84db5eSDavid du Colombier "router adv %I", ra->src);
600e47528f3SDavid du Colombier return;
601e47528f3SDavid du Colombier }
602e47528f3SDavid du Colombier
603e47528f3SDavid du Colombier snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
604e47528f3SDavid du Colombier arpfd = open(abuf, OWRITE);
605e47528f3SDavid du Colombier if (arpfd < 0) {
6060a84db5eSDavid du Colombier ralog("recvrahost: couldn't open %s to write: %r",
6070a84db5eSDavid du Colombier abuf);
608e47528f3SDavid du Colombier return;
609e47528f3SDavid du Colombier }
610e47528f3SDavid du Colombier
611e47528f3SDavid du Colombier n = snprint(abuf, sizeof abuf, "add ether %I %E",
612e47528f3SDavid du Colombier ra->src, llao->lladdr);
613e47528f3SDavid du Colombier if (write(arpfd, abuf, n) < n)
614e47528f3SDavid du Colombier ralog("recvrahost: couldn't write to %s/arp",
615e47528f3SDavid du Colombier conf.mpoint);
616e47528f3SDavid du Colombier close(arpfd);
617e47528f3SDavid du Colombier break;
6188c6ab946SDavid du Colombier case V6nd_targlladdr:
6198c6ab946SDavid du Colombier case V6nd_redirhdr:
620e47528f3SDavid du Colombier m += 8 * buf[m+1];
6210a84db5eSDavid du Colombier ralog("ignoring unexpected option type `%s' in Routeradv",
6220a84db5eSDavid du Colombier optname(optype));
623e47528f3SDavid du Colombier break;
6248c6ab946SDavid du Colombier case V6nd_mtu:
625e47528f3SDavid du Colombier mtuo = (Mtuopt*)&buf[m];
626e47528f3SDavid du Colombier m += 8 * mtuo->len;
627e47528f3SDavid du Colombier conf.linkmtu = nhgetl(mtuo->mtu);
628e47528f3SDavid du Colombier break;
6298c6ab946SDavid du Colombier case V6nd_pfxinfo:
630e47528f3SDavid du Colombier prfo = (Prefixopt*)&buf[m];
631e47528f3SDavid du Colombier m += 8 * prfo->len;
632e47528f3SDavid du Colombier if (prfo->len != 4) {
633e47528f3SDavid du Colombier ralog("illegal len (%d) for prefix option",
634e47528f3SDavid du Colombier prfo->len);
635e47528f3SDavid du Colombier return;
636e47528f3SDavid du Colombier }
637e47528f3SDavid du Colombier memmove(conf.v6pref, prfo->pref, IPaddrlen);
638e47528f3SDavid du Colombier conf.prefixlen = prfo->plen;
639e47528f3SDavid du Colombier conf.onlink = ((prfo->lar & OLMASK) != 0);
640e47528f3SDavid du Colombier conf.autoflag = ((prfo->lar & AFMASK) != 0);
641e47528f3SDavid du Colombier conf.validlt = nhgetl(prfo->validlt);
642e47528f3SDavid du Colombier conf.preflt = nhgetl(prfo->preflt);
643ccaac148SDavid du Colombier issueadd6(&conf);
6440a84db5eSDavid du Colombier if (first) {
6450a84db5eSDavid du Colombier first = 0;
6460a84db5eSDavid du Colombier ralog("got initial RA from %I on %s; pfx %I",
6470a84db5eSDavid du Colombier ra->src, conf.dev, prfo->pref);
6480a84db5eSDavid du Colombier }
6490a84db5eSDavid du Colombier break;
65059f7772cSDavid du Colombier default:
651*e961f303SDavid du Colombier if (debug)
65259f7772cSDavid du Colombier ralog("ignoring optype %d in Routeradv from %I",
65359f7772cSDavid du Colombier optype, ra->src);
65459f7772cSDavid du Colombier /* fall through */
6550a84db5eSDavid du Colombier case V6nd_srcaddrs:
6560a84db5eSDavid du Colombier /* netsbd sends this, so quietly ignore it for now */
6570a84db5eSDavid du Colombier m += 8 * buf[m+1];
658e47528f3SDavid du Colombier break;
659e47528f3SDavid du Colombier }
660e47528f3SDavid du Colombier }
661e47528f3SDavid du Colombier }
662e47528f3SDavid du Colombier
663e47528f3SDavid du Colombier /*
6640a84db5eSDavid du Colombier * daemon to receive router advertisements from routers
665e47528f3SDavid du Colombier */
666e47528f3SDavid du Colombier void
recvra6(void)667e47528f3SDavid du Colombier recvra6(void)
668e47528f3SDavid du Colombier {
669e47528f3SDavid du Colombier int fd, cfd, n, sendrscnt, sleepfor;
670e47528f3SDavid du Colombier uchar buf[4096];
671e47528f3SDavid du Colombier
6720a84db5eSDavid du Colombier /* TODO: why not v6allroutersL? */
673e47528f3SDavid du Colombier fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
674e47528f3SDavid du Colombier if (fd < 0)
675e47528f3SDavid du Colombier sysfatal("can't open icmp_ra connection: %r");
676e47528f3SDavid du Colombier
677e47528f3SDavid du Colombier notify(catch);
6785e1edbcaSDavid du Colombier sendrscnt = Maxv6rss;
679e47528f3SDavid du Colombier
680e47528f3SDavid du Colombier switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
681e47528f3SDavid du Colombier case -1:
682e47528f3SDavid du Colombier sysfatal("can't fork: %r");
683e47528f3SDavid du Colombier default:
684e47528f3SDavid du Colombier return;
685e47528f3SDavid du Colombier case 0:
6860a84db5eSDavid du Colombier break;
6870a84db5eSDavid du Colombier }
6880a84db5eSDavid du Colombier
689e47528f3SDavid du Colombier procsetname("recvra6 on %s", conf.dev);
690e47528f3SDavid du Colombier ralog("recvra6 on %s", conf.dev);
6910a84db5eSDavid du Colombier sleepfor = jitter();
692e47528f3SDavid du Colombier for (;;) {
6930a84db5eSDavid du Colombier /*
6940a84db5eSDavid du Colombier * We only get 3 (Maxv6rss) tries, so make sure we
6950a84db5eSDavid du Colombier * wait long enough to be certain that at least one RA
6960a84db5eSDavid du Colombier * will be transmitted.
6970a84db5eSDavid du Colombier */
6980a84db5eSDavid du Colombier if (sleepfor < 7000)
6990a84db5eSDavid du Colombier sleepfor = 7000;
700e47528f3SDavid du Colombier alarm(sleepfor);
701e47528f3SDavid du Colombier n = read(fd, buf, sizeof buf);
702e47528f3SDavid du Colombier alarm(0);
703e47528f3SDavid du Colombier if (n <= 0) {
704e47528f3SDavid du Colombier if (sendrscnt > 0) {
705e47528f3SDavid du Colombier sendrscnt--;
7060a84db5eSDavid du Colombier if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
707e47528f3SDavid du Colombier sendrs(fd);
7085e1edbcaSDavid du Colombier sleepfor = V6rsintvl + nrand(100);
709e47528f3SDavid du Colombier }
710e47528f3SDavid du Colombier if (sendrscnt == 0) {
711e47528f3SDavid du Colombier sendrscnt--;
712e47528f3SDavid du Colombier sleepfor = 0;
7130a84db5eSDavid du Colombier ralog("recvra6: no router advs after %d sols on %s",
7145e1edbcaSDavid du Colombier Maxv6rss, conf.dev);
715e47528f3SDavid du Colombier }
716e47528f3SDavid du Colombier continue;
717e47528f3SDavid du Colombier }
718e47528f3SDavid du Colombier
719e47528f3SDavid du Colombier sleepfor = 0;
7200a84db5eSDavid du Colombier sendrscnt = -1; /* got at least initial ra; no whining */
721e47528f3SDavid du Colombier switch (recvra6on(conf.mpoint, myifc)) {
722e47528f3SDavid du Colombier case IsRouter:
723e47528f3SDavid du Colombier recvrarouter(buf, n);
724e47528f3SDavid du Colombier break;
725e47528f3SDavid du Colombier case IsHostRecv:
726e47528f3SDavid du Colombier recvrahost(buf, n);
727e47528f3SDavid du Colombier break;
728e47528f3SDavid du Colombier case IsHostNoRecv:
7290a84db5eSDavid du Colombier ralog("recvra6: recvra off, quitting on %s", conf.dev);
730e47528f3SDavid du Colombier close(fd);
731e47528f3SDavid du Colombier exits(0);
732e47528f3SDavid du Colombier default:
7330a84db5eSDavid du Colombier ralog("recvra6: unable to read router status on %s",
734e47528f3SDavid du Colombier conf.dev);
735e47528f3SDavid du Colombier break;
736e47528f3SDavid du Colombier }
737e47528f3SDavid du Colombier }
738e47528f3SDavid du Colombier }
739e47528f3SDavid du Colombier
740e47528f3SDavid du Colombier /*
741e47528f3SDavid du Colombier * return -1 -- error, reading/writing some file,
742e47528f3SDavid du Colombier * 0 -- no arp table updates
743e47528f3SDavid du Colombier * 1 -- successful arp table update
744e47528f3SDavid du Colombier */
745e47528f3SDavid du Colombier int
recvrs(uchar * buf,int pktlen,uchar * sol)746e47528f3SDavid du Colombier recvrs(uchar *buf, int pktlen, uchar *sol)
747e47528f3SDavid du Colombier {
748e47528f3SDavid du Colombier int n, optsz, arpfd;
749e47528f3SDavid du Colombier char abuf[256];
750e47528f3SDavid du Colombier Routersol *rs;
751e47528f3SDavid du Colombier Lladdropt *llao;
752e47528f3SDavid du Colombier
753e47528f3SDavid du Colombier rs = (Routersol *)buf;
754e47528f3SDavid du Colombier n = sizeof *rs;
755e47528f3SDavid du Colombier optsz = pktlen - n;
756e47528f3SDavid du Colombier pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
757e47528f3SDavid du Colombier
758e47528f3SDavid du Colombier if (optsz != sizeof *llao)
759e47528f3SDavid du Colombier return 0;
7608c6ab946SDavid du Colombier if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
761e47528f3SDavid du Colombier ralog("rs opt err %s", abuf);
762e47528f3SDavid du Colombier return -1;
763e47528f3SDavid du Colombier }
764e47528f3SDavid du Colombier
765e47528f3SDavid du Colombier ralog("rs recv %s", abuf);
766e47528f3SDavid du Colombier
767e47528f3SDavid du Colombier if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
768e47528f3SDavid du Colombier return 0;
769e47528f3SDavid du Colombier
770e47528f3SDavid du Colombier snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
771e47528f3SDavid du Colombier arpfd = open(abuf, OWRITE);
772e47528f3SDavid du Colombier if (arpfd < 0) {
773e47528f3SDavid du Colombier ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
774e47528f3SDavid du Colombier return -1;
775e47528f3SDavid du Colombier }
776e47528f3SDavid du Colombier
777e47528f3SDavid du Colombier llao = (Lladdropt *)buf[n];
778e47528f3SDavid du Colombier n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
779e47528f3SDavid du Colombier if (write(arpfd, abuf, n) < n) {
780e47528f3SDavid du Colombier ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
781e47528f3SDavid du Colombier close(arpfd);
782e47528f3SDavid du Colombier return -1;
783e47528f3SDavid du Colombier }
784e47528f3SDavid du Colombier
785e47528f3SDavid du Colombier memmove(sol, rs->src, IPaddrlen);
786e47528f3SDavid du Colombier close(arpfd);
787e47528f3SDavid du Colombier return 1;
788e47528f3SDavid du Colombier }
789e47528f3SDavid du Colombier
790e47528f3SDavid du Colombier void
sendra(int fd,uchar * dst,int rlt)791e47528f3SDavid du Colombier sendra(int fd, uchar *dst, int rlt)
792e47528f3SDavid du Colombier {
793e47528f3SDavid du Colombier int pktsz, preflen;
794e47528f3SDavid du Colombier char abuf[1024], tmp[40];
795e47528f3SDavid du Colombier uchar buf[1024], macaddr[6], src[IPaddrlen];
796e47528f3SDavid du Colombier Ipifc *ifc = nil;
797e47528f3SDavid du Colombier Iplifc *lifc, *nlifc;
798e47528f3SDavid du Colombier Lladdropt *llao;
799e47528f3SDavid du Colombier Prefixopt *prfo;
800e47528f3SDavid du Colombier Routeradv *ra;
801e47528f3SDavid du Colombier
802e47528f3SDavid du Colombier memset(buf, 0, sizeof buf);
803e47528f3SDavid du Colombier ra = (Routeradv *)buf;
804e47528f3SDavid du Colombier
805e47528f3SDavid du Colombier myetheraddr(macaddr, conf.dev);
806e47528f3SDavid du Colombier ea2lla(src, macaddr);
807e47528f3SDavid du Colombier memmove(ra->src, src, IPaddrlen);
808e47528f3SDavid du Colombier memmove(ra->dst, dst, IPaddrlen);
809e47528f3SDavid du Colombier ra->type = ICMP6_RA;
810e47528f3SDavid du Colombier ra->cttl = conf.ttl;
811e47528f3SDavid du Colombier
812e47528f3SDavid du Colombier if (conf.mflag > 0)
813e47528f3SDavid du Colombier ra->mor |= MFMASK;
814e47528f3SDavid du Colombier if (conf.oflag > 0)
815e47528f3SDavid du Colombier ra->mor |= OCMASK;
816e47528f3SDavid du Colombier if (rlt > 0)
817e47528f3SDavid du Colombier hnputs(ra->routerlt, conf.routerlt);
818e47528f3SDavid du Colombier else
819e47528f3SDavid du Colombier hnputs(ra->routerlt, 0);
820e47528f3SDavid du Colombier hnputl(ra->rchbltime, conf.reachtime);
821e47528f3SDavid du Colombier hnputl(ra->rxmtimer, conf.rxmitra);
822e47528f3SDavid du Colombier
823e47528f3SDavid du Colombier pktsz = sizeof *ra;
824e47528f3SDavid du Colombier
825e47528f3SDavid du Colombier /* include all global unicast prefixes on interface in prefix options */
826e47528f3SDavid du Colombier ifc = readipifc(conf.mpoint, ifc, myifc);
827e47528f3SDavid du Colombier for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
828e47528f3SDavid du Colombier nlifc = lifc->next;
829e47528f3SDavid du Colombier prfo = (Prefixopt *)(buf + pktsz);
8305e1edbcaSDavid du Colombier /* global unicast address? */
8315e1edbcaSDavid du Colombier if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
8325e1edbcaSDavid du Colombier memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
8330a84db5eSDavid du Colombier memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
8340a84db5eSDavid du Colombier !isv4(lifc->ip)) {
835e47528f3SDavid du Colombier memmove(prfo->pref, lifc->net, IPaddrlen);
836e47528f3SDavid du Colombier
837e47528f3SDavid du Colombier /* hack to find prefix length */
838e47528f3SDavid du Colombier snprint(tmp, sizeof tmp, "%M", lifc->mask);
839e47528f3SDavid du Colombier preflen = atoi(&tmp[1]);
840e47528f3SDavid du Colombier prfo->plen = preflen & 0xff;
841e47528f3SDavid du Colombier if (prfo->plen == 0)
842e47528f3SDavid du Colombier continue;
843e47528f3SDavid du Colombier
8448c6ab946SDavid du Colombier prfo->type = V6nd_pfxinfo;
845e47528f3SDavid du Colombier prfo->len = 4;
846e47528f3SDavid du Colombier prfo->lar = AFMASK;
847e47528f3SDavid du Colombier hnputl(prfo->validlt, lifc->validlt);
848e47528f3SDavid du Colombier hnputl(prfo->preflt, lifc->preflt);
849e47528f3SDavid du Colombier pktsz += sizeof *prfo;
850e47528f3SDavid du Colombier }
851e47528f3SDavid du Colombier }
852e47528f3SDavid du Colombier /*
853e47528f3SDavid du Colombier * include link layer address (mac address for now) in
854e47528f3SDavid du Colombier * link layer address option
855e47528f3SDavid du Colombier */
856e47528f3SDavid du Colombier llao = (Lladdropt *)(buf + pktsz);
8578c6ab946SDavid du Colombier llao->type = V6nd_srclladdr;
858e47528f3SDavid du Colombier llao->len = 1;
859e47528f3SDavid du Colombier memmove(llao->lladdr, macaddr, sizeof macaddr);
860e47528f3SDavid du Colombier pktsz += sizeof *llao;
861e47528f3SDavid du Colombier
862e47528f3SDavid du Colombier pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
863e47528f3SDavid du Colombier if(write(fd, buf, pktsz) < pktsz)
8640a84db5eSDavid du Colombier ralog("sendra fail %s: %r", abuf);
8650a84db5eSDavid du Colombier else if (debug)
8660a84db5eSDavid du Colombier ralog("sendra succ %s", abuf);
867e47528f3SDavid du Colombier }
868e47528f3SDavid du Colombier
869e47528f3SDavid du Colombier /*
8700a84db5eSDavid du Colombier * daemon to send router advertisements to hosts
871e47528f3SDavid du Colombier */
872e47528f3SDavid du Colombier void
sendra6(void)873e47528f3SDavid du Colombier sendra6(void)
874e47528f3SDavid du Colombier {
875e47528f3SDavid du Colombier int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
8760a84db5eSDavid du Colombier long lastra, now;
877e47528f3SDavid du Colombier uchar buf[4096], dst[IPaddrlen];
878e47528f3SDavid du Colombier Ipifc *ifc = nil;
879e47528f3SDavid du Colombier
880e47528f3SDavid du Colombier fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
881e47528f3SDavid du Colombier if (fd < 0)
882e47528f3SDavid du Colombier sysfatal("can't open icmp_rs connection: %r");
883e47528f3SDavid du Colombier
884e47528f3SDavid du Colombier notify(catch);
8855e1edbcaSDavid du Colombier sendracnt = Maxv6initras;
8865e1edbcaSDavid du Colombier nquitmsgs = Maxv6finalras;
887e47528f3SDavid du Colombier
888e47528f3SDavid du Colombier switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
889e47528f3SDavid du Colombier case -1:
890e47528f3SDavid du Colombier sysfatal("can't fork: %r");
891e47528f3SDavid du Colombier default:
892e47528f3SDavid du Colombier return;
893e47528f3SDavid du Colombier case 0:
8940a84db5eSDavid du Colombier break;
8950a84db5eSDavid du Colombier }
8960a84db5eSDavid du Colombier
897e47528f3SDavid du Colombier procsetname("sendra6 on %s", conf.dev);
898e47528f3SDavid du Colombier ralog("sendra6 on %s", conf.dev);
8990a84db5eSDavid du Colombier sleepfor = jitter();
900e47528f3SDavid du Colombier for (;;) {
901e47528f3SDavid du Colombier lastra = time(0);
9020a84db5eSDavid du Colombier if (sleepfor < 0)
9030a84db5eSDavid du Colombier sleepfor = 0;
904e47528f3SDavid du Colombier alarm(sleepfor);
905e47528f3SDavid du Colombier n = read(fd, buf, sizeof buf);
906e47528f3SDavid du Colombier alarm(0);
907e47528f3SDavid du Colombier
908e47528f3SDavid du Colombier ifc = readipifc(conf.mpoint, ifc, myifc);
909e47528f3SDavid du Colombier if (ifc == nil) {
9100a84db5eSDavid du Colombier ralog("sendra6: can't read router params on %s",
911e47528f3SDavid du Colombier conf.mpoint);
912e47528f3SDavid du Colombier continue;
913e47528f3SDavid du Colombier }
914e47528f3SDavid du Colombier
915e47528f3SDavid du Colombier if (ifc->sendra6 <= 0)
916e47528f3SDavid du Colombier if (nquitmsgs > 0) {
917e47528f3SDavid du Colombier sendra(fd, v6allnodesL, 0);
918e47528f3SDavid du Colombier nquitmsgs--;
9190a84db5eSDavid du Colombier sleepfor = Minv6interradelay + jitter();
920e47528f3SDavid du Colombier continue;
921e47528f3SDavid du Colombier } else {
9220a84db5eSDavid du Colombier ralog("sendra6: sendra off, quitting on %s",
9230a84db5eSDavid du Colombier conf.dev);
924e47528f3SDavid du Colombier exits(0);
925e47528f3SDavid du Colombier }
926e47528f3SDavid du Colombier
9275e1edbcaSDavid du Colombier nquitmsgs = Maxv6finalras;
928e47528f3SDavid du Colombier
9298c6ab946SDavid du Colombier if (n <= 0) { /* no RS */
930e47528f3SDavid du Colombier if (sendracnt > 0)
931e47528f3SDavid du Colombier sendracnt--;
9328c6ab946SDavid du Colombier } else { /* respond to RS */
933e47528f3SDavid du Colombier dstknown = recvrs(buf, n, dst);
9340a84db5eSDavid du Colombier now = time(0);
935e47528f3SDavid du Colombier
9360a84db5eSDavid du Colombier if (now - lastra < Minv6interradelay) {
937e47528f3SDavid du Colombier /* too close, skip */
9380a84db5eSDavid du Colombier sleepfor = lastra + Minv6interradelay +
9390a84db5eSDavid du Colombier jitter() - now;
940e47528f3SDavid du Colombier continue;
941e47528f3SDavid du Colombier }
9420a84db5eSDavid du Colombier sleep(jitter());
943e47528f3SDavid du Colombier }
9440a84db5eSDavid du Colombier sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
945e47528f3SDavid du Colombier if (dstknown > 0)
946e47528f3SDavid du Colombier sendra(fd, dst, 1);
947e47528f3SDavid du Colombier else
948e47528f3SDavid du Colombier sendra(fd, v6allnodesL, 1);
949e47528f3SDavid du Colombier }
950e47528f3SDavid du Colombier }
951e47528f3SDavid du Colombier
952e47528f3SDavid du Colombier void
startra6(void)953ccaac148SDavid du Colombier startra6(void)
954e47528f3SDavid du Colombier {
955e47528f3SDavid du Colombier static char routeon[] = "iprouting 1";
956e47528f3SDavid du Colombier
957e47528f3SDavid du Colombier if (conf.recvra > 0)
958e47528f3SDavid du Colombier recvra6();
959e47528f3SDavid du Colombier
960e47528f3SDavid du Colombier if (conf.sendra > 0) {
961e47528f3SDavid du Colombier if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
9628c6ab946SDavid du Colombier warning("write (iprouting 1) failed: %r");
963e47528f3SDavid du Colombier return;
964e47528f3SDavid du Colombier }
965e47528f3SDavid du Colombier sendra6();
966e47528f3SDavid du Colombier if (conf.recvra <= 0)
967e47528f3SDavid du Colombier recvra6();
968e47528f3SDavid du Colombier }
969e47528f3SDavid du Colombier }
970e47528f3SDavid du Colombier
971e47528f3SDavid du Colombier void
doipv6(int what)972ccaac148SDavid du Colombier doipv6(int what)
973e47528f3SDavid du Colombier {
974e47528f3SDavid du Colombier nip = nipifcs(conf.mpoint);
975e47528f3SDavid du Colombier if(!noconfig){
976e47528f3SDavid du Colombier lookforip(conf.mpoint);
977e47528f3SDavid du Colombier controldevice();
978e47528f3SDavid du Colombier binddevice();
979e47528f3SDavid du Colombier }
980e47528f3SDavid du Colombier
981e47528f3SDavid du Colombier switch (what) {
982e47528f3SDavid du Colombier default:
9838c6ab946SDavid du Colombier sysfatal("unknown IPv6 verb");
984e47528f3SDavid du Colombier case Vaddpref6:
985ccaac148SDavid du Colombier issueadd6(&conf);
986e47528f3SDavid du Colombier break;
987e47528f3SDavid du Colombier case Vra6:
988ccaac148SDavid du Colombier issuebasera6(&conf);
989ccaac148SDavid du Colombier issuerara6(&conf);
9900a84db5eSDavid du Colombier dolog = 1;
991ccaac148SDavid du Colombier startra6();
992e47528f3SDavid du Colombier break;
993e47528f3SDavid du Colombier }
994e47528f3SDavid du Colombier }
995