OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [nd6_nbr.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/nd6_nbr.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: nd6_nbr.c,v 1.83 2001/12/18 02:06:55 itojun Exp $        */
23
 
24
/*
25
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
#include <sys/param.h>
54
#include <sys/malloc.h>
55
#include <sys/mbuf.h>
56
#include <sys/socket.h>
57
#include <sys/sockio.h>
58
#include <sys/errno.h>
59
#include <sys/queue.h>
60
#ifdef __OpenBSD__
61
#include <dev/rndvar.h>
62
#endif
63
 
64
#include <net/if.h>
65
#include <net/if_types.h>
66
#include <net/if_dl.h>
67
#include <net/route.h>
68
 
69
#include <netinet/in.h>
70
#include <netinet/in_var.h>
71
#include <netinet6/in6_var.h>
72
#include <netinet/ip6.h>
73
#include <netinet6/ip6_var.h>
74
#include <netinet6/nd6.h>
75
#include <netinet/icmp6.h>
76
 
77
#ifdef __OpenBSD__      /* don't confuse KAME ipsec with OpenBSD ipsec */
78
#undef IPSEC
79
#endif
80
 
81
#ifdef IPSEC
82
#include <netinet6/ipsec.h>
83
#endif
84
 
85
#ifdef MIP6
86
#include <netinet6/mip6.h>
87
#endif /* MIP6 */
88
 
89
#define SDL(s) ((struct sockaddr_dl *)s)
90
 
91
struct dadq;
92
static struct dadq *nd6_dad_find __P((struct ifaddr *));
93
static void nd6_dad_starttimer __P((struct dadq *, int));
94
static void nd6_dad_stoptimer __P((struct dadq *));
95
static void nd6_dad_timer __P((struct ifaddr *));
96
static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *));
97
static void nd6_dad_ns_input __P((struct ifaddr *));
98
static void nd6_dad_na_input __P((struct ifaddr *));
99
 
100
static int dad_ignore_ns = 0;    /* ignore NS in DAD - specwise incorrect*/
101
static int dad_maxtry = 15;     /* max # of *tries* to transmit DAD packet */
102
 
103
/*
104
 * Input an Neighbor Solicitation Message.
105
 *
106
 * Based on RFC 2461
107
 * Based on RFC 2462 (duplicated address detection)
108
 */
109
void
110
nd6_ns_input(m, off, icmp6len)
111
        struct mbuf *m;
112
        int off, icmp6len;
113
{
114
        struct ifnet *ifp = m->m_pkthdr.rcvif;
115
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
116
        struct nd_neighbor_solicit *nd_ns;
117
        struct in6_addr saddr6 = ip6->ip6_src;
118
        struct in6_addr daddr6 = ip6->ip6_dst;
119
        struct in6_addr taddr6;
120
        struct in6_addr myaddr6;
121
        char *lladdr = NULL;
122
        struct ifaddr *ifa;
123
        int lladdrlen = 0;
124
        int anycast = 0, proxy = 0, tentative = 0;
125
        int tlladdr;
126
        union nd_opts ndopts;
127
        struct sockaddr_dl *proxydl = NULL;
128
 
129
#ifndef PULLDOWN_TEST
130
        IP6_EXTHDR_CHECK(m, off, icmp6len,);
131
        nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
132
#else
133
        IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
134
        if (nd_ns == NULL) {
135
                icmp6stat.icp6s_tooshort++;
136
                return;
137
        }
138
#endif
139
        ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
140
        taddr6 = nd_ns->nd_ns_target;
141
 
142
        if (ip6->ip6_hlim != 255) {
143
                nd6log((LOG_ERR,
144
                    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
145
                    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
146
                    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
147
                goto bad;
148
        }
149
 
150
        if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
151
                /* dst has to be solicited node multicast address. */
152
                if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL
153
                    /* don't check ifindex portion */
154
                    && daddr6.s6_addr32[1] == 0
155
                    && daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE
156
                    && daddr6.s6_addr8[12] == 0xff) {
157
                        ; /* good */
158
                } else {
159
                        nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
160
                                "(wrong ip6 dst)\n"));
161
                        goto bad;
162
                }
163
        }
164
 
165
        if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
166
                nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
167
                goto bad;
168
 
169
        }
170
 
171
        if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
172
                taddr6.s6_addr16[1] = htons(ifp->if_index);
173
 
174
        icmp6len -= sizeof(*nd_ns);
175
        nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
176
        if (nd6_options(&ndopts) < 0) {
177
                nd6log((LOG_INFO,
178
                    "nd6_ns_input: invalid ND option, ignored\n"));
179
                /* nd6_options have incremented stats */
180
                goto freeit;
181
        }
182
 
183
        if (ndopts.nd_opts_src_lladdr) {
184
                lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
185
                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
186
        }
187
 
188
        if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
189
                nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
190
                    "(link-layer address option)\n"));
191
                goto bad;
192
        }
193
 
194
        /*
195
         * Attaching target link-layer address to the NA?
196
         * (RFC 2461 7.2.4)
197
         *
198
         * NS IP dst is unicast/anycast                 MUST NOT add
199
         * NS IP dst is solicited-node multicast        MUST add
200
         *
201
         * In implementation, we add target link-layer address by default.
202
         * We do not add one in MUST NOT cases.
203
         */
204
#if 0 /* too much! */
205
        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
206
        if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
207
                tlladdr = 0;
208
        else
209
#endif
210
        if (!IN6_IS_ADDR_MULTICAST(&daddr6))
211
                tlladdr = 0;
212
        else
213
                tlladdr = 1;
214
 
215
        /*
216
         * Target address (taddr6) must be either:
217
         * (1) Valid unicast/anycast address for my receiving interface,
218
         * (2) Unicast address for which I'm offering proxy service, or
219
         * (3) "tentative" address on which DAD is being performed.
220
         */
221
        /* (1) and (3) check. */
222
        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
223
 
224
        /* (2) check. */
225
        if (!ifa) {
226
                struct rtentry *rt;
227
                struct sockaddr_in6 tsin6;
228
 
229
                bzero(&tsin6, sizeof tsin6);
230
                tsin6.sin6_len = sizeof(struct sockaddr_in6);
231
                tsin6.sin6_family = AF_INET6;
232
                tsin6.sin6_addr = taddr6;
233
 
234
                rt = rtalloc1((struct sockaddr *)&tsin6, 0
235
#ifdef __FreeBSD__
236
                              , 0
237
#endif /* __FreeBSD__ */
238
                              );
239
                if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
240
                    rt->rt_gateway->sa_family == AF_LINK) {
241
                        /*
242
                         * proxy NDP for single entry
243
                         */
244
                        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
245
                                IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
246
                        if (ifa) {
247
                                proxy = 1;
248
                                proxydl = SDL(rt->rt_gateway);
249
                        }
250
                }
