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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv6/] [ndisc.c] - Blame information for rev 1275

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Neighbour Discovery for IPv6
3
 *      Linux INET6 implementation
4
 *
5
 *      Authors:
6
 *      Pedro Roque             <roque@di.fc.ul.pt>
7
 *      Mike Shaver             <shaver@ingenia.com>
8
 *
9
 *      This program is free software; you can redistribute it and/or
10
 *      modify it under the terms of the GNU General Public License
11
 *      as published by the Free Software Foundation; either version
12
 *      2 of the License, or (at your option) any later version.
13
 */
14
 
15
/*
16
 *      Changes:
17
 *
18
 *      Lars Fenneberg                  :       fixed MTU setting on receipt
19
 *                                              of an RA.
20
 *
21
 *      Janos Farkas                    :       kmalloc failure checks
22
 *      Alexey Kuznetsov                :       state machine reworked
23
 *                                              and moved to net/core.
24
 *      Pekka Savola                    :       RFC2461 validation
25
 *      YOSHIFUJI Hideaki @USAGI        :       Verify ND options properly
26
 */
27
 
28
/* Set to 3 to get tracing... */
29
#define ND_DEBUG 1
30
 
31
#define ND_PRINTK(x...) printk(KERN_DEBUG x)
32
#define ND_NOPRINTK(x...) do { ; } while(0)
33
#define ND_PRINTK0 ND_PRINTK
34
#define ND_PRINTK1 ND_NOPRINTK
35
#define ND_PRINTK2 ND_NOPRINTK
36
#if ND_DEBUG >= 1
37
#undef ND_PRINTK1
38
#define ND_PRINTK1 ND_PRINTK
39
#endif
40
#if ND_DEBUG >= 2
41
#undef ND_PRINTK2
42
#define ND_PRINTK2 ND_PRINTK
43
#endif
44
 
45
#include <linux/module.h>
46
#include <linux/config.h>
47
#include <linux/errno.h>
48
#include <linux/types.h>
49
#include <linux/socket.h>
50
#include <linux/sockios.h>
51
#include <linux/sched.h>
52
#include <linux/net.h>
53
#include <linux/in6.h>
54
#include <linux/route.h>
55
#include <linux/init.h>
56
#ifdef CONFIG_SYSCTL
57
#include <linux/sysctl.h>
58
#endif
59
 
60
#include <linux/if_arp.h>
61
#include <linux/ipv6.h>
62
#include <linux/icmpv6.h>
63
 
64
#include <net/sock.h>
65
#include <net/snmp.h>
66
 
67
#include <net/ipv6.h>
68
#include <net/protocol.h>
69
#include <net/ndisc.h>
70
#include <net/ip6_route.h>
71
#include <net/addrconf.h>
72
#include <net/icmp.h>
73
 
74
#include <net/checksum.h>
75
#include <linux/proc_fs.h>
76
 
77
static struct socket *ndisc_socket;
78
 
79
static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
80
static int ndisc_constructor(struct neighbour *neigh);
81
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
82
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
83
static int pndisc_constructor(struct pneigh_entry *n);
84
static void pndisc_destructor(struct pneigh_entry *n);
85
static void pndisc_redo(struct sk_buff *skb);
86
 
87
static struct neigh_ops ndisc_generic_ops =
88
{
89
        AF_INET6,
90
        NULL,
91
        ndisc_solicit,
92
        ndisc_error_report,
93
        neigh_resolve_output,
94
        neigh_connected_output,
95
        dev_queue_xmit,
96
        dev_queue_xmit
97
};
98
 
99
static struct neigh_ops ndisc_hh_ops =
100
{
101
        AF_INET6,
102
        NULL,
103
        ndisc_solicit,
104
        ndisc_error_report,
105
        neigh_resolve_output,
106
        neigh_resolve_output,
107
        dev_queue_xmit,
108
        dev_queue_xmit
109
};
110
 
111
 
112
static struct neigh_ops ndisc_direct_ops =
113
{
114
        AF_INET6,
115
        NULL,
116
        NULL,
117
        NULL,
118
        dev_queue_xmit,
119
        dev_queue_xmit,
120
        dev_queue_xmit,
121
        dev_queue_xmit
122
};
123
 
124
struct neigh_table nd_tbl =
125
{
126
        NULL,
127
        AF_INET6,
128
        sizeof(struct neighbour) + sizeof(struct in6_addr),
129
        sizeof(struct in6_addr),
130
        ndisc_hash,
131
        ndisc_constructor,
132
        pndisc_constructor,
133
        pndisc_destructor,
134
        pndisc_redo,
135
        "ndisc_cache",
136
        { NULL, NULL, &nd_tbl, 0, NULL, NULL,
137
                  30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 0 },
138
        30*HZ, 128, 512, 1024,
139
};
140
 
141
#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
142
 
143
static u8 *ndisc_fill_option(u8 *opt, int type, void *data, int data_len)
144
{
145
        int space = NDISC_OPT_SPACE(data_len);
146
 
147
        opt[0] = type;
148
        opt[1] = space>>3;
149
        memcpy(opt+2, data, data_len);
150
        data_len += 2;
151
        opt += data_len;
152
        if ((space -= data_len) > 0)
153
                memset(opt, 0, space);
154
        return opt + space;
155
}
156
 
157
struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
158
                                     struct nd_opt_hdr *end)
159
{
160
        int type;
161
        if (!cur || !end || cur >= end)
162
                return NULL;
163
        type = cur->nd_opt_type;
164
        do {
165
                cur = ((void *)cur) + (cur->nd_opt_len << 3);
166
        } while(cur < end && cur->nd_opt_type != type);
167
        return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
168
}
169
 
170
struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
171
                                          struct ndisc_options *ndopts)
