mn_agentadv.c

Go to the documentation of this file.
00001 /* $Id: mn_agentadv.c,v 1.76 2001/09/29 18:42:07 jm Exp $
00002  * Mobile Node agentadv module
00003  *
00004  * Dynamic hierarchial IP tunnel
00005  * Copyright (C) 1998-2001, Dynamics group
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as
00009  * published by the Free Software Foundation. See README and COPYING for
00010  * more details.
00011  */
00012 
00013 #ifdef HAVE_CONFIG_H
00014 #include <config.h>
00015 #endif
00016 
00017 #include <stdlib.h>
00018 #include <sys/socket.h>
00019 #include <netinet/in.h>
00020 #include <arpa/inet.h>
00021 #include <string.h>
00022 #include <assert.h>
00023 #include <errno.h>
00024 #include <stddef.h>
00025 #include <features.h>    /* for the glibc version number */
00026 #include <unistd.h>
00027 #ifdef DYN_TARGET_LINUX
00028 #include <net/if_arp.h>
00029 #ifndef __GLIBC__
00030 /* get struct iphdr */
00031 #include <linux/ip.h>
00032 #endif
00033 #endif
00034 
00035 #include "hashtable.h"
00036 #include "debug.h"
00037 #include "fileio.h"
00038 #include "proxyarp.h"
00039 #ifdef WITH_WIRELESS
00040 #include "monitor.h"
00041 #endif
00042 #include "dyn_ip.h"
00043 #include "agentapi.h"
00044 #include "util.h"
00045 #include "mn_agentadv.h"
00046 #include "mn_handler.h"
00047 #include "mn.h"
00048 
00049 
00050 /* fa decision .. */
00051 static struct agentadv_data *max_adv;
00052 static int max_priority;
00053 static struct timeval max_adv_time;
00054 
00055 extern struct mn_data mn; 
00056 extern struct mn_config config;
00057 extern struct timeval timers[TIMER_COUNT];
00058 extern int real_tunnel_up; /* from mn_tunnel */
00059 
00060 
00061 int adv_ok_fa(struct agentadv_data *adv)
00062 {
00063         int opts;
00064 
00065         if (mn.force_fa_addr.s_addr != 0 &&
00066             mn.force_fa_addr.s_addr != adv->addr.s_addr)
00067                 return 0;
00068 
00069         if (adv->adv.ext == NULL)
00070                 return 0;
00071 
00072         opts = ntohs(adv->adv.ext->opts);
00073         if ((opts & AGENT_ADV_BUSY) || !(opts & AGENT_ADV_FOREIGN_AGENT))
00074                 return 0;
00075 
00076         if (config.tunneling_mode == TUNMODE_REVERSE &&
00077             !(opts & AGENT_ADV_BIDIR_TUNNELING))
00078                 return 0;
00079 
00080         if (config.tunneling_mode == TUNMODE_TRIANGLE &&
00081             adv->adv.own_ext != NULL &&
00082             !(adv->adv.own_ext->opts & AGENT_ADV_OWN_TRIANGLE_TUNNELING))
00083                 return 0;
00084 
00085         return 1;
00086 }
00087 
00088 
00089 static int addr_cmp(void *key, struct node *cmprd)
00090 {
00091         struct agentadv_data *entry = (struct agentadv_data *) cmprd;
00092         struct agentadv_key *akey = (struct agentadv_key *) key;
00093 
00094         if (akey->addr.s_addr == entry->addr.s_addr &&
00095             (akey->ifindex == 0 || akey->ifindex == entry->ifindex))
00096                 return TRUE;
00097         return FALSE;
00098 }
00099 
00100 
00101 static int addr_hash(void *key, const int tablesize)
00102 {
00103         unsigned char *addr;
00104         struct agentadv_key *akey = (struct agentadv_key *) key;
00105 
00106         addr = (unsigned char *) &akey->addr;
00107         return (int) (addr[0] ^ addr[1] ^ addr[2] ^ addr[3]);
00108 }
00109 
00110 
00123 struct agentadv_data *
00124 adv_fetch(struct hashtable *adv_hash, struct in_addr *addr, int ifindex)
00125 {
00126         struct agentadv_data *adv;
00127         struct agentadv_key key;
00128         key.addr.s_addr = addr->s_addr;
00129         key.ifindex = ifindex;
00130 
00131         adv = (struct agentadv_data *)
00132                 hashtable_fetch(adv_hash, addr_hash, &key, addr_cmp);
00133         return (adv);
00134 }
00135 
00136 
00137 static int current_agent_expired;
00138 
00139 /* remove hashtable entry, if the current time (data as struct timeval *) is
00140  * NULL (forced cleaning) or if the entry has expired */
00141 int clean_agentadv(struct node *node, void *data)
00142 {
00143         struct agentadv_data *adv;
00144         struct timeval *tval;
00145         struct event_FA dat;
00146 
00147         adv = (struct agentadv_data *) node;
00148         tval = (struct timeval *) data;
00149 
00150         if (tval != NULL && cmp_timeval(tval, &adv->expire) < 0)
00151                 return TRUE; /* not expired */
00152 
00153         if (tval != NULL && adv->in_use) {
00154                 /* in use and removal not forced */
00155                 current_agent_expired = TRUE;
00156                 return TRUE;
00157         }
00158 
00159         DEBUG(DEBUG_AGENTADV, "clean_agentadv: removing %s\n",
00160               inet_ntoa(adv->addr));
00161 
00162         /* call handlers registered for FA_ADV_EXPIRE event */
00163         dat.adv = adv;
00164         dat.hash = mn.agentadv;
00165         handler_call_all(FA_ADV_EXPIRE, &dat);
00166 
00167         /* remove the possible ARP entries etc. */
00168         if (adv->arpentry == 1 &&
00169             arp_del_permanent_item(adv->addr, adv->ifname) < 0) {
00170                 if (device_up(adv->ifindex)) {
00171                         LOG2(LOG_WARNING,
00172                              "arp_del_permanent_item(%s, %s) failed\n",
00173                              inet_ntoa(adv->addr), adv->ifname);
00174                 } else {
00175                         DEBUG(DEBUG_INFO, "arp_del_permanent_item(%s, %s) "
00176                               "failed (device down)\n",
00177                               inet_ntoa(adv->addr), adv->ifname);
00178                 }
00179         }
00180 
00181         /* remove the possible host route to FA */
00182         if (adv->routeentry == 1) {
00183                 DEBUG(DEBUG_INFO, "Removing FA route (%s,%s)\n",
00184                       inet_ntoa(adv->addr), adv->ifname);
00185                 if (dyn_ip_route_del(adv->addr, adv->ifname) != 0)
00186                         DEBUG(DEBUG_INFO, "FA route removing failed\n");
00187         }
00188 
00189         if (mn.current_adv == adv) {
00190                 DEBUG(DEBUG_AGENTADV, "clean_agentadv: removed current_adv\n");
00191                 mn.current_adv = NULL;
00192         }
00193 
00194         hashtable_remove(node);
00195         free(adv);
00196 
00197         return TRUE;
00198 }
00199 
00200 
00201 static void handle_home_adv(struct agentadv_data *adv)
00202 {
00203         struct in_addr addr;
00204 
00205         DEBUG(DEBUG_AGENTADV, "Home advertisement\n");
00206         if (config.priv_ha_ip_addr.s_addr != 0)
00207                 addr = config.priv_ha_ip_addr;
00208         else
00209                 addr = config.ha_ip_addr;
00210         if (addr.s_addr != adv->addr.s_addr) {
00211                 struct node *iter;
00212                 int found = 0;
00213                 for (iter = list_get_first(&config.alt_ha_ip_addrs);
00214                      iter != NULL; iter = list_get_next(iter)) {
00215                         struct alt_ha_entry *alt =
00216                                 (struct alt_ha_entry *) iter;
00217                         if (alt->addr.s_addr == adv->addr.s_addr) {
00218                                 found = 1;
00219                                 break;
00220                         }
00221                 }
00222                 if (!found) {
00223                         DEBUG(DEBUG_AGENTADV, "\tnot our HA\n");
00224                         return;
00225                 }
00226         }
00227 
00228         if (config.ha_nai_len > 0) {
00229                 struct fa_nai_ext *fa_nai =
00230                         (struct fa_nai_ext *) adv->adv.fa_nai;
00231                 if (fa_nai == NULL) {
00232                         DEBUG(DEBUG_AGENTADV, "\tno NAI extension in agent adv"
00233                               " - ignoring packet\n");
00234                         return;
00235                 }
00236                 if (config.ha_nai_len != GET_NAI_LEN(fa_nai)) {
00237                         DEBUG(DEBUG_AGENTADV, "\tNAI length mismatch - "
00238                               "ignoring packet\n");
00239                         return;
00240                 }
00241                 if (memcmp(config.ha_nai, MSG_NAI_DATA(fa_nai),
00242                            config.ha_nai_len) != 0) {
00243                         DEBUG(DEBUG_AGENTADV, "\tNAI mismatch - ignoring "
00244                               "packet\n");
00245                         return;
00246                 }
00247                 
00248         }
00249 
00250         if (mn.current_adv != NULL && mn.current_adv->in_use)
00251                 mn.current_adv->in_use = 0;
00252         mn.current_adv = adv;
00253         mn.current_adv->in_use = 1;
00254 
00255         mn.cur_route_info.ifindex = mn.cur_route_info.ifindex_net =
00256                 adv->ifindex;
00257         memcpy(mn.cur_route_info.ifname, adv->ifname, IFNAMSIZ);
00258         memcpy(mn.cur_route_info.ifname_net, adv->ifname, IFNAMSIZ);
00259         mn.cur_route_info.known = 1;
00260         mn.cur_route_info.via.s_addr = config.home_net_gateway.s_addr;
00261 
00262         adv->adv_type = MN_ADV_TYPE_OWN_HA;
00263         DEBUG(DEBUG_AGENTADV, "\tfrom our own HA - MN is at home\n");
00264         if (mn.state == MN_FIND_AGENT || mn.state == MN_PASSIVE_FIND ||
00265             mn.state == MN_REQUEST_TUNNEL || mn.state == MN_CONNECTED) {
00266                 /* FIX: if the co-loc. COA was used, the address of the
00267                  * interface must be set to the home network settings.
00268                  * Currently it is assumed that some external program
00269                  * handles the IP addresses if co-loc. COA is used. */
00270                 DEBUG(DEBUG_INFO, "Deregistering due to the heard "
00271                       "own HA agent advertisement\n");
00272                 close_for_home(STATE_INIT);
00273         }
00274 }
00275 
00276 
00277 /* hashtable iterator for update_fa_decision()
00278  * searches the entry with largest priority */
00279 static int find_fa_with_priority(struct node *node, void *data)
00280 {
00281         struct agentadv_data *adv;
00282 
00283         adv = (struct agentadv_data *) node;
00284 
00285         if (monitor_check_policy(NEWEST_ADV_BIT)) {
00286                 /* special case for Newest-ADV policy: just select the latest
00287                  * received advertisement */
00288                 if (!timerisset(&max_adv_time) ||
00289                     cmp_timeval(&max_adv_time, &adv->last) < 0) {
00290                         max_adv_time = adv->last;
00291                         max_adv = adv;
00292                 }
00293                 return TRUE;
00294         }
00295 
00296         adv->priority_degraded = adv->priority;
00297         DEBUG(DEBUG_HANDLERS, "%s priority %i", inet_ntoa(adv->addr), 
00298               adv->priority_degraded);
00299 
00300         /* degrade priority by degrade percent */
00301         if (adv->prio_degrade_percent > 0 && adv->priority_degraded > 0) {
00302                 adv->priority_degraded = (int)
00303                         (adv->priority_degraded *
00304                          ((100.0 - adv->prio_degrade_percent) / 100.0));
00305                 /* do not totally deny this FA */
00306                 if (adv->priority_degraded == 0)
00307                         adv->priority_degraded = 1;
00308                 DEBUG(DEBUG_HANDLERS, " => %i (-%i%%)", adv->priority_degraded,
00309                       adv->prio_degrade_percent);
00310         }
00311         DEBUG(DEBUG_HANDLERS, "\n");
00312 
00313         if (adv->priority_degraded > max_priority && !adv->reg_failed &&
00314             (adv_ok_fa(adv) || adv == mn.current_adv)) {
00315                 max_priority = adv->priority_degraded;
00316                 max_adv = adv;
00317         }
00318 
00319         return TRUE;
00320 }
00321 
00322 
00323 /* Called after FA_GET handlers */
00324 static int update_fa_decision(struct agentadv_data *adv)
00325 {
00326         int same_prio;
00327         struct timeval now;
00328 
00329         gettimeofday(&now, NULL);
00330 
00331         /* (A) 
00332          * if we are at home and the HA's agentadv has not expired, do not try
00333          * to change the FA */
00334         if ((mn.state == MN_AT_HOME || mn.state == MN_CLOSE_FOR_HOME) &&
00335             mn.current_adv != NULL &&
00336             mn.current_adv->addr.s_addr == config.ha_ip_addr.s_addr &&
00337             mn.current_adv->adv.ext != NULL &&
00338             ntohs(mn.current_adv->adv.ext->opts) & AGENT_ADV_HOME_AGENT &&
00339             cmp_timeval(&mn.current_adv->expire, &now) >= 0 &&
00340             !monitor_check_policy(NEWEST_ADV_BIT)) {
00341                 DEBUG(DEBUG_AGENTADV,
00342                       "HA agentadv still valid - staying at home\n");
00343                 return FA_GET_NO;
00344         }
00345 
00346         /* if we are using direct connection to the HA, do not try to change
00347          * the FA */
00348         if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {
00349                 DEBUG(DEBUG_AGENTADV, "Direct connection to the HA - ignoring "
00350                       "FA agent advertisement\n");
00351                 return FA_GET_NO;
00352         }
00353 
00354         /* Get FA with max priority */
00355         max_adv = NULL;
00356         max_priority = 0;
00357         timerclear(&max_adv_time);
00358 
00359         if (mn.agentadv == NULL) {
00360                 DEBUG(DEBUG_AGENTADV, "update_fa_decision: mn.agentadv == "
00361                       "NULL\n");
00362                 return FA_GET_NO;
00363         }
00364         hashtable_iterator(mn.agentadv, find_fa_with_priority, NULL);
00365         if (max_adv == NULL) {
00366                 DEBUG(DEBUG_AGENTADV, "update_fa_decision: Can't find FA!\n");
00367                 return FA_GET_NO;
00368         }
00369 
00370         if (mn.current_adv != NULL) {
00371                 DEBUG(DEBUG_AGENTADV, "CURRENT: %s   ",
00372                       inet_ntoa(mn.current_adv->addr));
00373                 DEBUG(DEBUG_AGENTADV, "MAX: %s\n",
00374                       inet_ntoa(max_adv->addr));
00375         }
00376 
00377         /* (B) 
00378          * If same priority, don't change */
00379         /* FIX: How to compare two LFAs. How can we know that they are same
00380          * JM-FIX: use FA NAI */
00381         if (mn.current_adv != NULL)
00382                 same_prio = mn.current_adv->priority_degraded == max_priority;
00383         else
00384                 same_prio = FALSE;
00385         /* skip priority check if Newest-ADV policy is used */
00386         if (monitor_check_policy(NEWEST_ADV_BIT))
00387                 same_prio = FALSE;
00388         if (mn.current_adv != NULL &&
00389             (same_prio ||
00390              mn.current_adv->addr.s_addr == max_adv->addr.s_addr)) {
00391                 return FA_GET_SAME; /* no change if same priority or SAME FA */
00392         }
00393 
00394         /* Change FA. First update the FA information */
00395         mn.fa_addr.s_addr = max_adv->addr.s_addr;
00396         memcpy(&mn.co_addr, (max_adv->adv.ext) + 1, sizeof(struct in_addr));
00397         mn.req_lifetime = ntohs(max_adv->adv.ext->reg_lifetime);
00398         if (mn.current_adv != NULL)
00399                 mn.current_adv->in_use = 0;
00400         mn.current_adv = max_adv;
00401         memcpy(&mn.fa_dynamics_ext, &max_adv->adv.own_ext,
00402                sizeof(struct agent_adv_dynamics));
00403         gettimeofday(&timers[TIMER_ADV], NULL);
00404         timers[TIMER_ADV].tv_sec += ntohs(max_adv->adv.radv->lifetime);
00405 
00406         return FA_GET_CHANGED;
00407 }
00408 
00409 
00410 /* Get a FA
00411  * Returns:
00412  *   0 = FA not found or HA agentadv still valid => do not try to register
00413  *   1 = new FA found
00414  *   2 = FA found, but it is the same as the current FA */
00415 int get_fa(struct agentadv_data *adv)
00416 {
00417         struct event_FA data;
00418 
00419         data.adv = adv;
00420         data.hash = mn.agentadv;
00421         handler_call_all(FA_GET, &data);
00422         return update_fa_decision(adv);
00423 }
00424 
00425 
00426 static void handle_fa_adv(struct agentadv_data *adv)
00427 {
00428         struct in_addr _fa_addr, _highest_fa_addr;
00429         int chg = 0;
00430         struct event_FA data;
00431 
00432         UNALIGNED_(&_fa_addr.s_addr, &adv->adv.ip->saddr);
00433         memcpy(&_highest_fa_addr, adv->adv.ext + 1, sizeof(struct in_addr));
00434 
00435         DEBUG(DEBUG_AGENTADV, "FA advertisement - fa_addr=%s, ",
00436               inet_ntoa(_fa_addr));
00437         DEBUG(DEBUG_AGENTADV, "highest_fa_addr=%s\n",
00438               inet_ntoa(_highest_fa_addr));
00439 
00440 
00441         /* Call all handlers for this event: FA_ADV_RECEIVE */
00442         data.adv = adv;
00443         data.hash = mn.agentadv;
00444         handler_call_all(FA_ADV_RECEIVE, &data);
00445 
00446         if (mn.state == MN_CONNECTED && ntohs(adv->adv.ext->seq) < 256 &&
00447             adv->last_heard_seqn >= ntohs(adv->adv.ext->seq)) {
00448                 adv->last_heard_seqn = ntohs(adv->adv.ext->seq);
00449                 DEBUG(DEBUG_INFO, "FA rebooted - trying to reregister\n");
00450                 request_tunnel(STATE_INIT, 0, 0);
00451                 return;
00452         }
00453 
00454         /* update sequence number */
00455         adv->last_heard_seqn = ntohs(adv->adv.ext->seq);
00456 
00457         switch (mn.state) {
00458         case MN_DISCONNECTED:
00459                 break;
00460         case MN_AT_HOME:
00461         case MN_CLOSE_FOR_HOME:
00462                 /* try to register to an FA if the HA's agentadv expires */
00463                 if (mn.current_adv == NULL ||
00464                     mn.current_adv->adv_type != MN_ADV_TYPE_OWN_HA ||
00465                     adv->adv_type != MN_ADV_TYPE_FA)
00466                         break;
00467                 if (cmp_timeval(&adv->last, &mn.current_adv->expire) < 0 &&
00468                     !monitor_check_policy(NEWEST_ADV_BIT))
00469                         break;
00470 
00471                 DEBUG(DEBUG_INFO,
00472                       "HA agentadv expired - trying to use FA (IP=%s)\n",
00473                       inet_ntoa(adv->addr));
00474                 /* continue to next case statement.. */
00475         case MN_FIND_AGENT:
00476         case MN_PASSIVE_FIND:
00477         case MN_REQUEST_TUNNEL:
00478                 /* FIX: if the real tunnel is not yet up and the MN gets a
00479                  * flood of agentadvs from different FAs, there might not be
00480                  * enough time for the reply to arrive and MN might try to
00481                  * register to yet another FA.. */
00482                 chg = get_fa(adv);
00483                 if (chg == FA_GET_CHANGED ||
00484                     (chg == FA_GET_SAME && (real_tunnel_up == 0 ||
00485                             mn.state != MN_REQUEST_TUNNEL)))
00486                         request_tunnel(STATE_INIT, 0, 1);
00487                 break;
00488         case MN_CONNECTED:
00489                 chg = get_fa(adv);
00490                 /* start requesting the tunnel if the current FA's seq#
00491                  * indicates that the FA has rebooted or if the FA has been
00492                  * changed */
00493                 if (chg == FA_GET_CHANGED) {
00494                         request_tunnel(STATE_INIT, 0, 1);
00495                 }
00496                 break;
00497         default:
00498                 break;
00499         }
00500 }
00501 
00502 /* check_expired_agent_advs:
00503  *
00504  * Remove old agent advertisement datas from the memory 
00505  *
00506  * Returns: 1 if current agent has expired, else 0
00507  */
00508 int check_expired_agent_advs(void)
00509 {
00510         static time_t prev_check = 0;
00511         struct timeval now;
00512         struct timeval tmp;
00513         
00514         gettimeofday(&now, NULL);
00515 
00516         if (prev_check <= now.tv_sec &&
00517             now.tv_sec < prev_check + ADV_CLEANUP_FREQ)
00518                 return 0;
00519                 
00520         prev_check = now.tv_sec;
00521         current_agent_expired = FALSE;
00522 
00523         tmp.tv_sec = now.tv_sec - ADV_EXTRA_TIME;
00524         tmp.tv_usec = now.tv_usec;
00525         DEBUG(DEBUG_AGENTADV,
00526               "\tchecking for expired agentadv data\n");
00527         hashtable_iterator(mn.agentadv, clean_agentadv, &tmp);
00528         
00529         if (current_agent_expired) {
00530                 DEBUG(DEBUG_AGENTADV, "Current agent's adv. expired - try to "
00531                       "find new FA\n");
00532                 return 1;
00533         }
00534         
00535         return 0;
00536 }
00537 
00538 /* handle incoming agent advertisement
00539  * Returns:
00540  *   0 - no extra processing needed
00541  *   1 - current agent's advertisement has expired
00542  */
00543 int handle_icmp(struct interface_data *iface)
00544 {
00545         char buf[MAX_ADV_MSG];
00546         struct adv_extensions ext;
00547         struct agentadv_key key;
00548         struct agentadv_data *adv;
00549         int res;
00550 
00551         /* return, if message was not for us */
00552         res = handle_icmp_adv(iface->s_adv, buf, MAX_ADV_MSG, &ext);
00553         if (res == -1) {
00554                 /* network is down - rescan interfaces */
00555                 check_interfaces(mn.iface, MAX_INTERFACES);
00556         }
00557 
00558         if (res != 1)
00559                 return 0;
00560 
00561         UNALIGNED_(&key.addr.s_addr, &ext.ip->saddr);
00562 
00563 #ifndef MN_FA_FORCE_AFTER_AGENTADV_UPDATE
00564         if (mn.force_fa_addr.s_addr != 0 &&
00565             mn.force_fa_addr.s_addr != key.addr.s_addr) {
00566                 DEBUG(DEBUG_AGENTADV,
00567                       "handle_icmp: force_fa set to %s - ignoring this FA(1)",
00568                       inet_ntoa(mn.force_fa_addr));
00569                 DEBUG(DEBUG_AGENTADV, " (%s)\n", inet_ntoa(key.addr));
00570                 return 0;
00571         }
00572 #endif /* MN_FA_FORCE_AFTER_AGENTADV_UPDATE */
00573 
00574         key.ifindex = iface->index;
00575 
00576         if (ntohs(ext.ext->reg_lifetime) < MIN_ALLOWED_LIFETIME) {
00577                 DEBUG(DEBUG_AGENTADV,
00578                       "handle_icmp: too small lifetime advertised (%d) "
00579                       "- ignoring this FA (%s)\n",
00580                       ntohs(ext.ext->reg_lifetime), inet_ntoa(key.addr));
00581                 return 0;
00582         }
00583 
00584         /* save the last agentadv */
00585         adv = (struct agentadv_data *)
00586                 hashtable_fetch(mn.agentadv, addr_hash, &key, addr_cmp);
00587         if (adv == NULL) {
00588                 /* we have no previous information on this mobility agent */
00589                 adv = (struct agentadv_data *)
00590                         malloc(sizeof(struct agentadv_data));
00591                 if (adv == NULL) {
00592                         DEBUG(DEBUG_AGENTADV,
00593                               "handle_icmp: no memory for agentadv data\n");
00594                         return 0;
00595                 }
00596                 DEBUG(DEBUG_AGENTADV, "Added new agentadv entry for %s\n",
00597                       inet_ntoa(key.addr));
00598                 memset(adv, 0, sizeof(struct agentadv_data));
00599                 list_init_node(&adv->node);
00600                 UNALIGNED_(&adv->addr.s_addr, &ext.ip->saddr);
00601                 adv->counter = 1;
00602                 adv->prio_degrade_percent = 0; /* don't degrade new FAs! */ 
00603                 if (!hashtable_add(mn.agentadv, addr_hash, &key.addr,
00604                                    &adv->node)) {
00605                         DEBUG(DEBUG_AGENTADV,
00606                               "handle_icmp: hashtable_add failed\n");
00607                         free(adv);
00608                         return 0;
00609                 }
00610         } else {
00611                 /* updating information for previously heard mobility agent */
00612                 DEBUG(DEBUG_AGENTADV, "Used old agentadv entry for %s\n",
00613                       inet_ntoa(key.addr));
00614                 adv->counter++;
00615                 /* Let FA become slowly "available" again */
00616                 if (adv->prio_degrade_percent > 0)
00617                         adv->prio_degrade_percent = (int)
00618                                 (adv->prio_degrade_percent*
00619                                  DEFAULT_PRIO_DEGRADE_DEGRADE);
00620                 /* remove the reg_failed flag if the adv. opts has changed */
00621                 if (adv->reg_failed && ext.ext->opts != adv->adv.ext->opts) {
00622                         DEBUG(DEBUG_AGENTADV,
00623                               "Reseting reg_failed for this FA\n");
00624                         adv->reg_failed = 0;
00625                 }
00626         }
00627 
00628         adv->ifindex = iface->index;
00629         dynamics_strlcpy(adv->ifname, iface->device, sizeof(adv->ifname));
00630         gettimeofday(&adv->last, NULL);
00631         adv->expire.tv_sec = adv->last.tv_sec + ntohs(ext.radv->lifetime) + 1;
00632         adv->expire.tv_usec = adv->last.tv_usec;
00633         DEBUG(DEBUG_AGENTADV, "\tnow=%li.%li, expire=%li.%li\n",
00634               adv->last.tv_sec, adv->last.tv_usec,
00635               adv->expire.tv_sec, adv->expire.tv_usec);
00636 
00637         memcpy(adv->buf, buf, MAX_ADV_MSG);
00638         memcpy(&adv->adv, &ext, sizeof(struct adv_extensions));
00639         adv->adv.start = adv->buf;
00640         adv->adv.len = ext.len;
00641         adv->adv.coaddrs = ext.coaddrs;
00642         memcpy(&adv->adv.from, &ext.from, sizeof(ext.from));
00643 #define UPDATE_OFFSET(n) adv->adv.n = ext.n ? \
00644 (typeof(ext.n)) (((char *) ext.n) - ext.start + adv->adv.start) : NULL
00645 #ifndef DYN_TARGET_LINUX
00646         UPDATE_OFFSET(eth);
00647 #endif
00648         UPDATE_OFFSET(ip);
00649         UPDATE_OFFSET(radv);
00650         UPDATE_OFFSET(ext);
00651         UPDATE_OFFSET(prefix);
00652         UPDATE_OFFSET(own_ext);
00653         UPDATE_OFFSET(pubkey_hash);
00654         UPDATE_OFFSET(fa_nai);
00655         UPDATE_OFFSET(challenge);
00656 
00657 #ifdef MN_FA_FORCE_AFTER_AGENTADV_UPDATE
00658         if (mn.force_fa_addr.s_addr != 0 &&
00659             mn.force_fa_addr.s_addr != key.addr.s_addr) {
00660                 DEBUG(DEBUG_AGENTADV,
00661                       "handle_icmp: force_fa set to %s - ignoring this FA(2)",
00662                       inet_ntoa(mn.force_fa_addr));
00663                 DEBUG(DEBUG_AGENTADV, " (%s)\n", inet_ntoa(key.addr));
00664                 return 0;
00665         }
00666 #endif /* MN_FA_FORCE_AFTER_AGENTADV_UPDATE */
00667 
00668         if (ntohs(ext.ext->opts) & AGENT_ADV_HOME_AGENT) {
00669                 adv->adv_type = MN_ADV_TYPE_HA;
00670                 handle_home_adv(adv);
00671         }
00672         if (ntohs(ext.ext->opts) & AGENT_ADV_FOREIGN_AGENT) {
00673                 if (adv->adv_type != MN_ADV_TYPE_OWN_HA)
00674                         adv->adv_type = MN_ADV_TYPE_FA;
00675                 if (ext.coaddrs <= 0)
00676                         DEBUG(DEBUG_AGENTADV,
00677                               "handle_icmp: FA adv with no COAs - ignoring\n");
00678                 else
00679                         handle_fa_adv(adv);
00680         }
00681 
00682         return 0;
00683 }

Generated on Tue Jan 15 08:50:43 2008 for Virtual foreign agent generator version 0.1 by  doxygen 1.5.1