251
                if (rt)
252
                        rtfree(rt);
253
        }
254
#ifdef MIP6
255
        if (!ifa) {
256
                ifa = mip6_dad_find(&taddr6, ifp);
257
        }
258
#endif
259
        if (!ifa) {
260
                /*
261
                 * We've got an NS packet, and we don't have that adddress
262
                 * assigned for us.  We MUST silently ignore it.
263
                 * See RFC2461 7.2.3.
264
                 */
265
                goto freeit;
266
        }
267
        myaddr6 = *IFA_IN6(ifa);
268
        anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
269
        tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
270
        if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
271
                goto freeit;
272
 
273
        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
274
                nd6log((LOG_INFO,
275
                    "nd6_ns_input: lladdrlen mismatch for %s "
276
                    "(if %d, NS packet %d)\n",
277
                        ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
278
                goto bad;
279
        }
280
 
281
        if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
282
                nd6log((LOG_INFO,
283
                    "nd6_ns_input: duplicate IP6 address %s\n",
284
                    ip6_sprintf(&saddr6)));
285
                goto freeit;
286
        }
287
 
288
        /*
289
         * We have neighbor solicitation packet, with target address equals to
290
         * one of my tentative address.
291
         *
292
         * src addr     how to process?
293
         * ---          ---
294
         * multicast    of course, invalid (rejected in ip6_input)
295
         * unicast      somebody is doing address resolution -> ignore
296
         * unspec       dup address detection
297
         *
298
         * The processing is defined in RFC 2462.
299
         */
300
        if (tentative) {
301
                /*
302
                 * If source address is unspecified address, it is for
303
                 * duplicated address detection.
304
                 *
305
                 * If not, the packet is for addess resolution;
306
                 * silently ignore it.
307
                 */
308
                if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
309
                        nd6_dad_ns_input(ifa);
310
 
311
                goto freeit;
312
        }
313
 
314
        /*
315
         * If the source address is unspecified address, entries must not
316
         * be created or updated.
317
         * It looks that sender is performing DAD.  Output NA toward
318
         * all-node multicast address, to tell the sender that I'm using
319
         * the address.
320
         * S bit ("solicited") must be zero.
321
         */
322
        if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
323
                saddr6 = in6addr_linklocal_allnodes;
324
                saddr6.s6_addr16[1] = htons(ifp->if_index);
325
                nd6_na_output(ifp, &saddr6, &taddr6,
326
                              ((anycast || proxy || !tlladdr)
327
                                      ? 0 : ND_NA_FLAG_OVERRIDE)
328
                                | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
329
                              tlladdr, (struct sockaddr *)proxydl);
330
                goto freeit;
331
        }
332
 
333
        nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
334
 
335
        nd6_na_output(ifp, &saddr6, &taddr6,
336
                      ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
337
                        | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
338
                        | ND_NA_FLAG_SOLICITED,
339
                      tlladdr, (struct sockaddr *)proxydl);
340
 freeit:
341
        m_freem(m);
342
        return;
343
 
344
 bad:
345
        nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
346
        nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
347
        nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
348
        icmp6stat.icp6s_badns++;
349
        m_freem(m);
350
}
351
 
352
/*
353
 * Output an Neighbor Solicitation Message. Caller specifies:
354
 *      - ICMP6 header source IP6 address
355
 *      - ND6 header target IP6 address
356
 *      - ND6 header source datalink address
357
 *
358
 * Based on RFC 2461
359
 * Based on RFC 2462 (duplicated address detection)
360
 */
361
void
362
nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
363
        struct ifnet *ifp;
364
        const struct in6_addr *daddr6, *taddr6;
365
        struct llinfo_nd6 *ln;  /* for source address determination */
366
        int dad;        /* duplicated address detection */
367
{
368
        struct mbuf *m;
369
        struct ip6_hdr *ip6;
370
        struct nd_neighbor_solicit *nd_ns;
371
        struct in6_ifaddr *ia = NULL;
372
        struct ip6_moptions im6o;
373
        int icmp6len;
374
        int maxlen;
375
        caddr_t mac;
376
        struct sockaddr_in6 sin6_in;
377
#ifdef MIP6
378
        int unicast_ns = 0;
379
#endif
380
 
381
        if (IN6_IS_ADDR_MULTICAST(taddr6))
382
                return;
383
 
384
        /* estimate the size of message */
385
        maxlen = sizeof(*ip6) + sizeof(*nd_ns);
386
        maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
387
#ifdef DIAGNOSTIC
388
        if (max_linkhdr + maxlen >= MCLBYTES) {
389
                printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
390
                    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
391
                panic("nd6_ns_output: insufficient MCLBYTES");
392
                /* NOTREACHED */
393
        }
394
#endif
395
 
396
        MGETHDR(m, M_DONTWAIT, MT_DATA);
397
        if (m && max_linkhdr + maxlen >= MHLEN) {
398
                MCLGET(m, M_DONTWAIT);
399
                if ((m->m_flags & M_EXT) == 0) {
400
                        m_free(m);
401
                        m = NULL;
402
                }
403
        }
404
        if (m == NULL)
405
                return;
406
        m->m_pkthdr.rcvif = NULL;
407
 
408
#ifdef MIP6
409
        if (MIP6_IS_MN && daddr6 == NULL && !dad) {
410
                struct hif_softc *sc;
411
                struct mip6_bu *mbu;
412
 
413
                /* 10.20. Returning Home */
414
                for (sc = TAILQ_FIRST(&hif_softc_list);
415
                     sc;
416
                     sc = TAILQ_NEXT(sc, hif_entry)) {
417
                        mbu = mip6_bu_list_find_withpaddr(
418
                                                        &sc->hif_bu_list,
419
                                                        (struct in6_addr *)taddr6);
420
                        if (mbu == NULL)
421
                                continue;
422
                        if ((mbu->mbu_flags & IP6_BUF_HOME) == 0)
423
                                continue;
424
                        if (mbu->mbu_reg_state ==
425
                                        MIP6_BU_REG_STATE_DEREGWAITACK) {
426
                                /* unspecified source */
427
                                dad = 1;
428
                                if (ln && ND6_IS_LLINFO_PROBREACH(ln))
429
                                        unicast_ns = 1;
430
                        }
431
                        break;
432
                }
433
        }
434
        if (!unicast_ns)
435
#endif
436
        if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
437
                m->m_flags |= M_MCAST;
438
                im6o.im6o_multicast_ifp = ifp;
439
                im6o.im6o_multicast_hlim = 255;
440
                im6o.im6o_multicast_loop = 0;
441
        }