172
{
173
        struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
174
 
175
        if (!nd_opt || opt_len < 0 || !ndopts)
176
                return NULL;
177
        memset(ndopts, 0, sizeof(*ndopts));
178
        while (opt_len) {
179
                int l;
180
                if (opt_len < sizeof(struct nd_opt_hdr))
181
                        return NULL;
182
                l = nd_opt->nd_opt_len << 3;
183
                if (opt_len < l || l == 0)
184
                        return NULL;
185
                switch (nd_opt->nd_opt_type) {
186
                case ND_OPT_SOURCE_LL_ADDR:
187
                case ND_OPT_TARGET_LL_ADDR:
188
                case ND_OPT_MTU:
189
                case ND_OPT_REDIRECT_HDR:
190
                        if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
191
                                ND_PRINTK2((KERN_WARNING
192
                                            "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
193
                                            nd_opt->nd_opt_type));
194
                        } else {
195
                                ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
196
                        }
197
                        break;
198
                case ND_OPT_PREFIX_INFO:
199
                        ndopts->nd_opts_pi_end = nd_opt;
200
                        if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
201
                                ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
202
                        break;
203
                default:
204
                        /*
205
                         * Unknown options must be silently ignored,
206
                         * to accomodate future extension to the protocol.
207
                         */
208
                        ND_PRINTK2(KERN_WARNING
209
                                   "ndisc_parse_options(): ignored unsupported option; type=%d, len=%d\n",
210
                                   nd_opt->nd_opt_type, nd_opt->nd_opt_len);
211
                }
212
                opt_len -= l;
213
                nd_opt = ((void *)nd_opt) + l;
214
        }
215
        return ndopts;
216
}
217
 
218
int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
219
{
220
        switch (dev->type) {
221
        case ARPHRD_ETHER:
222
        case ARPHRD_IEEE802:    /* Not sure. Check it later. --ANK */
223
        case ARPHRD_FDDI:
224
                ipv6_eth_mc_map(addr, buf);
225
                return 0;
226
        case ARPHRD_IEEE802_TR:
227
                ipv6_tr_mc_map(addr,buf);
228
                return 0;
229
        case ARPHRD_ARCNET:
230
                ipv6_arcnet_mc_map(addr, buf);
231
                return 0;
232
        default:
233
                if (dir) {
234
                        memcpy(buf, dev->broadcast, dev->addr_len);
235
                        return 0;
236
                }
237
        }
238
        return -EINVAL;
239
}
240
 
241
static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
242
{
243
        u32 hash_val;
244
 
245
        hash_val = *(u32*)(pkey + sizeof(struct in6_addr) - 4);
246
        hash_val ^= (hash_val>>16);
247
        hash_val ^= hash_val>>8;
248
        hash_val ^= hash_val>>3;
249
        hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
250
 
251
        return hash_val;
252
}
253
 
254
static int ndisc_constructor(struct neighbour *neigh)
255
{
256
        struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
257
        struct net_device *dev = neigh->dev;
258
        struct inet6_dev *in6_dev = in6_dev_get(dev);
259
        int addr_type;
260
 
261
        if (in6_dev == NULL)
262
                return -EINVAL;
263
 
264
        addr_type = ipv6_addr_type(addr);
265
        if (in6_dev->nd_parms)
266
                neigh->parms = in6_dev->nd_parms;
267
 
268
        if (addr_type&IPV6_ADDR_MULTICAST)
269
                neigh->type = RTN_MULTICAST;
270
        else
271
                neigh->type = RTN_UNICAST;
272
        if (dev->hard_header == NULL) {
273
                neigh->nud_state = NUD_NOARP;
274
                neigh->ops = &ndisc_direct_ops;
275
                neigh->output = neigh->ops->queue_xmit;
276
        } else {
277
                if (addr_type&IPV6_ADDR_MULTICAST) {
278
                        neigh->nud_state = NUD_NOARP;
279
                        ndisc_mc_map(addr, neigh->ha, dev, 1);
280
                } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
281
                        neigh->nud_state = NUD_NOARP;
282
                        memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
283
                        if (dev->flags&IFF_LOOPBACK)
284
                                neigh->type = RTN_LOCAL;
285
                } else if (dev->flags&IFF_POINTOPOINT) {
286
                        neigh->nud_state = NUD_NOARP;
287
                        memcpy(neigh->ha, dev->broadcast, dev->addr_len);
288
                }
289
                if (dev->hard_header_cache)
290
                        neigh->ops = &ndisc_hh_ops;
291
                else
292
                        neigh->ops = &ndisc_generic_ops;
293
                if (neigh->nud_state&NUD_VALID)
294
                        neigh->output = neigh->ops->connected_output;
295
                else
296
                        neigh->output = neigh->ops->output;
297
        }
298
        in6_dev_put(in6_dev);
299
        return 0;
300
}
301
 
302
static int pndisc_constructor(struct pneigh_entry *n)
303
{
304
        struct in6_addr *addr = (struct in6_addr*)&n->key;
305
        struct in6_addr maddr;
306
        struct net_device *dev = n->dev;
307
 
308
        if (dev == NULL || __in6_dev_get(dev) == NULL)
309
                return -EINVAL;
310
        addrconf_addr_solict_mult(addr, &maddr);
311
        ipv6_dev_mc_inc(dev, &maddr);
312
        return 0;
313
}
314
 
315
static void pndisc_destructor(struct pneigh_entry *n)
316
{
317
        struct in6_addr *addr = (struct in6_addr*)&n->key;
318
        struct in6_addr maddr;
319
        struct net_device *dev = n->dev;
320
 
321
        if (dev == NULL || __in6_dev_get(dev) == NULL)
322
                return;
323
        addrconf_addr_solict_mult(addr, &maddr);
324
        ipv6_dev_mc_dec(dev, &maddr);
325
}
326
 
327
 
328
 
329
static int
330
ndisc_build_ll_hdr(struct sk_buff *skb, struct net_device *dev,
331
                   struct in6_addr *daddr, struct neighbour *neigh, int len)
