~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv6/ndisc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.