442
 
443
        icmp6len = sizeof(*nd_ns);
444
        m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
445
        m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
446
 
447
        /* fill neighbor solicitation packet */
448
        ip6 = mtod(m, struct ip6_hdr *);
449
        ip6->ip6_flow = 0;
450
        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
451
        ip6->ip6_vfc |= IPV6_VERSION;
452
        /* ip6->ip6_plen will be set later */
453
        ip6->ip6_nxt = IPPROTO_ICMPV6;
454
        ip6->ip6_hlim = 255;
455
        if (daddr6)
456
                ip6->ip6_dst = *daddr6;
457
#ifdef MIP6
458
        else if (unicast_ns)
459
                ip6->ip6_dst = *taddr6;
460
#endif
461
        else {
462
                ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
463
                ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
464
                ip6->ip6_dst.s6_addr32[1] = 0;
465
                ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
466
                ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
467
                ip6->ip6_dst.s6_addr8[12] = 0xff;
468
        }
469
        if (!dad) {
470
                /*
471
                 * RFC2461 7.2.2:
472
                 * "If the source address of the packet prompting the
473
                 * solicitation is the same as one of the addresses assigned
474
                 * to the outgoing interface, that address SHOULD be placed
475
                 * in the IP Source Address of the outgoing solicitation.
476
                 * Otherwise, any one of the addresses assigned to the
477
                 * interface should be used."
478
                 *
479
                 * We use the source address for the prompting packet
480
                 * (saddr6), if:
481
                 * - saddr6 is given from the caller (by giving "ln"), and
482
                 * - saddr6 belongs to the outgoing interface.
483
                 * Otherwise, we perform a scope-wise match.
484
                 */
485
                struct ip6_hdr *hip6;           /* hold ip6 */
486
                struct in6_addr *saddr6;
487
 
488
                if (ln && ln->ln_hold) {
489
                        hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
490
                        if (sizeof(*hip6) < ln->ln_hold->m_len) {
491
                                int zone;
492
 
493
                                bzero(&sin6_in, sizeof(sin6_in));
494
                                sin6_in.sin6_family = AF_INET6;
495
                                sin6_in.sin6_len = sizeof(sin6_in);
496
                                sin6_in.sin6_addr = hip6->ip6_src;
497
                                zone = in6_addr2zoneid(ifp,
498
                                                       &sin6_in.sin6_addr);
499
                                if (zone < 0) /* XXX: should not happen! */
500
                                        goto bad;
501
                                sin6_in.sin6_scope_id = zone;
502
                                in6_embedscope(&sin6_in.sin6_addr, &sin6_in);
503
                                saddr6 = &sin6_in.sin6_addr;
504
                        } else
505
                                saddr6 = NULL;
506
                } else
507
                        saddr6 = NULL;
508
                if (saddr6 && in6ifa_ifpwithaddr(ifp, saddr6))
509
                        bcopy(saddr6, &ip6->ip6_src, sizeof(*saddr6));
510
                else {
511
                        ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
512
                        if (ia == NULL) {
513
                                m_freem(m);
514
                                return;
515
                        }
516
                        ip6->ip6_src = ia->ia_addr.sin6_addr;
517
                }
518
        } else {
519
                /*
520
                 * Source address for DAD packet must always be IPv6
521
                 * unspecified address. (0::0)
522
                 */
523
                bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
524
        }
525
        nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
526
        nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
527
        nd_ns->nd_ns_code = 0;
528
        nd_ns->nd_ns_reserved = 0;
529
        nd_ns->nd_ns_target = *taddr6;
530
 
531
        if (IN6_IS_SCOPE_LINKLOCAL(&nd_ns->nd_ns_target))
532
                nd_ns->nd_ns_target.s6_addr16[1] = 0;
533
 
534
        /*
535
         * Add source link-layer address option.
536
         *
537
         *                              spec            implementation
538
         *                              ---             ---
539
         * DAD packet                   MUST NOT        do not add the option
540
         * there's no link layer address:
541
         *                              impossible      do not add the option
542
         * there's link layer address:
543
         *      Multicast NS            MUST add one    add the option
544
         *      Unicast NS              SHOULD add one  add the option
545
         */
546
        if (!dad && (mac = nd6_ifptomac(ifp))) {
547
                int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
548
                struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
549
                /* 8 byte alignments... */
550
                optlen = (optlen + 7) & ~7;
551
 
552
                m->m_pkthdr.len += optlen;
553
                m->m_len += optlen;
554
                icmp6len += optlen;
555
                bzero((caddr_t)nd_opt, optlen);
556
                nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
557
                nd_opt->nd_opt_len = optlen >> 3;
558
                bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
559
        }
560
 
561
        ip6->ip6_plen = htons((u_short)icmp6len);
562
        nd_ns->nd_ns_cksum = 0;
563
        nd_ns->nd_ns_cksum
564
                = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
565
 
566
#ifdef IPSEC
567
        /* Don't lookup socket */
568
        (void)ipsec_setsocket(m, NULL);
569
#endif
570
        ip6_output(m, NULL, NULL, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL);
571
        icmp6_ifstat_inc(ifp, ifs6_out_msg);
572
        icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
573
        icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
574
 
575
        return;
576
 
577
  bad:
578
        m_freem(m);
579
        return;
580
}
581
 
582
/*
583
 * Neighbor advertisement input handling.
584
 *
585
 * Based on RFC 2461
586
 * Based on RFC 2462 (duplicated address detection)
587
 *
588
 * the following items are not implemented yet:
589
 * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
590
 * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
591
 */
592
void
593
nd6_na_input(m, off, icmp6len)
594
        struct mbuf *m;
595
        int off, icmp6len;