332
{
333
        unsigned char ha[MAX_ADDR_LEN];
334
        unsigned char *h_dest = NULL;
335
 
336
        skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
337
 
338
        if (dev->hard_header) {
339
                if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
340
                        ndisc_mc_map(daddr, ha, dev, 1);
341
                        h_dest = ha;
342
                } else if (neigh) {
343
                        read_lock_bh(&neigh->lock);
344
                        if (neigh->nud_state&NUD_VALID) {
345
                                memcpy(ha, neigh->ha, dev->addr_len);
346
                                h_dest = ha;
347
                        }
348
                        read_unlock_bh(&neigh->lock);
349
                } else {
350
                        neigh = neigh_lookup(&nd_tbl, daddr, dev);
351
                        if (neigh) {
352
                                read_lock_bh(&neigh->lock);
353
                                if (neigh->nud_state&NUD_VALID) {
354
                                        memcpy(ha, neigh->ha, dev->addr_len);
355
                                        h_dest = ha;
356
                                }
357
                                read_unlock_bh(&neigh->lock);
358
                                neigh_release(neigh);
359
                        }
360
                }
361
 
362
                if (dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL, len) < 0)
363
                        return 0;
364
        }
365
 
366
        return 1;
367
}
368
 
369
 
370
/*
371
 *      Send a Neighbour Advertisement
372
 */
373
 
374
void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
375
                   struct in6_addr *daddr, struct in6_addr *solicited_addr,
376
                   int router, int solicited, int override, int inc_opt)
377
{
378
        static struct in6_addr tmpaddr;
379
        struct inet6_ifaddr *ifp;
380
        struct sock *sk = ndisc_socket->sk;
381
        struct in6_addr *src_addr;
382
        struct nd_msg *msg;
383
        int len;
384
        struct sk_buff *skb;
385
        int err;
386
 
387
        len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
388
 
389
        if (inc_opt) {
390
                if (dev->addr_len)
391
                        len += NDISC_OPT_SPACE(dev->addr_len);
392
                else
393
                        inc_opt = 0;
394
        }
395
 
396
        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
397
                                  1, &err);
398
 
399
        if (skb == NULL) {
400
                ND_PRINTK1("send_na: alloc skb failed\n");
401
                return;
402
        }
403
        /* for anycast or proxy, solicited_addr != src_addr */
404
        ifp = ipv6_get_ifaddr(solicited_addr, dev);
405
        if (ifp) {
406
                src_addr = solicited_addr;
407
                in6_ifa_put(ifp);
408
        } else {
409
                if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0))
410
                        return;
411
                src_addr = &tmpaddr;
412
        }
413
 
414
        if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
415
                kfree_skb(skb);
416
                return;
417
        }
418
 
419
        ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len);
420
 
421
        msg = (struct nd_msg *) skb_put(skb, len);
422
 
423
        msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
424
        msg->icmph.icmp6_code = 0;
425
        msg->icmph.icmp6_cksum = 0;
426
 
427
        msg->icmph.icmp6_unused = 0;
428
        msg->icmph.icmp6_router    = router;
429
        msg->icmph.icmp6_solicited = solicited;
430
        msg->icmph.icmp6_override  = !!override;
431
 
432
        /* Set the target address. */
433
        ipv6_addr_copy(&msg->target, solicited_addr);
434
 
435
        if (inc_opt)
436
                ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
437
 
438
        /* checksum */
439
        msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len,
440
                                                 IPPROTO_ICMPV6,
441
                                                 csum_partial((__u8 *) msg,
442
                                                              len, 0));
443
 
444
        dev_queue_xmit(skb);
445
 
446
        ICMP6_INC_STATS(Icmp6OutNeighborAdvertisements);
447
        ICMP6_INC_STATS(Icmp6OutMsgs);
448
}
449
 
450
void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
451
                   struct in6_addr *solicit,
452
                   struct in6_addr *daddr, struct in6_addr *saddr)
453
{
454
        struct sock *sk = ndisc_socket->sk;
455
        struct sk_buff *skb;
456
        struct nd_msg *msg;
457
        struct in6_addr addr_buf;
458
        int len;
459
        int err;
460
        int send_llinfo;
461
 
462
        if (saddr == NULL) {
463
                if (ipv6_get_lladdr(dev, &addr_buf))
464
                        return;
465
                saddr = &addr_buf;
466
        }
467
 
468
        len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
469
        send_llinfo = dev->addr_len && ipv6_addr_type(saddr) != IPV6_ADDR_ANY;
470
        if (send_llinfo)
471
                len += NDISC_OPT_SPACE(dev->addr_len);
472
 
473
        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
474
                                  1, &err);
475
        if (skb == NULL) {
476
                ND_PRINTK1("send_ns: alloc skb failed\n");
477
                return;
478
        }
479
 
480
        if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
481
                kfree_skb(skb);
482
                return;
483
        }
484
 
485
        ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
486
 
487
        msg = (struct nd_msg *)skb_put(skb, len);
488
        msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
489
        msg->icmph.icmp6_code = 0;
490
        msg->icmph.icmp6_cksum = 0;
491
        msg->icmph.icmp6_unused = 0;
492
 
493
        /* Set the target address. */
494
        ipv6_addr_copy(&msg->target, solicit);
495
 
496
        if (send_llinfo)
497
                ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
498
 
499
        /* checksum */
500
        msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
501
                                                 daddr, len,
502
                                                 IPPROTO_ICMPV6,
503
                                                 csum_partial((__u8 *) msg,
504
                                                              len, 0));
505
        /* send it! */
506
        dev_queue_xmit(skb);
507
 
508
        ICMP6_INC_STATS(Icmp6OutNeighborSolicits);
509
        ICMP6_INC_STATS(Icmp6OutMsgs);
510
}
511
 
512
void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
513
                   struct in6_addr *daddr)
514
{
515
        struct sock *sk = ndisc_socket->sk;
516
        struct sk_buff *skb;
517
        struct icmp6hdr *hdr;
518
        __u8 * opt;
519
        int len;
520
        int err;
521
 
522
        len = sizeof(struct icmp6hdr);
523
        if (dev->addr_len)
524
                len += NDISC_OPT_SPACE(dev->addr_len);
525
 
526
        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
527
                                  1, &err);
528
        if (skb == NULL) {
529
                ND_PRINTK1("send_ns: alloc skb failed\n");
530
                return;
531
        }
