Two swsusp patches:
[linux-flexiantxendom0-3.2.10.git] / net / ipv6 / mobile_ip6 / mdetect.c
1 /*
2  *      Movement Detection Module
3  *
4  *      Authors:
5  *      Henrik Petander                <lpetande@cc.hut.fi>
6  *
7  *      $Id: s.mdetect.c 1.135 03/10/02 15:26:27+03:00 henkku@mart10.hut.mediapoli.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  *      Handles the L3 movement detection of mobile node and also
15  *      changing of its routes.
16  *  
17  */
18
19 /*
20  *      Changes:
21  *
22  *      Nanno Langstraat        :       Locking fixes
23  *      Venkata Jagana          :       Locking fix
24  */
25
26 #include <linux/autoconf.h>
27 #include <linux/errno.h>
28 #include <linux/init.h>
29 #include <linux/if_arp.h>
30 #include <linux/route.h>
31 #include <net/ipv6.h>
32 #include <net/ip6_route.h>
33 #include <net/addrconf.h>
34 #include <net/mipglue.h>
35 #ifdef CONFIG_SYSCTL
36 #include <linux/sysctl.h>
37 #endif /* CONFIG_SYSCTL */
38
39 #include "util.h"
40 #include "mdetect.h"
41 #include "mn.h"
42 #include "debug.h"
43 #include "multiaccess_ctl.h"
44
45 #define START 0
46 #define CONTINUE 1
47 #define OK 2
48 #define DEBUG_MDETECT 7
49
50 #define DEF_RTR_POLL_IVAL RTR_SOLICITATION_INTERVAL /* In seconds */
51
52 /* States */
53 #define CURR_RTR_PRESENT        0
54 #define CURR_RTR_NOT_PRESENT    1
55 #define STOP_RTR_PROBE          2
56
57 /* Events */
58 #define RA_RCVD                 0
59 #define RA_TIMEOUT              1
60
61 #define MIPV6_MDF_NONE 0x0
62 #define MIPV6_MDF_HAS_RTR_PREV 0x1
63
64 #define ROUTER_REACHABLE 1
65 #define RADV_MISSED 2
66 #define NOT_REACHABLE 3
67
68 /* R_TIME_OUT paramater is used to make the decision when to change the 
69  * default  router, if the current one is unreachable. 2s is pretty aggressive 
70  * and may result in hopping between two routers. OTOH a small value enhances 
71  * the  performance
72  */
73 #define R_TIME_OUT 30*HZ
74
75 /* maximum RA interval for router unreachability detection */
76 #define MAX_RADV_INTERVAL 6000*HZ  /* 6000 ms... */
77
78 /* Threshold for exponential resending of router solicitations */
79 #define RS_RESEND_LINEAR 10*HZ
80
81 #define EAGER_CELL_SWITCHING 1
82 #define LAZY_CELL_SWITCHING 0
83 #define RESPECT_DAD 1
84
85 #define ROUTER_ADDRESS 0x20
86
87 /* RA flags */
88 #define ND_RA_FLAG_MANAGED  0x80
89 #define ND_RA_FLAG_OTHER    0x40
90 #define ND_RA_FLAG_HA       0x20
91 /* Care-of address */
92 #define COA_TENTATIVE       0x10
93
94 struct router {
95         struct list_head list;
96         struct in6_addr ll_addr;
97         struct in6_addr raddr; /* Also contains prefix */
98         __u8 link_addr[MAX_ADDR_LEN]; /* link layer address */
99         __u8 link_addr_len;
100         __u8 state;
101         __u8 is_current;
102         int ifindex;
103         int pfix_len; /* Length of the network prefix */
104         unsigned long lifetime; /* from ra */
105         __u32 last_ns_sent; 
106         __u32 last_ra_rcvd;
107         __u32 interval; /* ra interval in milliseconds, 0 if not set */ 
108         int glob_addr; /*Whether raddr contains also routers global address*/
109         __u8 flags; /* RA flags, for example ha */
110         struct in6_addr CoA;     /* care-off address used with this router */
111         int extra_addr_route;
112 };
113
114 /* dad could also be RESPECT_DAD for duplicate address detection of
115    new care-of addresses */
116 static int dad = 0;
117
118 /* Only one choice, nothing else implemented */
119 int max_rtr_reach_time = DEF_RTR_POLL_IVAL;
120 int mdet_mech = EAGER_CELL_SWITCHING; 
121
122 int eager_cell_switching = 1;  /* This can't be set from anywhere for now */
123 static spinlock_t router_lock; 
124 static spinlock_t ho_lock;
125
126 static void coa_timer_handler(unsigned long arg);
127 static void timer_handler(unsigned long foo);
128 static struct router *curr_router = NULL, *next_router = NULL;
129 static struct timer_list r_timer = { function: timer_handler };
130 static struct timer_list coa_timer = { function: coa_timer_handler };
131 #define MAX_ROUTERS 1000
132 static LIST_HEAD(rtr_list);
133 static int num_routers = 0;
134 static struct handoff *_ho = NULL;
135 /*
136  * Functions for handling the default router list, which movement
137  * detection uses for avoiding loops etc.
138  */
139
140 /* TODO: Send NS to router after MAX interval has passed from last RA */
141 static int mipv6_router_state(struct router *rtr)
142 {
143         if (rtr->interval) {
144                 if (time_before(jiffies, (unsigned long)(rtr->last_ra_rcvd + (rtr->interval * HZ) / 1000)))
145                         return ROUTER_REACHABLE;
146                 else
147                         return NOT_REACHABLE;
148         }
149         else
150                 if (time_after(jiffies, (unsigned long)(rtr->last_ra_rcvd + (rtr->lifetime * HZ))))
151                         return NOT_REACHABLE;
152         return ROUTER_REACHABLE;
153 }
154
155 /* searches for a specific router or any router that is reachable, 
156  * if address is NULL. Also deletes obsolete routers.
157  */
158 static void mipv6_router_gc(void)
159 {
160         struct router *curr = NULL;
161         struct list_head *lh, *lh_tmp;
162
163         DEBUG_FUNC();
164
165         list_for_each_safe(lh, lh_tmp, &rtr_list) {
166                 curr =  list_entry(lh, struct router, list);
167                 if (mipv6_router_state(curr) == NOT_REACHABLE && !curr->is_current) {
168                         num_routers--;
169                         list_del_init(&curr->list);
170                         DEBUG(DBG_DATADUMP, "Deleting unreachable router  %x:%x:%x:%x:%x:%x:%x:%x", 
171                               NIPV6ADDR(&curr->raddr));
172                         kfree(curr);
173                 }
174                 else {
175                         DEBUG(DBG_DATADUMP, "NOT Deleting router  %x:%x:%x:%x:%x:%x:%x:%x", 
176                               NIPV6ADDR(&curr->raddr));
177                 }
178         }
179 }
180
181 static struct router *mipv6_rtr_get(struct in6_addr *search_addr)
182 {
183         struct router *rtr = NULL;
184         struct list_head *lh;
185
186         DEBUG_FUNC();
187
188         if (search_addr == NULL)
189                 return NULL;
190         list_for_each(lh, &rtr_list) {
191                 rtr = list_entry(lh, struct router, list);
192                 if(!ipv6_addr_cmp(search_addr, &rtr->raddr)) {
193                         return rtr;
194                 }
195         }
196         return NULL;
197 }
198
199 /*
200  * Adds router to list
201  */
202 static struct router *mipv6_rtr_add(struct router *nrt)
203 {
204
205         struct router *rptr;
206
207         DEBUG_FUNC();
208
209         /* check if someone is trying DoS attack, or we just have some
210            memory leaks... */
211         if (num_routers > MAX_ROUTERS) {
212                 DEBUG(DBG_CRITICAL, 
213                       "failed to add new router, MAX_ROUTERS exceeded");
214                 return NULL;
215         }
216         
217         rptr = kmalloc(sizeof(struct router), GFP_ATOMIC);
218         if (rptr) {
219                 memcpy(rptr, nrt, sizeof(struct router));
220                 list_add(&rptr->list, &rtr_list);
221                 num_routers++;
222         }
223         DEBUG(DBG_INFO, "Adding router: %x:%x:%x:%x:%x:%x:%x:%x, "
224               "lifetime : %d sec, adv.interval: %d millisec", 
225               NIPV6ADDR(&rptr->raddr), rptr->lifetime, rptr->interval);
226
227         DEBUG(DBG_INFO, "num_routers after addition: %d", num_routers);
228         return rptr;
229 }
230
231 /* Cleans up the list */
232 static void list_free(struct router **curr_router_p)
233 {
234         struct router *tmp;
235         struct list_head *lh, *lh_tmp;
236
237         DEBUG_FUNC();
238
239         DEBUG(DBG_INFO, "Freeing the router list");
240         /* set curr_router->prev_router and curr_router NULL */
241         *curr_router_p = NULL;
242         list_for_each_safe(lh, lh_tmp, &rtr_list) {
243                 tmp = list_entry(lh, struct router, list);
244                 DEBUG(DBG_INFO, "%x:%x:%x:%x:%x:%x:%x:%x",
245                       NIPV6ADDR(&tmp->ll_addr));
246                 list_del(&tmp->list);
247                 kfree(tmp);
248                 num_routers--;
249         }
250 }
251
252 int rs_state = START;
253
254 /* Sends router solicitations to all valid devices 
255  * source  = link local address (of sending interface)
256  * dstaddr = all routers multicast address
257  * Solicitations are sent at an exponentially decreasing rate
258  *
259  * TODO: send solicitation first at a normal rate (from ipv6) and
260  *       after that use the exponentially increasing intervals 
261  */
262 static int rs_send(void)
263 {
264         struct net_device *dev;
265         struct in6_addr raddr, lladdr;
266         struct inet6_dev *in6_dev = NULL;
267         static int num_rs;
268
269         if (rs_state == START) {
270                 num_rs = 0;
271                 rs_state = CONTINUE;
272         } else if (num_rs++ > MAX_RTR_SOLICITATIONS)
273                 return HZ;
274
275         ipv6_addr_all_routers(&raddr);
276         read_lock(&dev_base_lock); 
277
278         /*  Send router solicitations to all interfaces  */
279         for (dev = dev_base; dev; dev = dev->next) {
280                 if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) {
281                         DEBUG(DBG_DATADUMP, "Sending RS to device %s", 
282                               dev->name);
283                         if (!ipv6_get_lladdr(dev, &lladdr)) {
284                                 ndisc_send_rs(dev, &lladdr, &raddr);
285                                 in6_dev = in6_dev_get(dev);
286                                 in6_dev->if_flags |= IF_RS_SENT;
287                                 in6_dev_put(in6_dev);
288                         } else {
289                                 DEBUG(DBG_DATADUMP, "%s: device doesn't have link-local address!\n", dev->name);
290                                 continue;
291                         }
292                 }
293                 
294         }
295         read_unlock(&dev_base_lock);
296         return RTR_SOLICITATION_INTERVAL;
297 }
298
299 /* Create a new CoA for MN and also add a route to it if it is still tentative 
300    to allow MN to get packets to the address immediately
301  */
302 static int form_coa(struct in6_addr *coa, struct in6_addr *pfix, 
303                     int plen, int ifindex)
304 {
305         struct net_device *dev;
306         int ret = 0;
307
308         if ((dev = dev_get_by_index(ifindex)) == NULL) {
309                 DEBUG(DBG_WARNING, "Device is not present");
310                 return -1;
311         }
312         if (ipv6_get_lladdr(dev, coa) != 0) /* Link local address still tentative */
313                 ret = -1;
314         coa->s6_addr32[0] = pfix->s6_addr32[0];
315         coa->s6_addr32[1] = pfix->s6_addr32[1];
316         
317         if (ipv6_chk_addr(coa, dev, 0) == 0) { 
318                 DEBUG(DBG_WARNING, "care-of address still tentative");
319                 ret = 1;
320         } 
321
322         dev_put(dev);
323         DEBUG(DBG_INFO, "Formed new CoA:  %x:%x:%x:%x:%x:%x:%x:%x",
324               NIPV6ADDR(coa));
325         return ret;
326 }
327
328 static inline int rtr_is_gw(struct router *rtr, struct rt6_info *rt) 
329 {
330         return ((rt->rt6i_flags & RTF_GATEWAY) && 
331                 !ipv6_addr_cmp(&rt->rt6i_gateway, &rtr->ll_addr));
332 }
333
334 static inline int is_prefix_route(struct router *rtr, struct rt6_info *rt) 
335 {
336         return (!(rt->rt6i_flags & RTF_GATEWAY) &&
337                 mipv6_prefix_compare(&rt->rt6i_dst.addr, &rtr->raddr, 
338                                      rtr->pfix_len));
339 }
340
341 /*
342  * Function that determines whether given rt6_info should be destroyed
343  * (negative => destroy rt6_info, zero or positive => do nothing) 
344  */
345 static int mn_route_cleaner(struct rt6_info *rt, void *arg)
346 {
347         int type;
348
349         struct router *rtr = (struct router *)arg;
350
351         int ret = -1;
352
353         DEBUG_FUNC();
354         
355         if (!rt || !rtr) {
356                 DEBUG(DBG_ERROR, "mn_route_cleaner: rt or rtr NULL");
357                 return 0;
358         }
359
360         /* Do not delete routes to local addresses or to multicast
361          * addresses, since we need them to get router advertisements
362          * etc. Multicast addresses are more tricky, but we don't
363          * delete them in any case. The routing mechanism is not optimal for 
364          * multihoming.   
365          *
366          * Also keep all new prefix routes, gateway routes through rtr and
367          * all remaining default routes (including those used for reverse
368          * tunneling)
369          */
370         type = ipv6_addr_type(&rt->rt6i_dst.addr);
371         
372         if ((type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) ||
373             rt->rt6i_dev == &loopback_dev || rtr_is_gw(rtr, rt) ||
374             is_prefix_route(rtr, rt) || (rt->rt6i_flags & RTF_DEFAULT))  
375                 ret = 0;
376         
377         /*   delete all others */
378
379         if (rt->rt6i_dev != &loopback_dev) {
380                 DEBUG(DEBUG_MDETECT, 
381                       "%s route:\n"
382                       "dev: %s,\n"
383                       "gw: %x:%x:%x:%x:%x:%x:%x:%x,\n"
384                       "flags: %x,\n"
385                       "metric: %d,\n"
386                       "src: %x:%x:%x:%x:%x:%x:%x:%x,\n"
387                       "dst: %x:%x:%x:%x:%x:%x:%x:%x,\n"
388                       "plen: %d\n",
389                       (ret ? "Deleting" : "Keeping"),
390                       rt->rt6i_dev->name,              
391                       NIPV6ADDR(&rt->rt6i_gateway),            
392                       rt->rt6i_flags,
393                       rt->rt6i_metric,
394                       NIPV6ADDR(&rt->rt6i_src.addr),
395                       NIPV6ADDR(&rt->rt6i_dst.addr),
396                       rt->rt6i_dst.plen);
397         }
398         return ret;
399 }
400
401 /* 
402  * Deletes old routes 
403  */
404 static __inline__ void delete_routes(struct router *rtr)
405 {
406         DEBUG_FUNC();
407
408         /* Routing table is locked to ensure that nobody uses its */  
409         write_lock_bh(&rt6_lock);
410         DEBUG(DBG_INFO, "mipv6: Purging routes");
411         /*  TODO: Does not prune, should it?  */
412         fib6_clean_tree(&ip6_routing_table, 
413                         mn_route_cleaner, 0, rtr);
414         write_unlock_bh(&rt6_lock);
415
416 }
417
418 #if 0
419 int next_mdet_state[3][3] = {{CURR_RTR_OK, NO_RTR, NO_RTR},
420                              {CURR_RTR_OK, CURR_RTR_OK, NO_RTR},
421                              {CURR_RTR_OK, CURR_RTR_OK, RTR_SUSPECT}};
422  
423 char *states[3] = {"NO_RTR", "RTR_SUSPECT", "CURR_RTR_OK"};
424 char *events[3] = {"RA_RCVD", "NA_RCVD", "TIMEOUT"};
425
426 /* State transitions
427  * NO_RTR, RA_RCVD -> CURR_RTR_OK
428  * NO_RTR, NA_RCVD -> NO_RTR
429  * NO_RTR, TIMEOUT -> NO_RTR
430
431  * RTR_SUSPECT, RA_RCVD -> CURR_RTR_OK
432  * RTR_SUSPECT, NA_RCVD -> CURR_RTR_OK
433  * RTR_SUSPECT, TIMEOUT -> NO_RTR
434
435  * CURR_RTR_OK, RA_RCVD -> CURR_RTR_OK
436  * CURR_RTR_OK, NA_RCVD -> CURR_RTR_OK
437  * CURR_RTR_OK, TIMEOUT -> RTR_SUSPECT
438  */
439 #else
440 /*
441  * State diagram has been changed to :
442  * STOP_RTR_PROBE, RA_RCVD -> CURR_RTR_PRESENT
443  *
444  * CURR_RTR_NOT_PRESENT, RA_RCVD -> CURR_RTR_PRESENT
445  * CURR_RTR_NOT_PRESENT, RA_TIMEOUT -> CURR_RTR_NOT_PRESENT
446  * CURR_RTR_NOT_PRESENT, RA_TIMEOUT (if _curr_count == 0) -> STOP_RTR_PROBE
447  *
448  * CURR_RTR_PRESENT, RA_RCVD -> CURR_RTR_PRESENT
449  * CURR_RTR_PRESENT, RA_TIMEOUT -> CURR_RTR_NOT_PRESENT
450  */
451 char *states[3] = {"CURR_RTR_PRESENT", "CURR_RTR_NOT_PRESENT", "STOP_RTR_PROBE"};
452 char *events[3] = {"RA_RCVD", "RA_TIMEOUT"};
453
454 static int _curr_state = CURR_RTR_NOT_PRESENT;
455 static int _curr_count = MAX_RTR_SOLICITATIONS;
456 #endif
457
458 /* Needs to be called with router_lock locked */
459 static int mdet_statemachine(int event)
460 {
461         if (event > RA_TIMEOUT || _curr_state > STOP_RTR_PROBE) {
462                DEBUG(DBG_ERROR, "Got illegal event or curr_state");
463                return -1;
464         }
465
466         DEBUG(DBG_DATADUMP, "Got event %s and curr_state is %s", 
467               events[event], states[_curr_state]); 
468         
469         switch (event) {
470                 case RA_RCVD:
471                         _curr_state = CURR_RTR_PRESENT;
472                         _curr_count = MAX_RTR_SOLICITATIONS;
473                         break;
474                 case RA_TIMEOUT:
475                         /* Try for _curr_count before stopping probe */
476                         if (_curr_count-- <= 0)
477                                 _curr_state = STOP_RTR_PROBE;
478                         else _curr_state = CURR_RTR_NOT_PRESENT;
479                         break;
480         }
481
482         DEBUG(DBG_DATADUMP, "Next state is %s", states[_curr_state]);
483
484         return _curr_state;
485 }
486
487 /* 
488  * Changes the router, called from ndisc.c if mipv6_router_event 
489  * returns true.
490  */
491
492 static void mipv6_change_router(void)
493 {
494
495         struct in6_addr coa;
496         int ret, ifindex;
497         
498         DEBUG_FUNC(); 
499
500         
501         if (next_router == NULL) 
502                 return;
503         
504         spin_lock(&router_lock);
505
506
507         if (curr_router != NULL && 
508             !ipv6_addr_cmp(&curr_router->ll_addr, &next_router->ll_addr)) {
509                 DEBUG(DBG_INFO,"Trying to handoff from: "
510                       "%x:%x:%x:%x:%x:%x:%x:%x",
511                       NIPV6ADDR(&curr_router->ll_addr));
512                 DEBUG(DBG_INFO,"Trying to handoff to: "
513                       "%x:%x:%x:%x:%x:%x:%x:%x",
514                       NIPV6ADDR(&next_router->ll_addr));
515                 next_router = NULL; /* Let's not leave dangling pointers */
516                 spin_unlock(&router_lock);
517                 return;
518         }
519
520         ret = form_coa(&next_router->CoA, &next_router->raddr, 64, 
521                        next_router->ifindex);
522         if (ret < 0) {
523                 DEBUG(DBG_ERROR, "handoff: Creation of coa failed");
524                 spin_unlock(&router_lock);
525                 return;
526         } else if (ret > 0)
527                 next_router->flags |= COA_TENTATIVE;
528
529         mdet_statemachine(RA_RCVD); /* TODO: What if DAD fails... */
530         if (next_router->interval)
531                 mod_timer(&r_timer, jiffies + 
532                           (next_router->interval * HZ)/1000);
533         else
534                 mod_timer(&r_timer, jiffies + max_rtr_reach_time);
535
536         if (ret == 0) {
537                 ipv6_addr_copy(&coa, &next_router->CoA);
538                 ifindex = next_router->ifindex;
539                 spin_unlock(&router_lock);
540                 mipv6_mdet_finalize_ho(&coa, ifindex);
541                 return;
542         }
543         spin_unlock(&router_lock);
544
545 }
546
547 static void coa_timer_handler(unsigned long dummy)
548 {
549         spin_lock_bh(&ho_lock);
550         if (_ho) {
551                 DEBUG(DBG_INFO, "Starting handoff after DAD");
552                 mipv6_mobile_node_moved(_ho);
553                 kfree(_ho);
554                 _ho = NULL;
555         }
556         spin_unlock_bh(&ho_lock);
557 }
558 static void timer_handler(unsigned long foo)
559 {
560         unsigned long timeout = 0;
561         int state;
562
563         spin_lock_bh(&router_lock);
564         state = mdet_statemachine(RA_TIMEOUT);
565         if (state == CURR_RTR_NOT_PRESENT)
566                 (void) rs_send();
567         if (state != STOP_RTR_PROBE) {
568                 if (curr_router) {
569                         timeout = curr_router->interval ?
570                         curr_router->interval * HZ / 1000 :
571                         max_rtr_reach_time;
572                         if (timeout < 2) {
573                                 DEBUG(DBG_ERROR, "mdetect timeout < 0.02s");
574                                 timeout = 10;
575                         }
576                 } else
577                         timeout = max_rtr_reach_time;
578         }
579
580         mipv6_router_gc();
581         if (timeout)
582                 mod_timer(&r_timer, jiffies + timeout);
583         spin_unlock_bh(&router_lock);
584 }
585
586 /**
587  * mipv6_get_care_of_address - get node's care-of primary address
588  * @homeaddr: one of node's home addresses
589  * @coaddr: buffer to store care-of address
590  *
591  * Stores the current care-of address in the @coaddr, assumes
592  * addresses in EUI-64 format.  Since node might have several home
593  * addresses caller MUST supply @homeaddr.  If node is at home
594  * @homeaddr is stored in @coaddr.  Returns 0 on success, otherwise a
595  * negative value.
596  **/
597 int mipv6_get_care_of_address(
598         struct in6_addr *homeaddr, struct in6_addr *coaddr)
599 {
600         
601         DEBUG_FUNC();
602
603         if (homeaddr == NULL)
604                 return -1;
605         spin_lock_bh(&router_lock);
606         if (curr_router == NULL || mipv6_mn_is_at_home(homeaddr) || 
607             mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64) || 
608             curr_router->flags&COA_TENTATIVE) {
609                 DEBUG(DBG_INFO,
610                       "mipv6_get_care_of_address: returning home address");
611                 ipv6_addr_copy(coaddr, homeaddr);
612                 spin_unlock_bh(&router_lock);
613                 return 0;
614
615         }
616
617         /* At home or address check failure probably due to dad wait */
618         if (mipv6_prefix_compare(&curr_router->raddr, homeaddr, 
619                                  curr_router->pfix_len) 
620                                  || (dad == RESPECT_DAD && 
621                                      (ipv6_chk_addr(coaddr, NULL, 0) == 0))) { 
622                 ipv6_addr_copy(coaddr, homeaddr);
623         } else { 
624                 ipv6_addr_copy(coaddr, &curr_router->CoA);
625         }
626
627         spin_unlock_bh(&router_lock);
628         return 0;
629 }
630 int mipv6_mdet_del_if(int ifindex)
631 {
632         struct router *curr = NULL;
633         struct list_head *lh, *lh_tmp;
634
635         DEBUG_FUNC();
636
637         spin_lock_bh(&router_lock);
638         list_for_each_safe(lh, lh_tmp, &rtr_list) {
639                 curr =  list_entry(lh, struct router, list);
640                 if (curr->ifindex == ifindex) {
641                         num_routers--;
642                         list_del_init(&curr->list);
643                         DEBUG(DBG_DATADUMP, "Deleting router  %x:%x:%x:%x:%x:%x:%x:%x on interface %d", 
644                               NIPV6ADDR(&curr->raddr), ifindex);
645                         if (curr_router == curr)
646                                 curr_router = NULL;
647                         kfree(curr);
648                 }
649         }
650         spin_unlock_bh(&router_lock);
651         return 0;
652 }
653 int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex)
654 {
655         int dummy;
656         struct handoff ho;
657         struct router *tmp;
658
659         spin_lock_bh(&router_lock);
660         if (next_router && mipv6_prefix_compare(coa, &next_router->CoA, 
661                                                 next_router->pfix_len)) {
662         
663                 tmp = curr_router;
664                 curr_router = next_router;
665                 curr_router->is_current = 1;
666                 next_router = NULL; 
667                 curr_router->flags &= ~COA_TENTATIVE; 
668                 delete_routes(curr_router);
669                 if (tmp) {
670                         struct net_device *dev = dev_get_by_index(tmp->ifindex);
671                         struct rt6_info *rt = NULL;
672                         if (dev) {
673                                 rt = rt6_get_dflt_router(&tmp->ll_addr, dev);
674                                 dev_put(dev);
675                         }
676                         if (rt)
677                                 ip6_del_rt(rt, NULL, NULL);
678                         tmp->is_current = 0;
679                 }
680
681                 ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
682                 ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
683
684
685                 memcpy(&ho.rtr_addr, &curr_router->raddr, sizeof(ho.rtr_addr));
686                 ho.coa = &curr_router->CoA;
687                 ho.plen = curr_router->pfix_len;
688                 ho.ifindex = curr_router->ifindex;
689                 ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
690                 ho.home_address = (curr_router->glob_addr && 
691                                     curr_router->flags&ND_RA_FLAG_HA);
692                 
693                 spin_unlock_bh(&router_lock);
694                 mipv6_mobile_node_moved(&ho);
695         } else 
696                 spin_unlock_bh(&router_lock);
697         return 0;
698 }
699 /* Decides whether router candidate is the same router as current rtr
700  * based on prefix / global addresses of the routers and their link local 
701  * addresses 
702  */
703 static int is_current_rtr(struct router *nrt, struct router *crt)
704 {
705         DEBUG_FUNC();
706         
707         DEBUG(DEBUG_MDETECT, "Current router: "
708               "%x:%x:%x:%x:%x:%x:%x:%x and", NIPV6ADDR(&crt->raddr));
709         DEBUG(DEBUG_MDETECT, "Candidate router: "
710               "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&nrt->raddr));
711
712         return (!ipv6_addr_cmp(&nrt->raddr,&crt->raddr) && 
713                 !ipv6_addr_cmp(&nrt->ll_addr, &crt->ll_addr));
714 }
715
716 /* 
717  * Set next router to nrtr
718  * TODO: Locking to ensure nothing happens to next router
719  * before handoff is done
720  */ 
721 static void set_next_rtr(struct router *nrtr, struct router *ortr)
722 {
723         DEBUG_FUNC();
724         next_router = nrtr;
725 }
726
727 static int clean_ncache(struct router *nrt, struct router *ort, int same_if)
728 {
729         struct net_device *ortdev;
730         DEBUG_FUNC();
731
732         /* Always call ifdown after a handoff to ensure proper routing */
733         
734         if (!ort) 
735                 return 0;
736         if ((ortdev = dev_get_by_index(ort->ifindex)) == NULL) {
737                 DEBUG(DBG_WARNING, "Device is not present");
738                 return -1;
739         }
740         neigh_ifdown(&nd_tbl, ortdev);
741         dev_put(ortdev);        
742         return 0;
743 }
744
745 static int mdet_get_if_preference(int ifi)
746 {
747         int pref = 0;
748
749         DEBUG_FUNC();
750
751         pref = ma_ctl_get_preference(ifi);
752
753         DEBUG(DEBUG_MDETECT, "ifi: %d preference %d", ifi, pref);
754
755         return pref;
756 }
757
758 /*
759  * Called from mipv6_mn_ra_rcv to determine whether to do a handoff. 
760  */
761 static int mipv6_router_event(struct router *rptr)
762 {
763         struct router *nrt = NULL;
764         int new_router = 0, same_if = 1;
765         int ret = MIPV6_IGN_RTR;
766         int oldstate = _curr_state;
767         int addrtype = ipv6_addr_type(&rptr->raddr);
768
769         DEBUG_FUNC();
770
771         if (rptr->lifetime == 0)
772                 return ret;
773         DEBUG(DEBUG_MDETECT, "Received a RA from router: "
774               "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&rptr->raddr));
775         spin_lock(&router_lock);
776         
777         /* Add or update router entry */
778         if ((nrt = mipv6_rtr_get(&rptr->raddr)) == NULL) {
779                 if (addrtype == IPV6_ADDR_ANY || (nrt = mipv6_rtr_add(rptr)) == NULL) {
780                                 spin_unlock(&router_lock);
781                                 return ret;
782                 }
783                 DEBUG(DBG_INFO, "Router not on list,adding it to the list"); 
784                 new_router = 1;
785         }
786         nrt->last_ra_rcvd = jiffies;
787         nrt->state = ROUTER_REACHABLE;
788         nrt->interval = rptr->interval;
789         nrt->lifetime = rptr->lifetime;
790         nrt->ifindex = rptr->ifindex;
791         nrt->flags = rptr->flags;
792         nrt->glob_addr = rptr->glob_addr;
793
794         /* Whether from current router */
795         if (curr_router && is_current_rtr(nrt, curr_router)) {
796                 if (nrt->interval)
797                         mod_timer(&r_timer, jiffies + (nrt->interval * HZ)/1000);
798                 else
799                         mod_timer(&r_timer, jiffies + max_rtr_reach_time);
800                 mdet_statemachine(RA_RCVD);
801                 spin_unlock(&router_lock);
802                 return MIPV6_ADD_RTR;
803         } else if (oldstate == STOP_RTR_PROBE) {
804                 rt6_purge_dflt_routers(0); /* For multiple interface case */
805                 DEBUG(DBG_INFO, "No router or router not reachable, switching to new one");   
806                 goto handoff;
807         }
808         if (!curr_router) { 
809                 /* Startup */
810                 goto handoff;
811         }
812         /* Router behind same interface as current one ?*/
813         same_if = (nrt->ifindex == curr_router->ifindex);
814         /* Switch to new router behind same interface if eager cell 
815          *  switching is used or if the interface is preferred
816          */
817         if ((new_router && eager_cell_switching && same_if) ||
818             (mdet_get_if_preference(nrt->ifindex) > 
819              mdet_get_if_preference(curr_router->ifindex))) {
820                 DEBUG(DBG_INFO, "Switching to new router.");
821                 goto handoff;
822         }
823         
824         /* No handoff, don't add default route */
825         DEBUG(DEBUG_MDETECT, "Ignoring RA");
826         spin_unlock(&router_lock);
827         return ret;
828 handoff:
829         clean_ncache(nrt, curr_router, same_if);
830         set_next_rtr(nrt, curr_router);
831         spin_unlock(&router_lock);
832
833         return MIPV6_CHG_RTR;
834 }       
835
836 /* 
837  * Called from ndisc.c's router_discovery.
838  */
839
840 static int mipv6_mn_ra_rcv(struct sk_buff *skb)
841 {
842         int optlen;
843         int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
844         struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
845         struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
846         struct router nrt;
847         __u8 * opt = (__u8 *)(ra + 1);
848
849         DEBUG_FUNC();
850
851         memset(&nrt, 0, sizeof(struct router));
852
853         if (ra->icmph.icmp6_home_agent) {
854                 nrt.flags |= ND_RA_FLAG_HA;
855                 DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_HA up");
856         }
857
858         if (ra->icmph.icmp6_addrconf_managed) {
859                 nrt.flags |= ND_RA_FLAG_MANAGED;
860                 DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_MANAGED up");
861         }
862
863         if (ra->icmph.icmp6_addrconf_other) {
864                 nrt.flags |= ND_RA_FLAG_OTHER;
865                 DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_OTHER up");
866         }
867
868         ipv6_addr_copy(&nrt.ll_addr, saddr);
869         nrt.ifindex = ifi;
870         nrt.lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
871
872         optlen = (skb->tail - (unsigned char *)ra) - sizeof(struct ra_msg);
873
874         while (optlen > 0) {
875                 int len = (opt[1] << 3);
876                 if (len == 0) 
877                         return MIPV6_IGN_RTR;
878
879
880                 
881                 if (opt[0] == ND_OPT_PREFIX_INFO) {
882                         struct prefix_info *pinfo;
883
884                         if (len < sizeof(struct prefix_info)) 
885                                 return MIPV6_IGN_RTR;
886
887                         pinfo = (struct prefix_info *) opt;
888
889                         if (!pinfo->autoconf) {
890                                 /* Autonomous not set according to
891                                  * 2462 5.5.3 (a)
892                                  */
893                                 goto nextopt;
894                         }
895
896                         /* use first prefix with widest scope */
897                         if (ipv6_addr_any(&nrt.raddr) || 
898                             ((ipv6_addr_type(&nrt.raddr) != IPV6_ADDR_UNICAST) &&
899                             (ipv6_addr_type(&pinfo->prefix) == IPV6_ADDR_UNICAST))) {
900                                 ipv6_addr_copy(&nrt.raddr, &pinfo->prefix);
901                                 nrt.pfix_len = pinfo->prefix_len;
902                                 if (pinfo->router_address)
903                                         nrt.glob_addr = 1;
904                                 else
905                                         nrt.glob_addr = 0;
906                                 DEBUG(DBG_DATADUMP, "Address of the received "
907                                       "prefix info option: %x:%x:%x:%x:%x:%x:%x:%x", 
908                                       NIPV6ADDR(&nrt.raddr));
909                                 DEBUG(DBG_DATADUMP, "the length of the prefix is %d", 
910                                       nrt.pfix_len);
911                         }
912                 }
913                 if (opt[0] == ND_OPT_SOURCE_LL_ADDR) {
914                         nrt.link_addr_len = skb->dev->addr_len;
915                         memcpy(nrt.link_addr, opt + 2, nrt.link_addr_len);
916                 }
917                 if (opt[0] == ND_OPT_RTR_ADV_INTERVAL) {                        
918                         nrt.interval = ntohl(*(__u32 *)(opt+4));
919                         DEBUG(DBG_DATADUMP, 
920                               "received router interval option with interval : %d ",
921                               nrt.interval / HZ);
922                         
923                         if (nrt.interval > MAX_RADV_INTERVAL) {
924                                 nrt.interval = 0;
925                                 DEBUG(DBG_DATADUMP, "but we are using: %d, "
926                                       "because interval>MAX_RADV_INTERVAL",
927                                       nrt.interval / HZ);
928                         }
929                 }
930         nextopt:
931                 optlen -= len;
932                 opt += len;
933         }
934
935         return mipv6_router_event(&nrt);
936 }
937
938 int __init mipv6_initialize_mdetect(void)
939 {
940
941         DEBUG_FUNC();
942
943         spin_lock_init(&router_lock);
944         spin_lock_init(&ho_lock);
945         init_timer(&coa_timer);
946         init_timer(&r_timer);
947         r_timer.expires = jiffies + HZ;
948         add_timer(&r_timer);
949
950         /* Actual HO, also deletes old routes after the addition of new ones 
951            in ndisc */
952         MIPV6_SETCALL(mipv6_change_router, mipv6_change_router);
953
954         MIPV6_SETCALL(mipv6_ra_rcv, mipv6_mn_ra_rcv);
955
956         return 0;
957 }
958
959 int __exit mipv6_shutdown_mdetect()
960 {
961
962         DEBUG_FUNC();
963
964         MIPV6_RESETCALL(mipv6_ra_rcv);
965         MIPV6_RESETCALL(mipv6_change_router);
966         spin_lock_bh(&router_lock);
967         spin_lock(&ho_lock);
968         del_timer(&coa_timer);
969         del_timer(&r_timer);
970         /* Free the memory allocated by router list */
971         list_free(&curr_router);
972         if (_ho)
973                 kfree(_ho);
974         spin_unlock(&ho_lock);
975         spin_unlock_bh(&router_lock);
976         return 0;
977 }