596
{
597
        struct ifnet *ifp = m->m_pkthdr.rcvif;
598
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
599
        struct nd_neighbor_advert *nd_na;
600
#if 0
601
        struct in6_addr saddr6 = ip6->ip6_src;
602
#endif
603
        struct in6_addr daddr6 = ip6->ip6_dst;
604
        struct in6_addr taddr6;
605
        int flags;
606
        int is_router;
607
        int is_solicited;
608
        int is_override;
609
        char *lladdr = NULL;
610
        int lladdrlen = 0;
611
        struct ifaddr *ifa;
612
        struct llinfo_nd6 *ln;
613
        struct rtentry *rt;
614
        struct sockaddr_dl *sdl;
615
        union nd_opts ndopts;
616
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
617
        long time_second = time.tv_sec;
618
#endif
619
 
620
        if (ip6->ip6_hlim != 255) {
621
                nd6log((LOG_ERR,
622
                    "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
623
                    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
624
                    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
625
                goto bad;
626
        }
627
 
628
#ifndef PULLDOWN_TEST
629
        IP6_EXTHDR_CHECK(m, off, icmp6len,);
630
        nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
631
#else
632
        IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
633
        if (nd_na == NULL) {
634
                icmp6stat.icp6s_tooshort++;
635
                return;
636
        }
637
#endif
638
        taddr6 = nd_na->nd_na_target;
639
        flags = nd_na->nd_na_flags_reserved;
640
        is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
641
        is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
642
        is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
643
 
644
        if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
645
                taddr6.s6_addr16[1] = htons(ifp->if_index);
646
 
647
        if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
648
                nd6log((LOG_ERR,
649
                    "nd6_na_input: invalid target address %s\n",
650
                    ip6_sprintf(&taddr6)));
651
                goto bad;
652
        }
653
        if (IN6_IS_ADDR_MULTICAST(&daddr6))
654
                if (is_solicited) {
655
                        nd6log((LOG_ERR,
656
                            "nd6_na_input: a solicited adv is multicasted\n"));
657
                        goto bad;
658
                }
659
 
660
        icmp6len -= sizeof(*nd_na);
661
        nd6_option_init(nd_na + 1, icmp6len, &ndopts);
662
        if (nd6_options(&ndopts) < 0) {
663
                nd6log((LOG_INFO,
664
                    "nd6_na_input: invalid ND option, ignored\n"));
665
                /* nd6_options have incremented stats */
666
                goto freeit;
667
        }
668
 
669
        if (ndopts.nd_opts_tgt_lladdr) {
670
                lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
671
                lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
672
        }
673
 
674
        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
675
#ifdef MIP6
676
        if (!ifa) {
677
                ifa = mip6_dad_find(&taddr6, ifp);
678
        }
679
#endif
680
 
681
        /*
682
         * Target address matches one of my interface address.
683
         *
684
         * If my address is tentative, this means that there's somebody
685
         * already using the same address as mine.  This indicates DAD failure.
686
         * This is defined in RFC 2462.
687
         *
688
         * Otherwise, process as defined in RFC 2461.
689
         */
690
        if (ifa
691
         && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
692
                nd6_dad_na_input(ifa);
693
                goto freeit;
694
        }
695
 
696
        /* Just for safety, maybe unnecessary. */
697
        if (ifa) {
698
                log(LOG_ERR,
699
                    "nd6_na_input: duplicate IP6 address %s\n",
700
                    ip6_sprintf(&taddr6));
701
                goto freeit;
702
        }
703
 
704
        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
705
                nd6log((LOG_INFO,
706
                    "nd6_na_input: lladdrlen mismatch for %s "
707
                    "(if %d, NA packet %d)\n",
708
                        ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
709
                goto bad;
710
        }
711
 
712
        /*
713
         * If no neighbor cache entry is found, NA SHOULD silently be discarded.
714
         */
715
        rt = nd6_lookup(&taddr6, 0, ifp);
716
        if ((rt == NULL) ||
717
           ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
718
           ((sdl = SDL(rt->rt_gateway)) == NULL))
719
                goto freeit;
720
 
721
        if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
722
                /*
723
                 * If the link-layer has address, and no lladdr option came,
724
                 * discard the packet.
725
                 */
726
                if (ifp->if_addrlen && !lladdr)
727
                        goto freeit;
728
 
729
                /*
730
                 * Record link-layer address, and update the state.
731
                 */
732
                sdl->sdl_alen = ifp->if_addrlen;
733
                bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
734
                if (is_solicited) {
735
                        ln->ln_state = ND6_LLINFO_REACHABLE;
736
                        ln->ln_byhint = 0;
737
                        if (ln->ln_expire)
738
                                ln->ln_expire = time_second +
739
                                    nd_ifinfo[rt->rt_ifp->if_index].reachable;
740
                } else {
741
                        ln->ln_state = ND6_LLINFO_STALE;
742
                        ln->ln_expire = time_second + nd6_gctimer;
743
                }
744
                if ((ln->ln_router = is_router) != 0) {
745
                        /*
746
                         * This means a router's state has changed from
747
                         * non-reachable to probably reachable, and might
748
                         * affect the status of associated prefixes..
749
                         */
750
                        pfxlist_onlink_check();
751
                }
752
        } else {
753
                int llchange;
754
 
755
                /*
756
                 * Check if the link-layer address has changed or not.
757
                 */
758
                if (!lladdr)
759
                        llchange = 0;
760
                else {
761
                        if (sdl->sdl_alen) {
762
                                if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))
763
                                        llchange = 1;
764
                                else
765
                                        llchange = 0;
766
                        } else
767
                                llchange = 1;
768
                }
769
 
770
                /*
771
                 * This is VERY complex.  Look at it with care.
772
                 *
773
                 * override solicit lladdr llchange     action
774
                 *                                      (L: record lladdr)
775
                 *
776
                 *      0        0        n       --      (2c)
777
                 *      0        0        y       n       (2b) L
778
                 *      0        0        y       y       (1)    REACHABLE->STALE
779
                 *      0        1       n       --      (2c)   *->REACHABLE
780
                 *      0        1       y       n       (2b) L *->REACHABLE
781
                 *      0        1       y       y       (1)    REACHABLE->STALE
782
                 *      1       0        n       --      (2a)
783
                 *      1       0        y       n       (2a) L
784
                 *      1       0        y       y       (2a) L *->STALE
785
                 *      1       1       n       --      (2a)   *->REACHABLE
786
                 *      1       1       y       n       (2a) L *->REACHABLE
787
                 *      1       1       y       y       (2a) L *->REACHABLE
788
                 */
789
                if (!is_override && (lladdr && llchange)) {        /* (1) */
790
                        /*
791
                         * If state is REACHABLE, make it STALE.
792
                         * no other updates should be done.
793
                         */
794
                        if (ln->ln_state == ND6_LLINFO_REACHABLE) {
795
                                ln->ln_state = ND6_LLINFO_STALE;
796
                                ln->ln_expire = time_second + nd6_gctimer;
797
                        }
798
                        goto freeit;
799
                } else if (is_override                             /* (2a) */
800
                        || (!is_override && (lladdr && !llchange)) /* (2b) */
801
                        || !lladdr) {                              /* (2c) */
802
                        /*
803
                         * Update link-local address, if any.
804
                         */
805
                        if (lladdr) {
806
                                sdl->sdl_alen = ifp->if_addrlen;
807
                                bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
808
                        }
809
 
810
                        /*
811
                         * If solicited, make the state REACHABLE.
812
                         * If not solicited and the link-layer address was
813
                         * changed, make it STALE.
814
                         */
815
                        if (is_solicited) {
816
                                ln->ln_state = ND6_LLINFO_REACHABLE;
817
                                ln->ln_byhint = 0;
818
                                if (ln->ln_expire) {
819
                                        ln->ln_expire = time_second +
820
                                            nd_ifinfo[ifp->if_index].reachable;
821
                                }
822
                        } else {
823
                                if (lladdr && llchange) {
824
                                        ln->ln_state = ND6_LLINFO_STALE;
825
                                        ln->ln_expire = time_second + nd6_gctimer;
826
                                }
827
                        }
828
                }
829
 
830
                if (ln->ln_router && !is_router) {
831
                        /*
832
                         * The peer dropped the router flag.
833
                         * Remove the sender from the Default Router List and
834
                         * update the Destination Cache entries.
835
                         */
836
                        struct nd_defrouter *dr;
837
                        struct in6_addr *in6;
838
                        int s;
839
 
840
                        in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
841
 
842
                        /*
843
                         * Lock to protect the default router list.
844
                         * XXX: this might be unnecessary, since this function
845
                         * is only called under the network software interrupt
846
                         * context.  However, we keep it just for safety.
847
                         */
848
#ifdef __NetBSD__
849
                        s = splsoftnet();
850
#else
851
                        s = splnet();
852
#endif
853
                        dr = defrouter_lookup(in6, rt->rt_ifp);
854
                        if (dr)
855
                                defrtrlist_del(dr);
856
                        else if (!ip6_forwarding && ip6_accept_rtadv) {
857
                                /*
858
                                 * Even if the neighbor is not in the default
859
                                 * router list, the neighbor may be used
860
                                 * as a next hop for some destinations
861
                                 * (e.g. redirect case). So we must
862
                                 * call rt6_flush explicitly.
863
                                 */
864
                                rt6_flush(&ip6->ip6_src, rt->rt_ifp);
865
                        }
866
                        splx(s);
867
                }
868
                ln->ln_router = is_router;
869
        }