532
 
533
        if (ndisc_build_ll_hdr(skb, dev, daddr, NULL, len) == 0) {
534
                kfree_skb(skb);
535
                return;
536
        }
537
 
538
        ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
539
 
540
        hdr = (struct icmp6hdr *) skb_put(skb, len);
541
        hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
542
        hdr->icmp6_code = 0;
543
        hdr->icmp6_cksum = 0;
544
        hdr->icmp6_unused = 0;
545
 
546
        opt = (u8*) (hdr + 1);
547
 
548
        if (dev->addr_len)
549
                ndisc_fill_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
550
 
551
        /* checksum */
552
        hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
553
                                           IPPROTO_ICMPV6,
554
                                           csum_partial((__u8 *) hdr, len, 0));
555
 
556
        /* send it! */
557
        dev_queue_xmit(skb);
558
 
559
        ICMP6_INC_STATS(Icmp6OutRouterSolicits);
560
        ICMP6_INC_STATS(Icmp6OutMsgs);
561
}
562
 
563
 
564
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
565
{
566
        /*
567
         *      "The sender MUST return an ICMP
568
         *       destination unreachable"
569
         */
570
        dst_link_failure(skb);
571
        kfree_skb(skb);
572
}
573
 
574
/* Called with locked neigh: either read or both */
575
 
576
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
577
{
578
        struct in6_addr *saddr = NULL;
579
        struct in6_addr mcaddr;
580
        struct net_device *dev = neigh->dev;
581
        struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
582
        int probes = atomic_read(&neigh->probes);
583
 
584
        if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev))
585
                saddr = &skb->nh.ipv6h->saddr;
586
 
587
        if ((probes -= neigh->parms->ucast_probes) < 0) {
588
                if (!(neigh->nud_state&NUD_VALID))
589
                        ND_PRINTK1("trying to ucast probe in NUD_INVALID\n");
590
                ndisc_send_ns(dev, neigh, target, target, saddr);
591
        } else if ((probes -= neigh->parms->app_probes) < 0) {
592
#ifdef CONFIG_ARPD
593
                neigh_app_ns(neigh);
594
#endif
595
        } else {
596
                addrconf_addr_solict_mult(target, &mcaddr);
597
                ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
598
        }
599
}
600
 
601
void ndisc_recv_ns(struct sk_buff *skb)
602
{
603
        struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
604
        struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
605
        struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
606
        u8 *lladdr = NULL;
607
        int lladdrlen = 0;
608
        u32 ndoptlen = skb->tail - msg->opt;
609
        struct ndisc_options ndopts;
610
        struct net_device *dev = skb->dev;
611
        struct inet6_ifaddr *ifp;
612
        struct neighbour *neigh;
613
 
614
        if (skb->len < sizeof(struct nd_msg)) {
615
                if (net_ratelimit())
616
                        printk(KERN_WARNING "ICMP NS: packet too short\n");
617
                return;
618
        }
619
 
620
        if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
621
                if (net_ratelimit())
622
                        printk(KERN_WARNING "ICMP NS: target address is multicast\n");
623
                return;
624
        }
625
 
626
        if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
627
                if (net_ratelimit())
628
                        printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
629
                return;
630
        }
631
 
632
        if (ndopts.nd_opts_src_lladdr) {
633
                lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);
634
                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
635
                if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
636
                        if (net_ratelimit())
637
                                printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
638
                        return;
639
                }
640
        }
641
 
642
        /* XXX: RFC2461 7.1.1:
643
         *      If the IP source address is the unspecified address, there
644
         *      MUST NOT be source link-layer address option in the message.
645
         *
646
         *      NOTE! Linux kernel < 2.4.4 broke this rule.
647
         */
648
 
649
        /* XXX: RFC2461 7.1.1:
650
         *      If the IP source address is the unspecified address, the IP
651
         *      destination address MUST be a solicited-node multicast address.
652
         */
653
 
654
        if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
655
                int addr_type = ipv6_addr_type(saddr);
656
 
657
                if (ifp->flags & IFA_F_TENTATIVE) {
658
                        /* Address is tentative. If the source
659
                           is unspecified address, it is someone
660
                           does DAD, otherwise we ignore solicitations
661
                           until DAD timer expires.
662
                         */
663
                        if (addr_type == IPV6_ADDR_ANY) {
664
                                if (dev->type == ARPHRD_IEEE802_TR) {
665
                                        unsigned char *sadr = skb->mac.raw ;
666
                                        if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
667
                                        (sadr[9] != dev->dev_addr[1]) ||
668
                                        (sadr[10] != dev->dev_addr[2]) ||
669
                                        (sadr[11] != dev->dev_addr[3]) ||
670
                                        (sadr[12] != dev->dev_addr[4]) ||
671
                                        (sadr[13] != dev->dev_addr[5]))
672
                                        {
673
                                                addrconf_dad_failure(ifp) ;
674
                                        }
675
                                } else {
676
                                        addrconf_dad_failure(ifp);
677
                                }
678
                        } else
679
                                in6_ifa_put(ifp);
680
                        return;
681
                }
682
 
683
                if (addr_type == IPV6_ADDR_ANY) {
684
                        struct in6_addr maddr;
685
 
686
                        ipv6_addr_all_nodes(&maddr);
687
                        ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
688
                                      ifp->idev->cnf.forwarding, 0,
689
                                      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
690
                                      1);
691
                        in6_ifa_put(ifp);
692
                        return;
693
                }
694
 
695
                if (addr_type & IPV6_ADDR_UNICAST) {
696
                        int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
697
 
698
                        if (inc)
699
                                nd_tbl.stats.rcv_probes_mcast++;
700
                        else
701
                                nd_tbl.stats.rcv_probes_ucast++;
702
 
703
                        /*
704
                         *      update / create cache entry
705
                         *      for the source adddress
706
                         */
707
 
708
                        neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
709
 
710
                        if (neigh || !dev->hard_header) {
711
                                ndisc_send_na(dev, neigh, saddr, &ifp->addr,
712
                                              ifp->idev->cnf.forwarding, 1,
713
                                              ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
714
                                              1);
715
                                if (neigh)
716
                                        neigh_release(neigh);
717
                        }
718
                }
