mn_tunnel.c

Go to the documentation of this file.
00001 /* $Id: mn_tunnel.c,v 1.7 2001/09/09 15:11:18 jm Exp $
00002  * Mobile Node - tunnel handling
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 <sys/socket.h>
00018 #include <netinet/in.h>
00019 #include <arpa/inet.h>
00020 #include <time.h>
00021 
00022 #include "mn.h"
00023 #include "mn_tunnel.h"
00024 #include "debug.h"
00025 #include "util.h"
00026 
00027 extern struct mn_data mn;
00028 extern struct mn_config config;
00029 
00030 int real_tunnel_up;
00031 /* If there exists any tunnels at all. When the
00032                              * first tunnel is created, this variable becomes
00033                              * true. */
00034 
00035 static char tunnel_device[IFNAMSIZ]; /* tunneling device name */
00036 static struct in_addr old_tunnel_addr; /* tunnel endpoint of the old (lazy deleted)
00037                                    tunnel */
00038 static char old_tunnel_device[IFNAMSIZ];
00039 static time_t old_tunnel_expire; /* time after which old tunnel can be
00040                                   * deleted, 0 = no old tunnel */
00041 static int tunnel_b_up;      /* Used to select tunnel device name */
00042 
00043 
00044 static char* 
00045 return_home_net_route(void)
00046 {
00047         int i;
00048         char *dev = NULL, *adv_dev = NULL;
00049 
00050         if (config.home_net_addr_plen < 0) {
00051                 DEBUG(DEBUG_MESSAGES, "return_home_net_route:"
00052                       " config.home_net_addr_plen < 0\n");
00053                 return NULL;
00054         }
00055 
00056         /* get the current advertisement interface if it is still up */
00057         if (mn.current_adv != NULL) {
00058                 for (i = 0; i < MAX_INTERFACES; i++) {
00059                         if (mn.iface[i].s > -1 &&
00060                             strcmp(mn.current_adv->ifname, mn.iface[i].device)
00061                             == 0) {
00062                                 DEBUG(DEBUG_MESSAGES, "return_home_net_route:"
00063                                       " found current adv interface\n");
00064                                 adv_dev = mn.current_adv->ifname;
00065                                 break;
00066                         }
00067                 }
00068         }
00069 
00070         /* use the interface from which the possible HA agentadv was heard,
00071          * if the interface is up */
00072         if (adv_dev != NULL &&
00073             ntohs(mn.current_adv->adv.ext->opts) & AGENT_ADV_HOME_AGENT &&
00074             config.ha_ip_addr.s_addr == mn.current_adv->addr.s_addr) {
00075                 DEBUG(DEBUG_MESSAGES, "return_home_net_route: "
00076                       "found interface where the HA is\n");
00077                 dev = adv_dev;
00078         }
00079 
00080         /* check if the originally used device is still available */
00081         if (dev == NULL && mn.start_default_device[0] != '\0') {
00082                 for (i = 0; i < MAX_INTERFACES; i++) {
00083                         if (mn.iface[i].s > -1 &&
00084                             strcmp(mn.start_default_device, mn.iface[i].device)
00085                             == 0) {
00086                                 dev = mn.start_default_device;
00087                                 break;
00088                         }
00089                 }
00090         }
00091 
00092         /* check the previously used device */
00093         if (dev == NULL && adv_dev != NULL)
00094                 dev = adv_dev;
00095 
00096         if (dev == NULL) {
00097                 /* take any device that is up */
00098                 for (i = 0; i < MAX_INTERFACES; i++) {
00099                         if (mn.iface[i].s > -1) {
00100                                 dev = mn.iface[i].device;
00101                                 break;
00102                         }
00103                 }
00104         }
00105 
00106         if (dev == NULL) {
00107                 DEBUG(DEBUG_INFO,
00108                       "No active device found - home net route not added\n");
00109                 return NULL;
00110         }
00111 
00112         mn.cur_route_info.known = 1;
00113         mn.cur_route_info.via.s_addr = config.home_net_gateway.s_addr;
00114         memcpy(mn.cur_route_info.ifname, dev, IFNAMSIZ);
00115         mn.cur_route_info.ifindex = dyn_ip_get_ifindex(dev);
00116         memcpy(mn.cur_route_info.ifname, dev, IFNAMSIZ);
00117         mn.cur_route_info.ifindex_net = mn.cur_route_info.ifindex;
00118 
00119 #ifdef DYN_TARGET_WINDOWS
00120         if (mn.home_net_route_set_via_fa) {
00121                 int count;
00122 
00123                 DEBUG(DEBUG_INFO, "Trying to delete home net route via FA\n");
00124                 count = dyn_ip_route_delete_net_routes(
00125                         &config.home_net_addr,
00126                         config.home_net_addr_plen);
00127                 if (count < 0) {
00128                         DEBUG(DEBUG_INFO, "   failed to delete home net route "
00129                               "via FA\n");
00130                 } else {
00131                         DEBUG(DEBUG_INFO, "   home net route delete count: "
00132                               "%i\n", count);
00133                         mn.home_net_route_set_via_fa = 0;
00134                 }
00135         }
00136 #endif /* DYN_TARGET_WINDOWS */
00137 
00138         DEBUG(DEBUG_INFO, "Returning home net route %s/%i to %s\n",
00139               inet_ntoa(config.home_net_addr), config.home_net_addr_plen, dev);
00140         if (dyn_ip_route_add_net(dev, &config.home_net_addr,
00141                                  config.home_net_addr_plen) != 0) {
00142                 LOG2(LOG_ERR,
00143                      "Home net route (%s/%i => %s) add failed\n",
00144                      inet_ntoa(config.home_net_addr),
00145                      config.home_net_addr_plen, dev);
00146         }
00147         return dev;
00148 }
00149 
00150 void 
00151 check_old_tunnel_expiration(void)
00152 {
00153 #ifdef MN_ENABLE_TUNNELING
00154         if (old_tunnel_expire == 0 ||
00155             time(NULL) <= old_tunnel_expire)
00156                 return;
00157 
00158         old_tunnel_expire = 0;
00159         if (dyn_ip_tunnel_del(old_tunnel_device) != 0) {
00160                 LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");
00161                 return;
00162         }
00163 #endif
00164 }
00165 
00166 void 
00167 init_tunneling(void)
00168 {
00169         DEBUG(DEBUG_INFO, "Init tunneling\n");
00170 
00171         dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE, sizeof(tunnel_device));
00172         real_tunnel_up = 0;
00173         tunnel_b_up = 0;
00174 }
00175 
00176 /* Free tunneling structures */
00177 void 
00178 close_tunneling(void)
00179 {
00180         DEBUG(DEBUG_INFO, "Close tunneling\n");
00181         /* clean up tunnel first */
00182         if (real_tunnel_up) stop_tunneling();
00183         /* disconnect any waiting api calls */
00184         reply_waiting_api(API_FAILED, NULL, 0);
00185 }
00186 
00196 static int
00197 make_tunnel(struct in_addr local_addr, struct in_addr ma_addr)
00198 {
00199         struct in_addr any;
00200 
00201         if (old_tunnel_expire != 0) {
00202                 /* try to use the lazy deleted tunnel, if it is to the correct
00203                  * FA */
00204                 old_tunnel_expire = 0;
00205 
00206                 if (old_tunnel_addr.s_addr == ma_addr.s_addr) {
00207                         DEBUG(DEBUG_INFO, "make_tunnel - reusing old (lazy "
00208                               "deleted) tunnel\n");
00209                         return 0;
00210                 }
00211 
00212                 /* old tunnel was to a wrong FA - remove it and make new tunnel
00213                  */
00214                 if (dyn_ip_tunnel_del(old_tunnel_device) != 0) {
00215                         LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");
00216                 }
00217         }
00218 
00219         any.s_addr = 0;
00220         DEBUG(DEBUG_INFO, "Adding tunnel %s => %s\n", tunnel_device,
00221               inet_ntoa(ma_addr));
00222         if (dyn_ip_tunnel_add(tunnel_device, ma_addr, any) != 0) {
00223                 LOG2(LOG_ERR, "tunnel add failed (%s => %s)\n",
00224                        tunnel_device, inet_ntoa(ma_addr));
00225                 return -1;
00226         }
00227 
00228         if (dyn_ip_addr_add(tunnel_device, local_addr) != 0) {
00229                 DEBUG(DEBUG_INFO, "dyn_ip_addr_add(%s, %s) failed!\n",
00230                       tunnel_device,
00231                       inet_ntoa(local_addr));
00232                 if (dyn_ip_tunnel_del(tunnel_device) != 0) {
00233                         DEBUG(DEBUG_INFO, "tunnel delete failed\n");
00234                 }
00235                 return -1;
00236         }
00237 
00238         if (dyn_ip_link_set_dev_up(tunnel_device) != 0) {
00239                 DEBUG(DEBUG_INFO,
00240                       "dyn_ip_link_set_dev_up(%s) failed!\n",
00241                       tunnel_device);
00242                 if (dyn_ip_tunnel_del(tunnel_device) != 0) {
00243                         DEBUG(DEBUG_INFO, "tunnel delete failed\n");
00244                 }
00245                 return -1;
00246         }
00247 
00248         return 0;
00249 }
00250 
00251 
00259 int 
00260 start_tunneling(void)
00261 {
00262         int failed = 0;
00263 
00264         if (real_tunnel_up) {
00265                 DEBUG(DEBUG_INFO, "Start tunneling - tunnel is already up\n");
00266                 mn.tunnel_up = 1;
00267                 return 0;
00268         }
00269 
00270 #ifdef MN_ENABLE_TUNNELING
00271 
00272         DEBUG(DEBUG_INFO, "Start tunneling - FA addr %s\n",
00273               inet_ntoa(mn.fa_addr));
00274 
00275         if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {
00276                 /* set a host route to the HA so that the default route
00277                  * replacing will not kill the route */
00278                 if (dyn_ip_route_to_host(config.ha_ip_addr) != 0) {
00279                         LOG2(LOG_ERR, "Could not set host route to the HA\n");
00280                 }
00281         }
00282 
00283         if (!config.enable_fa_decapsulation) {
00284                 if (make_tunnel(config.mn_home_ip_addr, mn.fa_addr) < 0)
00285                         return -1;
00286 
00287                 switch (config.mndecaps_route_handling) {
00288                 case MNDECAPS_ROUTE_DEFAULT:
00289                         /* set default route to the tunnel */
00290                         DEBUG(DEBUG_INFO, "Setting default route to %s\n",
00291                               tunnel_device);
00292                         if (dyn_ip_route_replace_default(
00293                                 tunnel_device, NULL,
00294                                 &config.mn_home_ip_addr) != 0) {
00295                                 LOG2(LOG_ERR,
00296                                      "Set default route to dev %s failed\n",
00297                                      tunnel_device);
00298                                 failed = 1;
00299                         }
00300                         break;
00301                 case MNDECAPS_ROUTE_HOME_NET:
00302                         /* only set home net route to the tunnel
00303                          * This entry will be automatically removed when the
00304                          * tunnel is set down. */
00305                         DEBUG(DEBUG_INFO, "Setting home net route to %s\n",
00306                               tunnel_device);
00307                         if (dyn_ip_route_replace_net(tunnel_device,
00308                                                      &config.home_net_addr,
00309                                                      config.home_net_addr_plen)
00310                             != 0) {
00311                                 LOG2(LOG_ERR,
00312                                      "Set home net route to dev %s failed\n",
00313                                      tunnel_device);
00314                                 failed = 1;
00315                         }
00316                         break;
00317                 case MNDECAPS_ROUTE_NONE:
00318                         DEBUG(DEBUG_INFO, "No route set to %s\n",
00319                               tunnel_device);
00320                         break;
00321                 }
00322 
00323                 if (failed) {
00324                         /* rollback */
00325                         if (dyn_ip_tunnel_del(tunnel_device) != 0) {
00326                                 DEBUG(DEBUG_INFO, "tunnel delete failed\n");
00327                         }
00328                         return -1;
00329                 }
00330         } else if (mn.current_adv != NULL) {
00331                 /* FA decapsulation and we have heard an advertisement:
00332                  * set default route to FA, and remove all routes to
00333                  * home network */
00334                 if (update_fa_decaps_routes(mn.current_adv->ifname,
00335                                             mn.current_adv->ifindex,
00336                                             mn.fa_addr,
00337                                             config.home_net_addr,
00338                                             config.home_net_addr_plen) < 0)
00339                         return -1;
00340         } else
00341                 LOG2(LOG_WARNING, "start_tunneling() - current_adv == NULL\n");
00342 
00343 #else
00344         DEBUG(DEBUG_INFO, "Start tunneling - tunneling disabled\n");
00345 #endif
00346         mn.tunnel_addr.s_addr = mn.fa_addr.s_addr;
00347         mn.tunnel_up = 1;
00348         real_tunnel_up = 1;
00349         return 0;
00350 }
00351 
00352 /*
00353  * Tunneling is up.
00354  * Create new (second) tunnel and set default route to this new tunnel.
00355  * Delete old tunnel.
00356  * Set route for FA.
00357  * Returns nonzero if successful.
00358  */
00359 int restart_tunneling(void)
00360 {
00361 #ifdef MN_ENABLE_TUNNELING
00362         struct in_addr old;
00363 
00364         /* roll tunnel device names */
00365         if (!tunnel_b_up) {
00366                 dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE_B,
00367                                  sizeof(tunnel_device));
00368                 tunnel_b_up = 1;
00369         } else {
00370                 dynamics_strlcpy(tunnel_device, TUNNEL_DEVICE,
00371                                  sizeof(tunnel_device));
00372                 tunnel_b_up = 0;
00373         }
00374         old.s_addr = mn.tunnel_addr.s_addr;
00375 
00376         mn.tunnel_up = 0;
00377         real_tunnel_up = 0;
00378         start_tunneling();
00379 
00380         if (tunnel_b_up)
00381                 dynamics_strlcpy(old_tunnel_device, TUNNEL_DEVICE,
00382                                  sizeof(old_tunnel_device));
00383         else
00384                 dynamics_strlcpy(old_tunnel_device, TUNNEL_DEVICE_B,
00385                                  sizeof(old_tunnel_device));
00386 
00387         if (!config.enable_fa_decapsulation) {
00388                 /* Mark the old tunnel to be deleted */
00389                 old_tunnel_addr.s_addr = old.s_addr;
00390                 old_tunnel_expire = time(NULL) + OLD_TUNNEL_EXTRA_TIME;
00391         }
00392 
00393 #else
00394         DEBUG(DEBUG_INFO, "Restart tunneling - tunneling disabled\n");
00395 #endif
00396         return 0;
00397 }
00398 
00406 int stop_tunneling(void)
00407 {
00408         int ret = 1;
00409         char dev[IFNAMSIZ], *home_dev = NULL;
00410 
00411 #ifdef MN_ENABLE_TUNNELING
00412         DEBUG(DEBUG_INFO, "Stop tunneling\n");
00413 
00414         if (mn.current_adv == NULL)
00415                 LOG2(LOG_WARNING, "stop_tunneling - current_adv == NULL\n");
00416 
00417         if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {
00418                 /* remove the host route to the HA */
00419                 dev[0] = '\0';
00420                 if (dyn_ip_route_get(config.ha_ip_addr, dev, IFNAMSIZ) != 0 ||
00421                     dyn_ip_route_del(config.ha_ip_addr, dev) != 0) {
00422                         LOG2(LOG_ERR, "Could not remove host route to the "
00423                              "HA (dev=%s)\n", dev);
00424                 }
00425         }
00426 
00427         if (config.enable_fa_decapsulation)
00428                 home_dev = return_home_net_route();
00429 
00430         /* restore default route */
00431         DEBUG(DEBUG_INFO, "Restoring default route\n");
00432         if (dyn_ip_route_restore_default(home_dev) != 0 &&
00433             device_up(dyn_ip_get_saved_ifindex())) {
00434                 LOG2(LOG_ERR, "restoring default route failed\n");
00435                 ret = 0;
00436         }
00437 
00438         if (config.enable_fa_decapsulation) {
00439                 if (mn.current_adv)
00440                         remove_fa_host_routes(1);
00441         } else {
00442                 if (dyn_ip_tunnel_del(tunnel_device) != 0) {
00443                         LOG2(LOG_ERR, "tunnel delete failed\n");
00444                         ret = 0;
00445                 }
00446                 if (old_tunnel_expire != 0 &&
00447                     dyn_ip_tunnel_del(old_tunnel_device) != 0) {
00448                         LOG2(LOG_ERR, "tunnel delete failed for old tunnel\n");
00449                 }
00450                 old_tunnel_expire = 0;
00451         }
00452 #else
00453         DEBUG(DEBUG_INFO, "Stop tunneling - tunneling disabled\n");
00454 #endif
00455         mn.tunnel_up = 0;
00456         real_tunnel_up = 0;
00457         if (mn.current_adv != NULL) mn.current_adv->in_use = 0;
00458         return ret;
00459 }

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