870
        rt->rt_flags &= ~RTF_REJECT;
871
        ln->ln_asked = 0;
872
        if (ln->ln_hold) {
873
                /*
874
                 * we assume ifp is not a p2p here, so just set the 2nd
875
                 * argument as the 1st one.
876
                 */
877
                nd6_output(ifp, ifp, ln->ln_hold,
878
                           (struct sockaddr_in6 *)rt_key(rt), rt);
879
                ln->ln_hold = 0;
880
        }
881
 
882
 freeit:
883
        m_freem(m);
884
        return;
885
 
886
 bad:
887
        icmp6stat.icp6s_badna++;
888
        m_freem(m);
889
}
890
 
891
/*
892
 * Neighbor advertisement output handling.
893
 *
894
 * Based on RFC 2461
895
 *
896
 * the following items are not implemented yet:
897
 * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
898
 * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
899
 */
900
void
901
nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
902
        struct ifnet *ifp;
903
        const struct in6_addr *daddr6, *taddr6;
904
        u_long flags;
905
        int tlladdr;            /* 1 if include target link-layer address */
906
        struct sockaddr *sdl0;  /* sockaddr_dl (= proxy NA) or NULL */
907
{
908
        struct mbuf *m;
909
        struct ip6_hdr *ip6;
910
        struct nd_neighbor_advert *nd_na;
911
        struct in6_ifaddr *ia = NULL;
912
        struct ip6_moptions im6o;
913
        int icmp6len;
914
        int maxlen;
915
        caddr_t mac = NULL;
916
 
917
        /* estimate the size of message */
918
        maxlen = sizeof(*ip6) + sizeof(*nd_na);
919
        maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
920
#ifdef DIAGNOSTIC
921
        if (max_linkhdr + maxlen >= MCLBYTES) {
922
                printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
923
                    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
924
                panic("nd6_na_output: insufficient MCLBYTES");
925
                /* NOTREACHED */
926
        }
927
#endif
928
 
929
        MGETHDR(m, M_DONTWAIT, MT_DATA);
930
        if (m && max_linkhdr + maxlen >= MHLEN) {
931
                MCLGET(m, M_DONTWAIT);
932
                if ((m->m_flags & M_EXT) == 0) {
933
                        m_free(m);
934
                        m = NULL;
935
                }
936
        }
937
        if (m == NULL)
938
                return;
939
        m->m_pkthdr.rcvif = NULL;
940
 
941
        if (IN6_IS_ADDR_MULTICAST(daddr6)) {
942
                m->m_flags |= M_MCAST;
943
                im6o.im6o_multicast_ifp = ifp;
944
                im6o.im6o_multicast_hlim = 255;
945
                im6o.im6o_multicast_loop = 0;
946
        }
947
 
948
        icmp6len = sizeof(*nd_na);
949
        m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
950
        m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
951
 
952
        /* fill neighbor advertisement packet */
953
        ip6 = mtod(m, struct ip6_hdr *);
954
        ip6->ip6_flow = 0;
955
        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
956
        ip6->ip6_vfc |= IPV6_VERSION;
957
        ip6->ip6_nxt = IPPROTO_ICMPV6;
958
        ip6->ip6_hlim = 255;
959
        if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
960
                /* reply to DAD */
961
                ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
962
                ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
963
                ip6->ip6_dst.s6_addr32[1] = 0;
964
                ip6->ip6_dst.s6_addr32[2] = 0;
965
                ip6->ip6_dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
966
                flags &= ~ND_NA_FLAG_SOLICITED;
967
        } else