719
                in6_ifa_put(ifp);
720
        } else if (ipv6_chk_acast_addr(dev, &msg->target)) {
721
                struct inet6_dev *idev = in6_dev_get(dev);
722
                int addr_type = ipv6_addr_type(saddr);
723
 
724
                /* anycast */
725
 
726
                if (!idev) {
727
                        /* XXX: count this drop? */
728
                        return;
729
                }
730
 
731
                if (addr_type == IPV6_ADDR_ANY) {
732
                        struct in6_addr maddr;
733
 
734
                        ipv6_addr_all_nodes(&maddr);
735
                        ndisc_send_na(dev, NULL, &maddr, &msg->target,
736
                                      idev->cnf.forwarding, 0, 0, 1);
737
                        in6_dev_put(idev);
738
                        return;
739
                }
740
 
741
                if (addr_type & IPV6_ADDR_UNICAST) {
742
                        int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
743
                        if (inc)
744
                                nd_tbl.stats.rcv_probes_mcast++;
745
                        else
746
                                nd_tbl.stats.rcv_probes_ucast++;
747
 
748
                        /*
749
                         *   update / create cache entry
750
                         *   for the source adddress
751
                         */
752
 
753
                        neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
754
 
755
                        if (neigh || !dev->hard_header) {
756
                                ndisc_send_na(dev, neigh, saddr,
757
                                        &msg->target,
758
                                        idev->cnf.forwarding, 1, 0, inc);
759
                                if (neigh)
760
                                        neigh_release(neigh);
761
                        }
762
                }
763
                in6_dev_put(idev);
764
        } else {
765
                struct inet6_dev *in6_dev = in6_dev_get(dev);
766
                int addr_type = ipv6_addr_type(saddr);
767
 
768
                if (in6_dev && in6_dev->cnf.forwarding &&
769
                    (addr_type & IPV6_ADDR_UNICAST) &&
770
                    pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
771
                        int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
772
 
773
                        if (skb->stamp.tv_sec == 0 ||
774
                            skb->pkt_type == PACKET_HOST ||
775
                            inc == 0 ||
776
                            in6_dev->nd_parms->proxy_delay == 0) {
777
                                if (inc)
778
                                        nd_tbl.stats.rcv_probes_mcast++;
779
                                else
780
                                        nd_tbl.stats.rcv_probes_ucast++;
781
 
782
                                neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
783
 
784
                                if (neigh) {
785
                                        ndisc_send_na(dev, neigh, saddr, &msg->target,
786
                                                      0, 1, 0, 1);
787
                                        neigh_release(neigh);
788
                                }
789
                        } else {
790
                                struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
791
                                if (n)
792
                                        pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
793
                                in6_dev_put(in6_dev);
794
                                return;
795
                        }
796
                }
797
                if (in6_dev)
798
                        in6_dev_put(in6_dev);
799
        }
800
        return;
801
}
802
 
803
void ndisc_recv_na(struct sk_buff *skb)
804
{
805
        struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
806
        struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
807
        struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
808
        u8 *lladdr = NULL;
809
        int lladdrlen = 0;
810
        u32 ndoptlen = skb->tail - msg->opt;
811
        struct ndisc_options ndopts;
812
        struct net_device *dev = skb->dev;
813
        struct inet6_ifaddr *ifp;
814
        struct neighbour *neigh;
815
 
816
        if (skb->len < sizeof(struct nd_msg)) {
817
                if (net_ratelimit())
818
                        printk(KERN_WARNING "ICMP NA: packet too short\n");
819
                return;
820
        }
821
 
822
        if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
823
                if (net_ratelimit())
824
                        printk(KERN_WARNING "NDISC NA: target address is multicast\n");
825
                return;
826
        }
827
 
828
        if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
829
            msg->icmph.icmp6_solicited) {
830
                ND_PRINTK0("NDISC: solicited NA is multicasted\n");
831
                return;
832
        }
833
 
834
        if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
835
                if (net_ratelimit())
836
                        printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
837
                return;
838
        }
839
        if (ndopts.nd_opts_tgt_lladdr) {
840
                lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
841
                lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
842
                if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
843
                        if (net_ratelimit())
844
                                printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
845
                        return;
846
                }
847
        }
848
        if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
849
                if (ifp->flags & IFA_F_TENTATIVE) {
850
                        addrconf_dad_failure(ifp);
851
                        return;
852
                }
853
                /* What should we make now? The advertisement
854
                   is invalid, but ndisc specs say nothing
855
                   about it. It could be misconfiguration, or
856
                   an smart proxy agent tries to help us :-)
857
                 */
858
                ND_PRINTK0("%s: someone advertises our address!\n",
859
                           ifp->idev->dev->name);
860
                in6_ifa_put(ifp);
861
                return;
862
        }
863
        neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
864
 
865
        if (neigh) {
866
                if (neigh->flags & NTF_ROUTER) {
867
                        if (msg->icmph.icmp6_router == 0) {
868
                                /*
869
                                 *      Change: router to host
870
                                 */
871
                                struct rt6_info *rt;
872
                                rt = rt6_get_dflt_router(saddr, dev);
873
                                if (rt) {
874
                                        /* It is safe only because
875
                                           we aer in BH */
876
                                        dst_release(&rt->u.dst);
877
                                        ip6_del_rt(rt, NULL);
878
                                }
879
                        }
880
                } else {
881
                        if (msg->icmph.icmp6_router)
882
                                neigh->flags |= NTF_ROUTER;
883
                }
884
 
885
                neigh_update(neigh, lladdr,
886
                             msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
887
                             msg->icmph.icmp6_override, 1);
888
                neigh_release(neigh);
889
        }
890
}
891
 
