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 {
388*fafe75d5SDavid du Colombier int dupfound = 0, n, nf;
389*fafe75d5SDavid du Colombier char *p, *fields[4];
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;
436*fafe75d5SDavid du Colombier nf = tokenize(p, fields, nelem(fields));
437*fafe75d5SDavid du Colombier if(nf >= 4 && cistrcmp(fields[2], buf) == 0) {
4388c6ab946SDavid du Colombier warning("found dup entry in arp cache");
439e47528f3SDavid du Colombier dupfound = 1;
440e47528f3SDavid du Colombier break;
441e47528f3SDavid du Colombier }
442e47528f3SDavid du Colombier }
443e47528f3SDavid du Colombier Bterm(bp);
444e47528f3SDavid du Colombier
445e47528f3SDavid du Colombier if (dupfound)
446e47528f3SDavid du Colombier doremove();
447e47528f3SDavid du Colombier else {
448e47528f3SDavid du Colombier n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
449e47528f3SDavid du Colombier if(validip(conf.raddr)){
450e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
451e47528f3SDavid du Colombier if(conf.mtu != 0)
452e47528f3SDavid du Colombier n += snprint(buf+n, sizeof buf-n, " %d",
453e47528f3SDavid du Colombier conf.mtu);
454e47528f3SDavid du Colombier }
455e47528f3SDavid du Colombier write(conf.cfd, buf, n);
456e47528f3SDavid du Colombier }
457e47528f3SDavid du Colombier return 0;
458e47528f3SDavid du Colombier }
459e47528f3SDavid du Colombier
460e47528f3SDavid du Colombier static int
recvra6on(char * net,int conn)461e47528f3SDavid du Colombier recvra6on(char *net, int conn)
462e47528f3SDavid du Colombier {
463e47528f3SDavid du Colombier Ipifc* ifc;
464e47528f3SDavid du Colombier
465e47528f3SDavid du Colombier ifc = readipifc(net, nil, conn);
466e47528f3SDavid du Colombier if (ifc == nil)
467e47528f3SDavid du Colombier return 0;
468e47528f3SDavid du Colombier else if (ifc->sendra6 > 0)
469e47528f3SDavid du Colombier return IsRouter;
470e47528f3SDavid du Colombier else if (ifc->recvra6 > 0)
471e47528f3SDavid du Colombier return IsHostRecv;
472e47528f3SDavid du Colombier else
473e47528f3SDavid du Colombier return IsHostNoRecv;
474e47528f3SDavid du Colombier }
475e47528f3SDavid du Colombier
4760a84db5eSDavid du Colombier /* send icmpv6 router solicitation to multicast address for all routers */
477e47528f3SDavid du Colombier static void
sendrs(int fd)478e47528f3SDavid du Colombier sendrs(int fd)
479e47528f3SDavid du Colombier {
480e47528f3SDavid du Colombier Routersol *rs;
481e47528f3SDavid du Colombier uchar buff[sizeof *rs];
482e47528f3SDavid du Colombier
483e47528f3SDavid du Colombier memset(buff, 0, sizeof buff);
484e47528f3SDavid du Colombier rs = (Routersol *)buff;
485e47528f3SDavid du Colombier memmove(rs->dst, v6allroutersL, IPaddrlen);
486e47528f3SDavid du Colombier memmove(rs->src, v6Unspecified, IPaddrlen);
487e47528f3SDavid du Colombier rs->type = ICMP6_RS;
488e47528f3SDavid du Colombier
489e47528f3SDavid du Colombier if(write(fd, rs, sizeof buff) < sizeof buff)
490e47528f3SDavid du Colombier ralog("sendrs: write failed, pkt size %d", sizeof buff);
4910a84db5eSDavid du Colombier else
4920a84db5eSDavid du Colombier ralog("sendrs: sent solicitation to %I from %I on %s",
4930a84db5eSDavid du Colombier rs->dst, rs->src, conf.dev);
494e47528f3SDavid du Colombier }
495e47528f3SDavid du Colombier
496e47528f3SDavid du Colombier /*
497e47528f3SDavid du Colombier * a router receiving a router adv from another
498e47528f3SDavid du Colombier * router calls this; it is basically supposed to
499e47528f3SDavid du Colombier * log the information in the ra and raise a flag
500e47528f3SDavid du Colombier * if any parameter value is different from its configured values.
501e47528f3SDavid du Colombier *
502e47528f3SDavid du Colombier * doing nothing for now since I don't know where to log this yet.
503e47528f3SDavid du Colombier */
504e47528f3SDavid du Colombier static void
recvrarouter(uchar buf[],int pktlen)505e47528f3SDavid du Colombier recvrarouter(uchar buf[], int pktlen)
506e47528f3SDavid du Colombier {
507e47528f3SDavid du Colombier USED(buf, pktlen);
508e47528f3SDavid du Colombier ralog("i am a router and got a router advert");
509e47528f3SDavid du Colombier }
510e47528f3SDavid du Colombier
511e47528f3SDavid du Colombier /* host receiving a router advertisement calls this */
512e47528f3SDavid du Colombier
513e47528f3SDavid du Colombier static void
ewrite(int fd,char * str)514ccaac148SDavid du Colombier ewrite(int fd, char *str)
515ccaac148SDavid du Colombier {
516ccaac148SDavid du Colombier int n;
517ccaac148SDavid du Colombier
518ccaac148SDavid du Colombier n = strlen(str);
519ccaac148SDavid du Colombier if (write(fd, str, n) != n)
520ccaac148SDavid du Colombier ralog("write(%s) failed: %r", str);
521ccaac148SDavid du Colombier }
522ccaac148SDavid du Colombier
523ccaac148SDavid du Colombier static void
issuebasera6(Conf * cf)524ccaac148SDavid du Colombier issuebasera6(Conf *cf)
525ccaac148SDavid du Colombier {
526ccaac148SDavid du Colombier char *cfg;
527ccaac148SDavid du Colombier
528ccaac148SDavid du Colombier cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
529ccaac148SDavid du Colombier "ttl %d routerlt %d",
530ccaac148SDavid du Colombier cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
531ccaac148SDavid du Colombier cf->ttl, cf->routerlt);
532ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
533ccaac148SDavid du Colombier free(cfg);
534ccaac148SDavid du Colombier }
535ccaac148SDavid du Colombier
536ccaac148SDavid du Colombier static void
issuerara6(Conf * cf)537ccaac148SDavid du Colombier issuerara6(Conf *cf)
538ccaac148SDavid du Colombier {
539ccaac148SDavid du Colombier char *cfg;
540ccaac148SDavid du Colombier
541ccaac148SDavid du Colombier cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
542ccaac148SDavid du Colombier "linkmtu %d",
543ccaac148SDavid du Colombier cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
544ccaac148SDavid du Colombier cf->linkmtu);
545ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
546ccaac148SDavid du Colombier free(cfg);
547ccaac148SDavid du Colombier }
548ccaac148SDavid du Colombier
549ccaac148SDavid du Colombier static void
issueadd6(Conf * cf)550ccaac148SDavid du Colombier issueadd6(Conf *cf)
551ccaac148SDavid du Colombier {
552ccaac148SDavid du Colombier char *cfg;
553ccaac148SDavid du Colombier
554ccaac148SDavid du Colombier cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
555ccaac148SDavid du Colombier cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
556ccaac148SDavid du Colombier ewrite(cf->cfd, cfg);
557ccaac148SDavid du Colombier free(cfg);
558ccaac148SDavid du Colombier }
559ccaac148SDavid du Colombier
560ccaac148SDavid du Colombier static void
recvrahost(uchar buf[],int pktlen)561e47528f3SDavid du Colombier recvrahost(uchar buf[], int pktlen)
562e47528f3SDavid du Colombier {
563e47528f3SDavid du Colombier int arpfd, m, n;
564ccaac148SDavid du Colombier char abuf[100];
565e47528f3SDavid du Colombier uchar optype;
566e47528f3SDavid du Colombier Lladdropt *llao;
567e47528f3SDavid du Colombier Mtuopt *mtuo;
568e47528f3SDavid du Colombier Prefixopt *prfo;
569e47528f3SDavid du Colombier Routeradv *ra;
5700a84db5eSDavid du Colombier static int first = 1;
571e47528f3SDavid du Colombier
572e47528f3SDavid du Colombier ra = (Routeradv*)buf;
573ccaac148SDavid du Colombier // memmove(conf.v6gaddr, ra->src, IPaddrlen);
574e47528f3SDavid du Colombier conf.ttl = ra->cttl;
575e47528f3SDavid du Colombier conf.mflag = (MFMASK & ra->mor);
576e47528f3SDavid du Colombier conf.oflag = (OCMASK & ra->mor);
577e47528f3SDavid du Colombier conf.routerlt = nhgets(ra->routerlt);
578e47528f3SDavid du Colombier conf.reachtime = nhgetl(ra->rchbltime);
579e47528f3SDavid du Colombier conf.rxmitra = nhgetl(ra->rxmtimer);
580e47528f3SDavid du Colombier
5810a84db5eSDavid du Colombier // issueadd6(&conf); /* for conf.v6gaddr? */
582ccaac148SDavid du Colombier if (fprint(conf.cfd, "ra6 recvra 1") < 0)
583ccaac148SDavid du Colombier ralog("write(ra6 recvra 1) failed: %r");
584ccaac148SDavid du Colombier issuebasera6(&conf);
585e47528f3SDavid du Colombier
586e47528f3SDavid du Colombier m = sizeof *ra;
587e47528f3SDavid du Colombier while (pktlen - m > 0) {
588e47528f3SDavid du Colombier optype = buf[m];
589e47528f3SDavid du Colombier switch (optype) {
5908c6ab946SDavid du Colombier case V6nd_srclladdr:
591e47528f3SDavid du Colombier llao = (Lladdropt *)&buf[m];
592e47528f3SDavid du Colombier m += 8 * buf[m+1];
593e47528f3SDavid du Colombier if (llao->len != 1) {
5940a84db5eSDavid du Colombier ralog("recvrahost: illegal len (%d) for source "
5950a84db5eSDavid du Colombier "link layer address option", llao->len);
596e47528f3SDavid du Colombier return;
597e47528f3SDavid du Colombier }
5980a84db5eSDavid du Colombier if (!ISIPV6LINKLOCAL(ra->src)) {
5990a84db5eSDavid du Colombier ralog("recvrahost: non-link-local src addr for "
6000a84db5eSDavid du Colombier "router adv %I", ra->src);
601e47528f3SDavid du Colombier return;
602e47528f3SDavid du Colombier }
603e47528f3SDavid du Colombier
604e47528f3SDavid du Colombier snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
605e47528f3SDavid du Colombier arpfd = open(abuf, OWRITE);
606e47528f3SDavid du Colombier if (arpfd < 0) {
6070a84db5eSDavid du Colombier ralog("recvrahost: couldn't open %s to write: %r",
6080a84db5eSDavid du Colombier abuf);
609e47528f3SDavid du Colombier return;
610e47528f3SDavid du Colombier }
611e47528f3SDavid du Colombier
612e47528f3SDavid du Colombier n = snprint(abuf, sizeof abuf, "add ether %I %E",
613e47528f3SDavid du Colombier ra->src, llao->lladdr);
614e47528f3SDavid du Colombier if (write(arpfd, abuf, n) < n)
615e47528f3SDavid du Colombier ralog("recvrahost: couldn't write to %s/arp",
616e47528f3SDavid du Colombier conf.mpoint);
617e47528f3SDavid du Colombier close(arpfd);
618e47528f3SDavid du Colombier break;
6198c6ab946SDavid du Colombier case V6nd_targlladdr:
6208c6ab946SDavid du Colombier case V6nd_redirhdr:
621e47528f3SDavid du Colombier m += 8 * buf[m+1];
6220a84db5eSDavid du Colombier ralog("ignoring unexpected option type `%s' in Routeradv",
6230a84db5eSDavid du Colombier optname(optype));
624e47528f3SDavid du Colombier break;
6258c6ab946SDavid du Colombier case V6nd_mtu:
626e47528f3SDavid du Colombier mtuo = (Mtuopt*)&buf[m];
627e47528f3SDavid du Colombier m += 8 * mtuo->len;
628e47528f3SDavid du Colombier conf.linkmtu = nhgetl(mtuo->mtu);
629e47528f3SDavid du Colombier break;
6308c6ab946SDavid du Colombier case V6nd_pfxinfo:
631e47528f3SDavid du Colombier prfo = (Prefixopt*)&buf[m];
632e47528f3SDavid du Colombier m += 8 * prfo->len;
633e47528f3SDavid du Colombier if (prfo->len != 4) {
634e47528f3SDavid du Colombier ralog("illegal len (%d) for prefix option",
635e47528f3SDavid du Colombier prfo->len);
636e47528f3SDavid du Colombier return;
637e47528f3SDavid du Colombier }
638e47528f3SDavid du Colombier memmove(conf.v6pref, prfo->pref, IPaddrlen);
639e47528f3SDavid du Colombier conf.prefixlen = prfo->plen;
640e47528f3SDavid du Colombier conf.onlink = ((prfo->lar & OLMASK) != 0);
641e47528f3SDavid du Colombier conf.autoflag = ((prfo->lar & AFMASK) != 0);
642e47528f3SDavid du Colombier conf.validlt = nhgetl(prfo->validlt);
643e47528f3SDavid du Colombier conf.preflt = nhgetl(prfo->preflt);
644ccaac148SDavid du Colombier issueadd6(&conf);
6450a84db5eSDavid du Colombier if (first) {
6460a84db5eSDavid du Colombier first = 0;
6470a84db5eSDavid du Colombier ralog("got initial RA from %I on %s; pfx %I",
6480a84db5eSDavid du Colombier ra->src, conf.dev, prfo->pref);
6490a84db5eSDavid du Colombier }
6500a84db5eSDavid du Colombier break;
65159f7772cSDavid du Colombier default:
652e961f303SDavid du Colombier if (debug)
65359f7772cSDavid du Colombier ralog("ignoring optype %d in Routeradv from %I",
65459f7772cSDavid du Colombier optype, ra->src);
65559f7772cSDavid du Colombier /* fall through */
6560a84db5eSDavid du Colombier case V6nd_srcaddrs:
6570a84db5eSDavid du Colombier /* netsbd sends this, so quietly ignore it for now */
6580a84db5eSDavid du Colombier m += 8 * buf[m+1];
659e47528f3SDavid du Colombier break;
660e47528f3SDavid du Colombier }
661e47528f3SDavid du Colombier }
662e47528f3SDavid du Colombier }
663e47528f3SDavid du Colombier
664e47528f3SDavid du Colombier /*
6650a84db5eSDavid du Colombier * daemon to receive router advertisements from routers
666e47528f3SDavid du Colombier */
667e47528f3SDavid du Colombier void
recvra6(void)668e47528f3SDavid du Colombier recvra6(void)
669e47528f3SDavid du Colombier {
670e47528f3SDavid du Colombier int fd, cfd, n, sendrscnt, sleepfor;
671e47528f3SDavid du Colombier uchar buf[4096];
672e47528f3SDavid du Colombier
6730a84db5eSDavid du Colombier /* TODO: why not v6allroutersL? */
674e47528f3SDavid du Colombier fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
675e47528f3SDavid du Colombier if (fd < 0)
676e47528f3SDavid du Colombier sysfatal("can't open icmp_ra connection: %r");
677e47528f3SDavid du Colombier
678e47528f3SDavid du Colombier notify(catch);
6795e1edbcaSDavid du Colombier sendrscnt = Maxv6rss;
680e47528f3SDavid du Colombier
681e47528f3SDavid du Colombier switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
682e47528f3SDavid du Colombier case -1:
683e47528f3SDavid du Colombier sysfatal("can't fork: %r");
684e47528f3SDavid du Colombier default:
685e47528f3SDavid du Colombier return;
686e47528f3SDavid du Colombier case 0:
6870a84db5eSDavid du Colombier break;
6880a84db5eSDavid du Colombier }
6890a84db5eSDavid du Colombier
690e47528f3SDavid du Colombier procsetname("recvra6 on %s", conf.dev);
691e47528f3SDavid du Colombier ralog("recvra6 on %s", conf.dev);
6920a84db5eSDavid du Colombier sleepfor = jitter();
693e47528f3SDavid du Colombier for (;;) {
6940a84db5eSDavid du Colombier /*
6950a84db5eSDavid du Colombier * We only get 3 (Maxv6rss) tries, so make sure we
6960a84db5eSDavid du Colombier * wait long enough to be certain that at least one RA
6970a84db5eSDavid du Colombier * will be transmitted.
6980a84db5eSDavid du Colombier */
6990a84db5eSDavid du Colombier if (sleepfor < 7000)
7000a84db5eSDavid du Colombier sleepfor = 7000;
701e47528f3SDavid du Colombier alarm(sleepfor);
702e47528f3SDavid du Colombier n = read(fd, buf, sizeof buf);
703e47528f3SDavid du Colombier alarm(0);
704e47528f3SDavid du Colombier if (n <= 0) {
705e47528f3SDavid du Colombier if (sendrscnt > 0) {
706e47528f3SDavid du Colombier sendrscnt--;
7070a84db5eSDavid du Colombier if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
708e47528f3SDavid du Colombier sendrs(fd);
7095e1edbcaSDavid du Colombier sleepfor = V6rsintvl + nrand(100);
710e47528f3SDavid du Colombier }
711e47528f3SDavid du Colombier if (sendrscnt == 0) {
712e47528f3SDavid du Colombier sendrscnt--;
713e47528f3SDavid du Colombier sleepfor = 0;
7140a84db5eSDavid du Colombier ralog("recvra6: no router advs after %d sols on %s",
7155e1edbcaSDavid du Colombier Maxv6rss, conf.dev);
716e47528f3SDavid du Colombier }
717e47528f3SDavid du Colombier continue;
718e47528f3SDavid du Colombier }
719e47528f3SDavid du Colombier
720e47528f3SDavid du Colombier sleepfor = 0;
7210a84db5eSDavid du Colombier sendrscnt = -1; /* got at least initial ra; no whining */
722e47528f3SDavid du Colombier switch (recvra6on(conf.mpoint, myifc)) {
723e47528f3SDavid du Colombier case IsRouter:
724e47528f3SDavid du Colombier recvrarouter(buf, n);
725e47528f3SDavid du Colombier break;
726e47528f3SDavid du Colombier case IsHostRecv:
727e47528f3SDavid du Colombier recvrahost(buf, n);
728e47528f3SDavid du Colombier break;
729e47528f3SDavid du Colombier case IsHostNoRecv:
7300a84db5eSDavid du Colombier ralog("recvra6: recvra off, quitting on %s", conf.dev);
731e47528f3SDavid du Colombier close(fd);
732e47528f3SDavid du Colombier exits(0);
733e47528f3SDavid du Colombier default:
7340a84db5eSDavid du Colombier ralog("recvra6: unable to read router status on %s",
735e47528f3SDavid du Colombier conf.dev);
736e47528f3SDavid du Colombier break;
737e47528f3SDavid du Colombier }
738e47528f3SDavid du Colombier }
739e47528f3SDavid du Colombier }
740e47528f3SDavid du Colombier
741e47528f3SDavid du Colombier /*
742e47528f3SDavid du Colombier * return -1 -- error, reading/writing some file,
743e47528f3SDavid du Colombier * 0 -- no arp table updates
744e47528f3SDavid du Colombier * 1 -- successful arp table update
745e47528f3SDavid du Colombier */
746e47528f3SDavid du Colombier int
recvrs(uchar * buf,int pktlen,uchar * sol)747e47528f3SDavid du Colombier recvrs(uchar *buf, int pktlen, uchar *sol)
748e47528f3SDavid du Colombier {
749e47528f3SDavid du Colombier int n, optsz, arpfd;
750e47528f3SDavid du Colombier char abuf[256];
751e47528f3SDavid du Colombier Routersol *rs;
752e47528f3SDavid du Colombier Lladdropt *llao;
753e47528f3SDavid du Colombier
754e47528f3SDavid du Colombier rs = (Routersol *)buf;
755e47528f3SDavid du Colombier n = sizeof *rs;
756e47528f3SDavid du Colombier optsz = pktlen - n;
757e47528f3SDavid du Colombier pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
758e47528f3SDavid du Colombier
759e47528f3SDavid du Colombier if (optsz != sizeof *llao)
760e47528f3SDavid du Colombier return 0;
7618c6ab946SDavid du Colombier if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
762e47528f3SDavid du Colombier ralog("rs opt err %s", abuf);
763e47528f3SDavid du Colombier return -1;
764e47528f3SDavid du Colombier }
765e47528f3SDavid du Colombier
766e47528f3SDavid du Colombier ralog("rs recv %s", abuf);
767e47528f3SDavid du Colombier
768e47528f3SDavid du Colombier if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
769e47528f3SDavid du Colombier return 0;
770e47528f3SDavid du Colombier
771e47528f3SDavid du Colombier snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
772e47528f3SDavid du Colombier arpfd = open(abuf, OWRITE);
773e47528f3SDavid du Colombier if (arpfd < 0) {
774e47528f3SDavid du Colombier ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
775e47528f3SDavid du Colombier return -1;
776e47528f3SDavid du Colombier }
777e47528f3SDavid du Colombier
778e47528f3SDavid du Colombier llao = (Lladdropt *)buf[n];
779e47528f3SDavid du Colombier n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
780e47528f3SDavid du Colombier if (write(arpfd, abuf, n) < n) {
781e47528f3SDavid du Colombier ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
782e47528f3SDavid du Colombier close(arpfd);
783e47528f3SDavid du Colombier return -1;
784e47528f3SDavid du Colombier }
785e47528f3SDavid du Colombier
786e47528f3SDavid du Colombier memmove(sol, rs->src, IPaddrlen);
787e47528f3SDavid du Colombier close(arpfd);
788e47528f3SDavid du Colombier return 1;
789e47528f3SDavid du Colombier }
790e47528f3SDavid du Colombier
791e47528f3SDavid du Colombier void
sendra(int fd,uchar * dst,int rlt)792e47528f3SDavid du Colombier sendra(int fd, uchar *dst, int rlt)
793e47528f3SDavid du Colombier {
794e47528f3SDavid du Colombier int pktsz, preflen;
795e47528f3SDavid du Colombier char abuf[1024], tmp[40];
796e47528f3SDavid du Colombier uchar buf[1024], macaddr[6], src[IPaddrlen];
797e47528f3SDavid du Colombier Ipifc *ifc = nil;
798e47528f3SDavid du Colombier Iplifc *lifc, *nlifc;
799e47528f3SDavid du Colombier Lladdropt *llao;
800e47528f3SDavid du Colombier Prefixopt *prfo;
801e47528f3SDavid du Colombier Routeradv *ra;
802e47528f3SDavid du Colombier
803e47528f3SDavid du Colombier memset(buf, 0, sizeof buf);
804e47528f3SDavid du Colombier ra = (Routeradv *)buf;
805e47528f3SDavid du Colombier
806e47528f3SDavid du Colombier myetheraddr(macaddr, conf.dev);
807e47528f3SDavid du Colombier ea2lla(src, macaddr);
808e47528f3SDavid du Colombier memmove(ra->src, src, IPaddrlen);
809e47528f3SDavid du Colombier memmove(ra->dst, dst, IPaddrlen);
810e47528f3SDavid du Colombier ra->type = ICMP6_RA;
811e47528f3SDavid du Colombier ra->cttl = conf.ttl;
812e47528f3SDavid du Colombier
813e47528f3SDavid du Colombier if (conf.mflag > 0)
814e47528f3SDavid du Colombier ra->mor |= MFMASK;
815e47528f3SDavid du Colombier if (conf.oflag > 0)
816e47528f3SDavid du Colombier ra->mor |= OCMASK;
817e47528f3SDavid du Colombier if (rlt > 0)
818e47528f3SDavid du Colombier hnputs(ra->routerlt, conf.routerlt);
819e47528f3SDavid du Colombier else
820e47528f3SDavid du Colombier hnputs(ra->routerlt, 0);
821e47528f3SDavid du Colombier hnputl(ra->rchbltime, conf.reachtime);
822e47528f3SDavid du Colombier hnputl(ra->rxmtimer, conf.rxmitra);
823e47528f3SDavid du Colombier
824e47528f3SDavid du Colombier pktsz = sizeof *ra;
825e47528f3SDavid du Colombier
826e47528f3SDavid du Colombier /* include all global unicast prefixes on interface in prefix options */
827e47528f3SDavid du Colombier ifc = readipifc(conf.mpoint, ifc, myifc);
828e47528f3SDavid du Colombier for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
829e47528f3SDavid du Colombier nlifc = lifc->next;
830e47528f3SDavid du Colombier prfo = (Prefixopt *)(buf + pktsz);
8315e1edbcaSDavid du Colombier /* global unicast address? */
8325e1edbcaSDavid du Colombier if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
8335e1edbcaSDavid du Colombier memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
8340a84db5eSDavid du Colombier memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
8350a84db5eSDavid du Colombier !isv4(lifc->ip)) {
836e47528f3SDavid du Colombier memmove(prfo->pref, lifc->net, IPaddrlen);
837e47528f3SDavid du Colombier
838e47528f3SDavid du Colombier /* hack to find prefix length */
839e47528f3SDavid du Colombier snprint(tmp, sizeof tmp, "%M", lifc->mask);
840e47528f3SDavid du Colombier preflen = atoi(&tmp[1]);
841e47528f3SDavid du Colombier prfo->plen = preflen & 0xff;
842e47528f3SDavid du Colombier if (prfo->plen == 0)
843e47528f3SDavid du Colombier continue;
844e47528f3SDavid du Colombier
8458c6ab946SDavid du Colombier prfo->type = V6nd_pfxinfo;
846e47528f3SDavid du Colombier prfo->len = 4;
847e47528f3SDavid du Colombier prfo->lar = AFMASK;
848e47528f3SDavid du Colombier hnputl(prfo->validlt, lifc->validlt);
849e47528f3SDavid du Colombier hnputl(prfo->preflt, lifc->preflt);
850e47528f3SDavid du Colombier pktsz += sizeof *prfo;
851e47528f3SDavid du Colombier }
852e47528f3SDavid du Colombier }
853e47528f3SDavid du Colombier /*
854e47528f3SDavid du Colombier * include link layer address (mac address for now) in
855e47528f3SDavid du Colombier * link layer address option
856e47528f3SDavid du Colombier */
857e47528f3SDavid du Colombier llao = (Lladdropt *)(buf + pktsz);
8588c6ab946SDavid du Colombier llao->type = V6nd_srclladdr;
859e47528f3SDavid du Colombier llao->len = 1;
860e47528f3SDavid du Colombier memmove(llao->lladdr, macaddr, sizeof macaddr);
861e47528f3SDavid du Colombier pktsz += sizeof *llao;
862e47528f3SDavid du Colombier
863e47528f3SDavid du Colombier pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
864e47528f3SDavid du Colombier if(write(fd, buf, pktsz) < pktsz)
8650a84db5eSDavid du Colombier ralog("sendra fail %s: %r", abuf);
8660a84db5eSDavid du Colombier else if (debug)
8670a84db5eSDavid du Colombier ralog("sendra succ %s", abuf);
868e47528f3SDavid du Colombier }
869e47528f3SDavid du Colombier
870e47528f3SDavid du Colombier /*
8710a84db5eSDavid du Colombier * daemon to send router advertisements to hosts
872e47528f3SDavid du Colombier */
873e47528f3SDavid du Colombier void
sendra6(void)874e47528f3SDavid du Colombier sendra6(void)
875e47528f3SDavid du Colombier {
876e47528f3SDavid du Colombier int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
8770a84db5eSDavid du Colombier long lastra, now;
878e47528f3SDavid du Colombier uchar buf[4096], dst[IPaddrlen];
879e47528f3SDavid du Colombier Ipifc *ifc = nil;
880e47528f3SDavid du Colombier
881e47528f3SDavid du Colombier fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
882e47528f3SDavid du Colombier if (fd < 0)
883e47528f3SDavid du Colombier sysfatal("can't open icmp_rs connection: %r");
884e47528f3SDavid du Colombier
885e47528f3SDavid du Colombier notify(catch);
8865e1edbcaSDavid du Colombier sendracnt = Maxv6initras;
8875e1edbcaSDavid du Colombier nquitmsgs = Maxv6finalras;
888e47528f3SDavid du Colombier
889e47528f3SDavid du Colombier switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
890e47528f3SDavid du Colombier case -1:
891e47528f3SDavid du Colombier sysfatal("can't fork: %r");
892e47528f3SDavid du Colombier default:
893e47528f3SDavid du Colombier return;
894e47528f3SDavid du Colombier case 0:
8950a84db5eSDavid du Colombier break;
8960a84db5eSDavid du Colombier }
8970a84db5eSDavid du Colombier
898e47528f3SDavid du Colombier procsetname("sendra6 on %s", conf.dev);
899e47528f3SDavid du Colombier ralog("sendra6 on %s", conf.dev);
9000a84db5eSDavid du Colombier sleepfor = jitter();
901e47528f3SDavid du Colombier for (;;) {
902e47528f3SDavid du Colombier lastra = time(0);
9030a84db5eSDavid du Colombier if (sleepfor < 0)
9040a84db5eSDavid du Colombier sleepfor = 0;
905e47528f3SDavid du Colombier alarm(sleepfor);
906e47528f3SDavid du Colombier n = read(fd, buf, sizeof buf);
907e47528f3SDavid du Colombier alarm(0);
908e47528f3SDavid du Colombier
909e47528f3SDavid du Colombier ifc = readipifc(conf.mpoint, ifc, myifc);
910e47528f3SDavid du Colombier if (ifc == nil) {
9110a84db5eSDavid du Colombier ralog("sendra6: can't read router params on %s",
912e47528f3SDavid du Colombier conf.mpoint);
913e47528f3SDavid du Colombier continue;
914e47528f3SDavid du Colombier }
915e47528f3SDavid du Colombier
916e47528f3SDavid du Colombier if (ifc->sendra6 <= 0)
917e47528f3SDavid du Colombier if (nquitmsgs > 0) {
918e47528f3SDavid du Colombier sendra(fd, v6allnodesL, 0);
919e47528f3SDavid du Colombier nquitmsgs--;
9200a84db5eSDavid du Colombier sleepfor = Minv6interradelay + jitter();
921e47528f3SDavid du Colombier continue;
922e47528f3SDavid du Colombier } else {
9230a84db5eSDavid du Colombier ralog("sendra6: sendra off, quitting on %s",
9240a84db5eSDavid du Colombier conf.dev);
925e47528f3SDavid du Colombier exits(0);
926e47528f3SDavid du Colombier }
927e47528f3SDavid du Colombier
9285e1edbcaSDavid du Colombier nquitmsgs = Maxv6finalras;
929e47528f3SDavid du Colombier
9308c6ab946SDavid du Colombier if (n <= 0) { /* no RS */
931e47528f3SDavid du Colombier if (sendracnt > 0)
932e47528f3SDavid du Colombier sendracnt--;
9338c6ab946SDavid du Colombier } else { /* respond to RS */
934e47528f3SDavid du Colombier dstknown = recvrs(buf, n, dst);
9350a84db5eSDavid du Colombier now = time(0);
936e47528f3SDavid du Colombier
9370a84db5eSDavid du Colombier if (now - lastra < Minv6interradelay) {
938e47528f3SDavid du Colombier /* too close, skip */
9390a84db5eSDavid du Colombier sleepfor = lastra + Minv6interradelay +
9400a84db5eSDavid du Colombier jitter() - now;
941e47528f3SDavid du Colombier continue;
942e47528f3SDavid du Colombier }
9430a84db5eSDavid du Colombier sleep(jitter());
944e47528f3SDavid du Colombier }
9450a84db5eSDavid du Colombier sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
946e47528f3SDavid du Colombier if (dstknown > 0)
947e47528f3SDavid du Colombier sendra(fd, dst, 1);
948e47528f3SDavid du Colombier else
949e47528f3SDavid du Colombier sendra(fd, v6allnodesL, 1);
950e47528f3SDavid du Colombier }
951e47528f3SDavid du Colombier }
952e47528f3SDavid du Colombier
953e47528f3SDavid du Colombier void
startra6(void)954ccaac148SDavid du Colombier startra6(void)
955e47528f3SDavid du Colombier {
956e47528f3SDavid du Colombier static char routeon[] = "iprouting 1";
957e47528f3SDavid du Colombier
958e47528f3SDavid du Colombier if (conf.recvra > 0)
959e47528f3SDavid du Colombier recvra6();
960e47528f3SDavid du Colombier
961e47528f3SDavid du Colombier if (conf.sendra > 0) {
962e47528f3SDavid du Colombier if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
9638c6ab946SDavid du Colombier warning("write (iprouting 1) failed: %r");
964e47528f3SDavid du Colombier return;
965e47528f3SDavid du Colombier }
966e47528f3SDavid du Colombier sendra6();
967e47528f3SDavid du Colombier if (conf.recvra <= 0)
968e47528f3SDavid du Colombier recvra6();
969e47528f3SDavid du Colombier }
970e47528f3SDavid du Colombier }
971e47528f3SDavid du Colombier
972e47528f3SDavid du Colombier void
doipv6(int what)973ccaac148SDavid du Colombier doipv6(int what)
974e47528f3SDavid du Colombier {
975e47528f3SDavid du Colombier nip = nipifcs(conf.mpoint);
976e47528f3SDavid du Colombier if(!noconfig){
977e47528f3SDavid du Colombier lookforip(conf.mpoint);
978e47528f3SDavid du Colombier controldevice();
979e47528f3SDavid du Colombier binddevice();
980e47528f3SDavid du Colombier }
981e47528f3SDavid du Colombier
982e47528f3SDavid du Colombier switch (what) {
983e47528f3SDavid du Colombier default:
9848c6ab946SDavid du Colombier sysfatal("unknown IPv6 verb");
985e47528f3SDavid du Colombier case Vaddpref6:
986ccaac148SDavid du Colombier issueadd6(&conf);
987e47528f3SDavid du Colombier break;
988e47528f3SDavid du Colombier case Vra6:
989ccaac148SDavid du Colombier issuebasera6(&conf);
990ccaac148SDavid du Colombier issuerara6(&conf);
9910a84db5eSDavid du Colombier dolog = 1;
992ccaac148SDavid du Colombier startra6();
993e47528f3SDavid du Colombier break;
994e47528f3SDavid du Colombier }
995e47528f3SDavid du Colombier }
996