968
                ip6->ip6_dst = *daddr6;
969
 
970
        /*
971
         * Select a source whose scope is the same as that of the dest.
972
         */
973
        ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
974
        if (ia == NULL) {
975
                m_freem(m);
976
                return;
977
        }
978
        ip6->ip6_src = ia->ia_addr.sin6_addr;
979
        nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
980
        nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
981
        nd_na->nd_na_code = 0;
982
        nd_na->nd_na_target = *taddr6;
983
        if (IN6_IS_SCOPE_LINKLOCAL(&nd_na->nd_na_target))
984
                nd_na->nd_na_target.s6_addr16[1] = 0;
985
 
986
        /*
987
         * "tlladdr" indicates NS's condition for adding tlladdr or not.
988
         * see nd6_ns_input() for details.
989
         * Basically, if NS packet is sent to unicast/anycast addr,
990
         * target lladdr option SHOULD NOT be included.
991
         */
992
        if (tlladdr) {
993
                mac = NULL;
994
                /*
995
                 * sdl0 != NULL indicates proxy NA.  If we do proxy, use
996
                 * lladdr in sdl0.  If we are not proxying (sending NA for
997
                 * my address) use lladdr configured for the interface.
998
                 */
999
                if (sdl0 == NULL)
1000
                        mac = nd6_ifptomac(ifp);
1001
                else if (sdl0->sa_family == AF_LINK) {
1002
                        struct sockaddr_dl *sdl;
1003
                        sdl = (struct sockaddr_dl *)sdl0;
1004
                        if (sdl->sdl_alen == ifp->if_addrlen)
1005
                                mac = LLADDR(sdl);
1006
                }
1007
        }
1008
        if (tlladdr && mac) {
1009
                int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
1010
                struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
1011
 
1012
                /* roundup to 8 bytes alignment! */
1013
                optlen = (optlen + 7) & ~7;
1014
 
1015
                m->m_pkthdr.len += optlen;
1016
                m->m_len += optlen;
1017
                icmp6len += optlen;
1018
                bzero((caddr_t)nd_opt, optlen);
1019
                nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1020
                nd_opt->nd_opt_len = optlen >> 3;
1021
                bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
1022
        } else
1023
                flags &= ~ND_NA_FLAG_OVERRIDE;
1024
 
1025
        ip6->ip6_plen = htons((u_short)icmp6len);
1026
        nd_na->nd_na_flags_reserved = flags;
1027
        nd_na->nd_na_cksum = 0;
1028
        nd_na->nd_na_cksum =
1029
                in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
1030
 
1031
#ifdef IPSEC
1032
        /* Don't lookup socket */
1033
        (void)ipsec_setsocket(m, NULL);
1034
#endif
1035
        ip6_output(m, NULL, NULL, 0, &im6o, NULL);
1036
 
1037
        icmp6_ifstat_inc(ifp, ifs6_out_msg);
1038
        icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
1039
        icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
1040
}
1041
 
1042
caddr_t
1043
nd6_ifptomac(ifp)
1044
        struct ifnet *ifp;
1045
{
1046
        switch (ifp->if_type) {
1047
        case IFT_ARCNET:
1048
        case IFT_ETHER:
1049
        case IFT_FDDI:
1050
        case IFT_IEEE1394:
1051
#ifdef IFT_PROPVIRTUAL
1052
        case IFT_PROPVIRTUAL:
1053
#endif
1054
#ifdef IFT_L2VLAN
1055
        case IFT_L2VLAN:
1056
#endif
1057
#ifdef IFT_IEEE80211
1058
        case IFT_IEEE80211:
1059
#endif
1060
#ifdef __NetBSD__
1061
                return LLADDR(ifp->if_sadl);
1062
#else
1063
                return ((caddr_t)(ifp + 1));
1064
#endif
1065
                break;
1066
        default:
1067
                return NULL;
1068
        }
1069
}
1070
 
1071
TAILQ_HEAD(dadq_head, dadq);
1072
struct dadq {
1073
        TAILQ_ENTRY(dadq) dad_list;
1074
        struct ifaddr *dad_ifa;
1075
        int dad_count;          /* max NS to send */
1076
        int dad_ns_tcount;      /* # of trials to send NS */
1077
        int dad_ns_ocount;      /* NS sent so far */
1078
        int dad_ns_icount;
1079
        int dad_na_icount;
1080
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1081
        struct callout dad_timer_ch;
1082
#elif defined(__OpenBSD__)
1083
        struct timeout dad_timer_ch;
1084
#endif
1085
};
1086
 
1087
static struct dadq_head dadq;
1088
static int dad_init = 0;
1089
 
1090
static struct dadq *
1091
nd6_dad_find(ifa)
1092
        struct ifaddr *ifa;
1093
{
1094
        struct dadq *dp;
1095
 
1096
        for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
1097
                if (dp->dad_ifa == ifa)
1098
                        return dp;
1099
        }
1100
        return NULL;
1101
}
1102
 
1103
static void
1104
nd6_dad_starttimer(dp, _ticks)
1105
        struct dadq *dp;
1106
        int _ticks;
1107
{
1108
 
1109
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1110
        callout_reset(&dp->dad_timer_ch, _ticks,
1111
            (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);
1112
#elif defined(__OpenBSD__)
1113
        timeout_set(&dp->dad_timer_ch, (void (*) __P((void *)))nd6_dad_timer,
1114
            (void *)dp->dad_ifa);
1115
        timeout_add(&dp->dad_timer_ch, _ticks);
1116
#else
1117
        timeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa,
1118
            _ticks);
1119
#endif
1120
}
1121
 
1122
static void
1123
nd6_dad_stoptimer(dp)
1124
        struct dadq *dp;
1125
{
1126
 
1127
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1128
        callout_stop(&dp->dad_timer_ch);
1129
#elif defined(__OpenBSD__)
1130
        timeout_del(&dp->dad_timer_ch);
1131
#else
1132
        untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);
1133
#endif
1134
}
1135
 
1136
/*
1137
 * Start Duplicated Address Detection (DAD) for specified interface address.
1138
 */
1139
void
1140
nd6_dad_start(ifa, tick)
1141
        struct ifaddr *ifa;
1142
        int *tick;      /* minimum delay ticks for IFF_UP event */