892
static void ndisc_router_discovery(struct sk_buff *skb)
893
{
894
        struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
895
        struct neighbour *neigh;
896
        struct inet6_dev *in6_dev;
897
        struct rt6_info *rt;
898
        int lifetime;
899
        struct ndisc_options ndopts;
900
        int optlen;
901
 
902
        __u8 * opt = (__u8 *)(ra_msg + 1);
903
 
904
        optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);
905
 
906
        if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
907
                if (net_ratelimit())
908
                        printk(KERN_WARNING "ICMP RA: source address is not linklocal\n");
909
                return;
910
        }
911
        if (optlen < 0) {
912
                if (net_ratelimit())
913
                        printk(KERN_WARNING "ICMP RA: packet too short\n");
914
                return;
915
        }
916
 
917
        /*
918
         *      set the RA_RECV flag in the interface
919
         */
920
 
921
        in6_dev = in6_dev_get(skb->dev);
922
        if (in6_dev == NULL) {
923
                ND_PRINTK1("RA: can't find in6 device\n");
924
                return;
925
        }
926
        if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
927
                in6_dev_put(in6_dev);
928
                return;
929
        }
930
 
931
        if (!ndisc_parse_options(opt, optlen, &ndopts)) {
932
                in6_dev_put(in6_dev);
933
                if (net_ratelimit())
934
                        ND_PRINTK2(KERN_WARNING
935
                                   "ICMP6 RA: invalid ND option, ignored.\n");
936
                return;
937
        }
938
 
939
        if (in6_dev->if_flags & IF_RS_SENT) {
940
                /*
941
                 *      flag that an RA was received after an RS was sent
942
                 *      out on this interface.
943
                 */
944
                in6_dev->if_flags |= IF_RA_RCVD;
945
        }
946
 
947
        /*
948
         * Remember the managed/otherconf flags from most recently
949
         * received RA message (RFC 2462) -- yoshfuji
950
         */
951
        in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
952
                                IF_RA_OTHERCONF)) |
953
                                (ra_msg->icmph.icmp6_addrconf_managed ?
954
                                        IF_RA_MANAGED : 0) |
955
                                (ra_msg->icmph.icmp6_addrconf_other ?
956
                                        IF_RA_OTHERCONF : 0);
957
 
958
        lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
959
 
960
        rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
961
 
962
        if (rt && lifetime == 0) {
963
                ip6_del_rt(rt, NULL);
964
                rt = NULL;
965
        }
966
 
967
        if (rt == NULL && lifetime) {
968
                ND_PRINTK2("ndisc_rdisc: adding default router\n");
969
 
970
                rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
971
                if (rt == NULL) {
972
                        ND_PRINTK1("route_add failed\n");
973
                        in6_dev_put(in6_dev);
974
                        return;
975
                }
976
 
977
                neigh = rt->rt6i_nexthop;
978
                if (neigh == NULL) {
979
                        ND_PRINTK1("nd: add default router: null neighbour\n");
980
                        dst_release(&rt->u.dst);
981
                        in6_dev_put(in6_dev);
982
                        return;
983
                }
984
                neigh->flags |= NTF_ROUTER;
985
 
986
                /*
987
                 *      If we where using an "all destinations on link" route
988
                 *      delete it
989
                 */
990
 
991
                rt6_purge_dflt_routers(RTF_ALLONLINK);
992
        }
993
 
994
        if (rt)
995
                rt->rt6i_expires = jiffies + (HZ * lifetime);
996
 
997
        if (ra_msg->icmph.icmp6_hop_limit)
998
                in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
999
 
1000
        /*
1001
         *      Update Reachable Time and Retrans Timer
1002
         */
1003
 
1004
        if (in6_dev->nd_parms) {
1005
                unsigned long rtime = ntohl(ra_msg->retrans_timer);
1006
 
1007
                if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1008
                        rtime = (rtime*HZ)/1000;
1009
                        if (rtime < HZ/10)
1010
                                rtime = HZ/10;
1011
                        in6_dev->nd_parms->retrans_time = rtime;
1012
                }
1013
 
1014
                rtime = ntohl(ra_msg->reachable_time);
1015
                if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1016
                        rtime = (rtime*HZ)/1000;
1017
 
1018
                        if (rtime < HZ/10)
1019
                                rtime = HZ/10;
1020
 
1021
                        if (rtime != in6_dev->nd_parms->base_reachable_time) {
1022
                                in6_dev->nd_parms->base_reachable_time = rtime;
1023
                                in6_dev->nd_parms->gc_staletime = 3 * rtime;
1024
                                in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1025
                        }
1026
                }
1027
        }
1028
 
1029
        /*
1030
         *      Process options.
1031
         */
1032
 
1033
        if (rt && (neigh = rt->rt6i_nexthop) != NULL) {
1034
                u8 *lladdr = NULL;
1035
                int lladdrlen;
1036
                if (ndopts.nd_opts_src_lladdr) {
1037
                        lladdr = (u8*)((ndopts.nd_opts_src_lladdr)+1);
1038
                        lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
1039
                        if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
1040
                                if (net_ratelimit())
1041
                                        ND_PRINTK2(KERN_WARNING
1042
                                                   "ICMP6 RA: Invalid lladdr length.\n");
1043
                                goto out;
1044
                        }
1045
                }
1046
                neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
1047
        }
1048
 
1049
        if (ndopts.nd_opts_pi) {
1050
                struct nd_opt_hdr *p;
1051
                for (p = ndopts.nd_opts_pi;
1052
                     p;
1053
                     p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
1054
                        addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3);
1055
                }
1056
        }
1057
 
1058
        if (ndopts.nd_opts_mtu) {
1059
                u32 mtu;
1060
 
1061
                memcpy(&mtu, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1062
                mtu = ntohl(mtu);
1063
 
1064
                if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
1065
                        if (net_ratelimit()) {
1066
                                ND_PRINTK0("NDISC: router announcement with mtu = %d\n",
1067
                                           mtu);
1068
                        }
1069
                }
1070
 
1071
                if (in6_dev->cnf.mtu6 != mtu) {
1072
                        in6_dev->cnf.mtu6 = mtu;
1073
 
1074
                        if (rt)
1075
                                rt->u.dst.pmtu = mtu;
1076
 
1077
                        rt6_mtu_change(skb->dev, mtu);
1078
                }
1079
        }