1143
{
1144
        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1145
        struct dadq *dp;
1146
        int ntick;
1147
 
1148
        if (!dad_init) {
1149
                TAILQ_INIT(&dadq);
1150
                dad_init++;
1151
        }
1152
 
1153
        /*
1154
         * If we don't need DAD, don't do it.
1155
         * There are several cases:
1156
         * - DAD is disabled (ip6_dad_count == 0)
1157
         * - the interface address is anycast
1158
         */
1159
        if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
1160
                log(LOG_DEBUG,
1161
                        "nd6_dad_start: called with non-tentative address "
1162
                        "%s(%s)\n",
1163
                        ip6_sprintf(&ia->ia_addr.sin6_addr),
1164
                        ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1165
                return;
1166
        }
1167
        if (ia->ia6_flags & IN6_IFF_ANYCAST) {
1168
                ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1169
                return;
1170
        }
1171
        if (!ip6_dad_count) {
1172
                ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1173
                return;
1174
        }
1175
        if (!ifa->ifa_ifp)
1176
                panic("nd6_dad_start: ifa->ifa_ifp == NULL");
1177
        if (!(ifa->ifa_ifp->if_flags & IFF_UP))
1178
                return;
1179
        if (nd6_dad_find(ifa) != NULL) {
1180
                /* DAD already in progress */
1181
                return;
1182
        }
1183
 
1184
        dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
1185
        if (dp == NULL) {
1186
                log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
1187
                        "%s(%s)\n",
1188
                        ip6_sprintf(&ia->ia_addr.sin6_addr),
1189
                        ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1190
                return;
1191
        }
1192
        bzero(dp, sizeof(*dp));
1193
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1194
        callout_init(&dp->dad_timer_ch);
1195
#elif defined(__OpenBSD__)
1196
        bzero(&dp->dad_timer_ch, sizeof(dp->dad_timer_ch));
1197
#endif
1198
        TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
1199
 
1200
        nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
1201
            ip6_sprintf(&ia->ia_addr.sin6_addr)));
1202
 
1203
        /*
1204
         * Send NS packet for DAD, ip6_dad_count times.
1205
         * Note that we must delay the first transmission, if this is the
1206
         * first packet to be sent from the interface after interface
1207
         * (re)initialization.
1208
         */
1209
        dp->dad_ifa = ifa;
1210
        IFAREF(ifa);    /* just for safety */
1211
        dp->dad_count = ip6_dad_count;
1212
        dp->dad_ns_icount = dp->dad_na_icount = 0;
1213
        dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
1214
        if (tick == NULL) {
1215
                nd6_dad_ns_output(dp, ifa);
1216
                ntick = nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000;
1217
        } else {
1218
 
1219
#ifdef __OpenBSD__
1220
#define random  arc4random
1221
#endif
1222
                if (*tick == 0)
1223
                        ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz);
1224
                else
1225
                        ntick = *tick + random() % (hz / 2);
1226
#ifdef __OpenBSD__
1227
#undef random
1228
#endif
1229
                *tick = ntick;
1230
        }
1231
        if (ntick <= 0) ntick = 1;  // Defensive
1232
        nd6_dad_starttimer(dp, ntick);
1233
}
1234
 
1235
/*
1236
 * terminate DAD unconditionally.  used for address removals.
1237
 */
1238
void
1239
nd6_dad_stop(ifa)
1240
        struct ifaddr *ifa;
1241
{
1242
        struct dadq *dp;
1243
 
1244
        if (!dad_init)
1245
                return;
1246
        dp = nd6_dad_find(ifa);
1247
        if (!dp) {
1248
                /* DAD wasn't started yet */
1249
                return;
1250
        }
1251
 
1252
        nd6_dad_stoptimer(dp);
1253
 
1254
        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1255
        free(dp, M_IP6NDP);
1256
        dp = NULL;
1257
        IFAFREE(ifa);
1258
}
1259
 
1260
static void
1261
nd6_dad_timer(ifa)
1262
        struct ifaddr *ifa;
1263
{
1264
        int s;
1265
        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1266
        struct dadq *dp;
1267
 
1268
#ifdef __NetBSD__
1269
        s = splsoftnet();       /* XXX */
1270
#else
1271
        s = splnet();           /* XXX */
1272
#endif
1273
 
1274
        /* Sanity check */
1275
        if (ia == NULL) {
1276
                log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
1277
                goto done;
1278
        }
1279
        dp = nd6_dad_find(ifa);
1280
        if (dp == NULL) {
1281
                log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
1282
                goto done;
1283
        }
1284
        if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1285
                log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
1286
                        "%s(%s)\n",
1287
                        ip6_sprintf(&ia->ia_addr.sin6_addr),
1288
                        ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1289
                goto done;
1290
        }
1291
        if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
1292
                log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
1293
                        "%s(%s)\n",
1294
                        ip6_sprintf(&ia->ia_addr.sin6_addr),
1295
                        ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1296
                goto done;
1297
        }
1298
 
1299
        /* timeouted with IFF_{RUNNING,UP} check */
1300
        if (dp->dad_ns_tcount > dad_maxtry) {
1301
                nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
1302
                        if_name(ifa->ifa_ifp)));
1303
 
1304
                TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1305
                free(dp, M_IP6NDP);
1306
                dp = NULL;
1307
                IFAFREE(ifa);
1308
                goto done;
1309
        }
1310
 
1311
        /* Need more checks? */
1312
        if (dp->dad_ns_ocount < dp->dad_count) {
1313
                /*
1314
                 * We have more NS to go.  Send NS packet for DAD.
1315
                 */
1316
                nd6_dad_ns_output(dp, ifa);
1317
                nd6_dad_starttimer(dp,
1318
                    nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
1319
        } else {
1320
                /*
1321
                 * We have transmitted sufficient number of DAD packets.
1322
                 * See what we've got.
1323
                 */
1324
                int duplicate;
1325
 
1326
                duplicate = 0;
1327
 
1328
                if (dp->dad_na_icount) {
1329
                        /*
1330
                         * the check is in nd6_dad_na_input(),
1331
                         * but just in case
1332
                         */
1333
                        duplicate++;
1334
                }
1335
 
1336
                if (dp->dad_ns_icount) {
1337
#if 0 /* heuristics */
1338
                        /*
1339
                         * if
1340
                         * - we have sent many(?) DAD NS, and
1341
                         * - the number of NS we sent equals to the
1342
                         *   number of NS we've got, and
1343
                         * - we've got no NA
1344
                         * we may have a faulty network card/driver which
1345
                         * loops back multicasts to myself.
1346
                         */
1347
                        if (3 < dp->dad_count
1348
                         && dp->dad_ns_icount == dp->dad_count
1349
                         && dp->dad_na_icount == 0) {
1350
                                log(LOG_INFO, "DAD questionable for %s(%s): "
1351
                                        "network card loops back multicast?\n",
1352
                                        ip6_sprintf(&ia->ia_addr.sin6_addr),
1353
                                        if_name(ifa->ifa_ifp));
1354
                                /* XXX consider it a duplicate or not? */
1355
                                /* duplicate++; */
1356
                        } else {
1357
                                /* We've seen NS, means DAD has failed. */
1358
                                duplicate++;
1359
                        }
1360
#else
1361
                        /* We've seen NS, means DAD has failed. */
1362
                        duplicate++;
1363
#endif
1364
                }
1365
 
1366
                if (duplicate) {
1367
                        /* (*dp) will be freed in nd6_dad_duplicated() */
1368
                        dp = NULL;
1369
                        nd6_dad_duplicated(ifa);
1370
                } else {
1371
                        /*
1372
                         * We are done with DAD.  No NA came, no NS came.
1373
                         * duplicated address found.
1374
                         */
1375
                        ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1376
 
1377
                        nd6log((LOG_DEBUG,
1378
                            "%s: DAD complete for %s - no duplicates found\n",
1379
                            if_name(ifa->ifa_ifp),
1380
                            ip6_sprintf(&ia->ia_addr.sin6_addr)));
1381
 
1382
                        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1383
                        free(dp, M_IP6NDP);
1384
                        dp = NULL;
1385
#ifdef MIP6
1386
                        if (mip6_dad_success(ifa) == ENOENT)
1387
#endif
1388
                        IFAFREE(ifa);
1389
                }
1390
        }
1391
 
1392
done:
1393
        splx(s);
1394
}
1395
 
1396
void
1397
nd6_dad_duplicated(ifa)
1398
        struct ifaddr *ifa;
1399
{
1400
        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1401
        struct dadq *dp;
1402
 
1403
        dp = nd6_dad_find(ifa);
1404
        if (dp == NULL) {
1405
                log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
1406
                return;
1407
        }
1408
 
1409
        log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
1410
            "NS in/out=%d/%d, NA in=%d\n",
1411
            if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
1412
            dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
1413
 
1414
        ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1415
        ia->ia6_flags |= IN6_IFF_DUPLICATED;
1416
 
1417
        /* We are done with DAD, with duplicated address found. (failure) */
1418
        nd6_dad_stoptimer(dp);
1419
 
1420
        log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
1421
            if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1422
        log(LOG_ERR, "%s: manual intervention required\n",
1423
            if_name(ifa->ifa_ifp));
1424
 
1425
        TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1426
        free(dp, M_IP6NDP);
1427
        dp = NULL;
1428
#ifdef MIP6
1429
        if (mip6_dad_duplicated(ifa) == ENOENT)
1430
#endif
1431
        IFAFREE(ifa);
1432
}
1433
 
1434
static void
1435
nd6_dad_ns_output(dp, ifa)
1436
        struct dadq *dp;
1437
        struct ifaddr *ifa;
1438
{
1439
        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1440
        struct ifnet *ifp = ifa->ifa_ifp;
1441
 
1442
        dp->dad_ns_tcount++;
1443
        if ((ifp->if_flags & IFF_UP) == 0) {
1444
#if 0
1445
                printf("%s: interface down?\n", if_name(ifp));
1446
#endif
1447
                return;
1448
        }
1449
        if ((ifp->if_flags & IFF_RUNNING) == 0) {
1450
#if 0
1451
                printf("%s: interface not running?\n", if_name(ifp));
1452
#endif
1453
                return;
1454
        }
1455
 
1456
        dp->dad_ns_ocount++;
1457
        nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
1458
}
1459
 
1460
static void
1461
nd6_dad_ns_input(ifa)
1462
        struct ifaddr *ifa;
1463
{
1464
        struct in6_ifaddr *ia;
1465
        struct ifnet *ifp;
1466
        const struct in6_addr *taddr6;
1467
        struct dadq *dp;
1468
        int duplicate;
1469
 
1470
        if (!ifa)
1471
                panic("ifa == NULL in nd6_dad_ns_input");
1472
 
1473
        ia = (struct in6_ifaddr *)ifa;
1474
        ifp = ifa->ifa_ifp;
1475
        taddr6 = &ia->ia_addr.sin6_addr;
1476
        duplicate = 0;
1477
        dp = nd6_dad_find(ifa);
1478
 
1479
        /* Quickhack - completely ignore DAD NS packets */
1480
        if (dad_ignore_ns) {
1481
                nd6log((LOG_INFO,
1482
                    "nd6_dad_ns_input: ignoring DAD NS packet for "
1483
                    "address %s(%s)\n", ip6_sprintf(taddr6),
1484
                    if_name(ifa->ifa_ifp)));
1485
                return;
1486
        }
1487
 
1488
        /*
1489
         * if I'm yet to start DAD, someone else started using this address
1490
         * first.  I have a duplicate and you win.
1491
         */
1492
        if (!dp || dp->dad_ns_ocount == 0)
1493
                duplicate++;
1494
 
1495
        /* XXX more checks for loopback situation - see nd6_dad_timer too */
1496
 
1497
        if (duplicate) {
1498
                dp = NULL;      /* will be freed in nd6_dad_duplicated() */
1499
                nd6_dad_duplicated(ifa);
1500
        } else {
1501
                /*
1502
                 * not sure if I got a duplicate.
1503
                 * increment ns count and see what happens.
1504
                 */
1505
                if (dp)
1506
                        dp->dad_ns_icount++;
1507
        }
1508
}
1509
 
1510
static void
1511
nd6_dad_na_input(ifa)
1512
        struct ifaddr *ifa;
1513
{
1514
        struct dadq *dp;
1515
 
1516
        if (!ifa)
1517
                panic("ifa == NULL in nd6_dad_na_input");
1518
 
1519
        dp = nd6_dad_find(ifa);
1520
        if (dp)
1521
                dp->dad_na_icount++;
1522
 
1523
        /* remove the address. */
1524
        nd6_dad_duplicated(ifa);
1525
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.