1080
 
1081
        if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
1082
                if (net_ratelimit())
1083
                        ND_PRINTK0(KERN_WARNING
1084
                                   "ICMP6 RA: got illegal option with RA");
1085
        }
1086
out:
1087
        if (rt)
1088
                dst_release(&rt->u.dst);
1089
        in6_dev_put(in6_dev);
1090
}
1091
 
1092
static void ndisc_redirect_rcv(struct sk_buff *skb)
1093
{
1094
        struct inet6_dev *in6_dev;
1095
        struct icmp6hdr *icmph;
1096
        struct in6_addr *dest;
1097
        struct in6_addr *target;        /* new first hop to destination */
1098
        struct neighbour *neigh;
1099
        int on_link = 0;
1100
        struct ndisc_options ndopts;
1101
        int optlen;
1102
        u8 *lladdr = NULL;
1103
        int lladdrlen;
1104
 
1105
        if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
1106
                if (net_ratelimit())
1107
                        printk(KERN_WARNING "ICMP redirect: source address is not linklocal\n");
1108
                return;
1109
        }
1110
 
1111
        optlen = skb->tail - skb->h.raw;
1112
        optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1113
 
1114
        if (optlen < 0) {
1115
                if (net_ratelimit())
1116
                        printk(KERN_WARNING "ICMP redirect: packet too small\n");
1117
                return;
1118
        }
1119
 
1120
        icmph = (struct icmp6hdr *) skb->h.raw;
1121
        target = (struct in6_addr *) (icmph + 1);
1122
        dest = target + 1;
1123
 
1124
        if (ipv6_addr_type(dest) & IPV6_ADDR_MULTICAST) {
1125
                if (net_ratelimit())
1126
                        printk(KERN_WARNING "ICMP redirect for multicast addr\n");
1127
                return;
1128
        }
1129
 
1130
        if (ipv6_addr_cmp(dest, target) == 0) {
1131
                on_link = 1;
1132
        } else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
1133
                if (net_ratelimit())
1134
                        printk(KERN_WARNING "ICMP redirect: target address is not linklocal\n");
1135
                return;
1136
        }
1137
 
1138
        in6_dev = in6_dev_get(skb->dev);
1139
        if (!in6_dev)
1140
                return;
1141
        if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
1142
                in6_dev_put(in6_dev);
1143
                return;
1144
        }
1145
 
1146
        /* XXX: RFC2461 8.1:
1147
         *      The IP source address of the Redirect MUST be the same as the current
1148
         *      first-hop router for the specified ICMP Destination Address.
1149
         */
1150
 
1151
        if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
1152
                if (net_ratelimit())
1153
                        ND_PRINTK2(KERN_WARNING
1154
                                   "ICMP6 Redirect: invalid ND options, rejected.\n");
1155
                in6_dev_put(in6_dev);
1156
                return;
1157
        }
1158
        if (ndopts.nd_opts_tgt_lladdr) {
1159
                lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
1160
                lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
1161
                if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
1162
                        if (net_ratelimit())
1163
                                ND_PRINTK2(KERN_WARNING
1164
                                           "ICMP6 Redirect: invalid lladdr length.\n");
1165
                        in6_dev_put(in6_dev);
1166
                        return;
1167
                }
1168
        }
1169
        /* passed validation tests */
1170
 
1171
        /*
1172
           We install redirect only if nexthop state is valid.
1173
         */
1174
 
1175
        neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
1176
        if (neigh) {
1177
                neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
1178
                if (neigh->nud_state&NUD_VALID)
1179
                        rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link);
1180
                else
1181
                        __neigh_event_send(neigh, NULL);
1182
                neigh_release(neigh);
1183
        }
1184
        in6_dev_put(in6_dev);
1185
}
1186
 
1187
void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1188
                         struct in6_addr *target)
1189
{
1190
        struct sock *sk = ndisc_socket->sk;
1191
        int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1192
        struct sk_buff *buff;
1193
        struct icmp6hdr *icmph;
1194
        struct in6_addr saddr_buf;
1195
        struct in6_addr *addrp;
1196
        struct net_device *dev;
1197
        struct rt6_info *rt;
1198
        u8 *opt;
1199
        int rd_len;
1200
        int err;
1201
        int hlen;
1202
 
1203
        dev = skb->dev;
1204
        rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
1205
 
1206
        if (rt == NULL)
1207
                return;
1208
 
1209
        if (rt->rt6i_flags & RTF_GATEWAY) {
1210
                ND_PRINTK1("ndisc_send_redirect: not a neighbour\n");
1211
                dst_release(&rt->u.dst);
1212
                return;
1213
        }
1214
        if (!xrlim_allow(&rt->u.dst, 1*HZ)) {
1215
                dst_release(&rt->u.dst);
1216
                return;
1217
        }
1218
        dst_release(&rt->u.dst);
1219
 
1220
        if (dev->addr_len) {
1221
                if (neigh->nud_state&NUD_VALID) {
1222
                        len  += NDISC_OPT_SPACE(dev->addr_len);
1223
                } else {
1224
                        /* If nexthop is not valid, do not redirect!
1225
                           We will make it later, when will be sure,
1226
                           that it is alive.
1227
                         */
1228
                        return;
1229
                }
1230
        }
1231
 
1232
        rd_len = min_t(unsigned int,
1233
                     IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
1234
        rd_len &= ~0x7;
1235
        len += rd_len;
1236
 
1237
        if (ipv6_get_lladdr(dev, &saddr_buf)) {
1238
                ND_PRINTK1("redirect: no link_local addr for dev\n");
1239
                return;
1240
        }
1241
 
1242
        buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
1243
                                   1, &err);
1244
        if (buff == NULL) {
1245
                ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n");
1246
                return;
1247
        }
1248
 
1249
        hlen = 0;
1250
 
1251
        if (ndisc_build_ll_hdr(buff, dev, &skb->nh.ipv6h->saddr, NULL, len) == 0) {
1252
                kfree_skb(buff);
1253
                return;
1254
        }
1255
 
1256
        ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr,
1257
                   IPPROTO_ICMPV6, len);
1258
 
1259
        icmph = (struct icmp6hdr *) skb_put(buff, len);
1260
 
1261
        memset(icmph, 0, sizeof(struct icmp6hdr));
1262
        icmph->icmp6_type = NDISC_REDIRECT;
1263
 
1264
        /*
1265
         *      copy target and destination addresses
1266
         */
1267
 
1268
        addrp = (struct in6_addr *)(icmph + 1);
1269
        ipv6_addr_copy(addrp, target);
1270
        addrp++;
1271
        ipv6_addr_copy(addrp, &skb->nh.ipv6h->daddr);
1272
 
1273
        opt = (u8*) (addrp + 1);
1274
 
1275
        /*
1276
         *      include target_address option
1277
         */
1278
 
1279
        if (dev->addr_len)
1280
                opt = ndisc_fill_option(opt, ND_OPT_TARGET_LL_ADDR, neigh->ha, dev->addr_len);
1281
 
1282
        /*
1283
         *      build redirect option and copy skb over to the new packet.
1284
         */
1285
 
1286
        memset(opt, 0, 8);
1287
        *(opt++) = ND_OPT_REDIRECT_HDR;
1288
        *(opt++) = (rd_len >> 3);
1289
        opt += 6;
1290
 
1291
        memcpy(opt, skb->nh.ipv6h, rd_len - 8);
1292
 
1293
        icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &skb->nh.ipv6h->saddr,
1294
                                             len, IPPROTO_ICMPV6,
1295
                                             csum_partial((u8 *) icmph, len, 0));
1296
 
1297
        dev_queue_xmit(buff);
1298
 
1299
        ICMP6_INC_STATS(Icmp6OutRedirects);
1300
        ICMP6_INC_STATS(Icmp6OutMsgs);
1301
}
1302
 
1303
static void pndisc_redo(struct sk_buff *skb)
1304
{
1305
        ndisc_rcv(skb);
1306
        kfree_skb(skb);
1307
}
1308
 
1309
int ndisc_rcv(struct sk_buff *skb)
1310
{
1311
        struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
1312
 
1313
        __skb_push(skb, skb->data-skb->h.raw);
1314
 
1315
        if (skb->nh.ipv6h->hop_limit != 255) {
1316
                if (net_ratelimit())
1317
                        printk(KERN_WARNING
1318
                               "ICMP NDISC: fake message with non-255 Hop Limit received: %d\n",
1319
                                        skb->nh.ipv6h->hop_limit);
1320
                return 0;
1321
        }
1322
 
1323
        if (msg->icmph.icmp6_code != 0) {
1324
                if (net_ratelimit())
1325
                        printk(KERN_WARNING "ICMP NDISC: code is not zero\n");
1326
                return 0;
1327
        }
1328
 
1329
        switch (msg->icmph.icmp6_type) {
1330
        case NDISC_NEIGHBOUR_SOLICITATION:
1331
                ndisc_recv_ns(skb);
1332
                break;
1333
 
1334
        case NDISC_NEIGHBOUR_ADVERTISEMENT:
1335
                ndisc_recv_na(skb);
1336
                break;
1337
 
1338
        case NDISC_ROUTER_ADVERTISEMENT:
1339
                ndisc_router_discovery(skb);
1340
                break;
1341
 
1342
        case NDISC_REDIRECT:
1343
                ndisc_redirect_rcv(skb);
1344
                break;
1345
        };
1346
 
1347
        return 0;
1348
}
1349
 
1350
static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1351
{
1352
        struct net_device *dev = ptr;
1353
 
1354
        switch (event) {
1355
        case NETDEV_CHANGEADDR:
1356
                neigh_changeaddr(&nd_tbl, dev);
1357
                fib6_run_gc(0);
1358
                break;
1359
        default:
1360
                break;
1361
        }
1362
 
1363
        return NOTIFY_DONE;
1364
}
1365
 
1366
struct notifier_block ndisc_netdev_notifier = {
1367
        .notifier_call = ndisc_netdev_event,
1368
};
1369
 
1370
int __init ndisc_init(struct net_proto_family *ops)
1371
{
1372
        struct sock *sk;
1373
        int err;
1374
 
1375
        ndisc_socket = sock_alloc();
1376
        if (ndisc_socket == NULL) {
1377
                printk(KERN_ERR
1378
                       "Failed to create the NDISC control socket.\n");
1379
                return -1;
1380
        }
1381
        ndisc_socket->inode->i_uid = 0;
1382
        ndisc_socket->inode->i_gid = 0;
1383
        ndisc_socket->type = SOCK_RAW;
1384
 
1385
        if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) {
1386
                printk(KERN_DEBUG
1387
                       "Failed to initialize the NDISC control socket (err %d).\n",
1388
                       err);
1389
                sock_release(ndisc_socket);
1390
                ndisc_socket = NULL; /* For safety. */
1391
                return err;
1392
        }
1393
 
1394
        sk = ndisc_socket->sk;
1395
        sk->allocation = GFP_ATOMIC;
1396
        sk->net_pinfo.af_inet6.hop_limit = 255;
1397
        /* Do not loopback ndisc messages */
1398
        sk->net_pinfo.af_inet6.mc_loop = 0;
1399
        sk->prot->unhash(sk);
1400
 
1401
        /*
1402
         * Initialize the neighbour table
1403
         */
1404
 
1405
        neigh_table_init(&nd_tbl);
1406
 
1407
#ifdef CONFIG_SYSCTL
1408
        neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
1409
#endif
1410
 
1411
        register_netdevice_notifier(&ndisc_netdev_notifier);
1412
        return 0;
1413
}
1414
 
1415
void ndisc_cleanup(void)
1416
{
1417
        neigh_table_clear(&nd_tbl);
1418
        sock_release(ndisc_socket);
1419
        ndisc_socket = NULL; /* For safety. */
1420
}

powered by: WebSVN 2.1.0

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