Example #1
0
File: ipcalc.c Project: OLSR/olsrd
const char *
olsr_ip_prefix_to_string(const struct olsr_ip_prefix *prefix)
{
  /* We need for IPv6 an IP address + '/' + prefix and for IPv4 an IP address + '/' + a netmask */
  static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
  const char *rv;

  if (olsr_cnf->ip_version == AF_INET) {
    /* IPv4 */
    int len;
    union olsr_ip_addr netmask;
    rv = inet_ntop(AF_INET, &prefix->prefix.v4, buf, sizeof(buf));
    len = strlen(buf);
    buf[len++] = '/';
    olsr_prefix_to_netmask(&netmask, prefix->prefix_len);
    inet_ntop(AF_INET, &netmask.v4, buf + len, sizeof(buf) - len);
  } else {
    /* IPv6 */
    int len;
    rv = inet_ntop(AF_INET6, &prefix->prefix.v6, buf, sizeof(buf));
    len = strlen(buf);
    buf[len++] = '/';
    snprintf(buf + len, sizeof(buf) - len, "%d", prefix->prefix_len);
  }
  return rv;
}
/**
 * Insert a route in the kernel routing table
 *
 * @param destination the route to add
 *
 * @return negative on error
 */
int
olsr_ioctl_add_route(const struct rt_entry *rt)
{
  char if_name[IFNAMSIZ];
  struct rtentry kernel_route;
  union olsr_ip_addr mask;
  int rslt;

  OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));

  memset(&kernel_route, 0, sizeof(struct rtentry));

  ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
  ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
  ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;

  ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;

  if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
    return -1;
  }
  ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;

  if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
    ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_best->rtp_nexthop.gateway.v4;
  }

  kernel_route.rt_flags = olsr_rt_flags(rt);
  kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric);

  /*
   * Set interface
   */
  strcpy(if_name, if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
  kernel_route.rt_dev = if_name;

  /* delete existing default route before ? */
  if ((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) {
    delete_all_inet_gws();
    olsr_cnf->del_gws = false;
  }

  if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {

    /*
     * Send IPC route update message
     */
    ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1,
                           if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
  }

  return rslt;
}
Example #3
0
/*
 * Remove a route from the kernel
 * @param destination the route to remove
 * @return negative on error
 */
int
os_route_del_rtentry(const struct rt_entry *rt, int ip_version)
{
  MIB_IPFORWARDROW Row;
  union olsr_ip_addr mask;
  unsigned long Res;
  struct interface *iface = rt->rt_nexthop.interface;

  if (AF_INET != ip_version) {
    /*
     * Not implemented
     */
    return -1;
  }

  OLSR_DEBUG(LOG_NETWORKING, "KERN: Deleting %s\n", olsr_rt_to_string(rt));

  memset(&Row, 0, sizeof(Row));

  Row.dwForwardDest = rt->rt_dst.prefix.v4.s_addr;

  if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
    return -1;
  }
  Row.dwForwardMask = mask.v4.s_addr;
  Row.dwForwardPolicy = 0;
  Row.dwForwardNextHop = rt->rt_nexthop.gateway.v4.s_addr;
  Row.dwForwardIfIndex = iface->if_index;
  // MIB_IPROUTE_TYPE_DIRECT and MIB_IPROUTE_TYPE_INDIRECT
  Row.dwForwardType = (rt->rt_dst.prefix.v4.s_addr == rt->rt_nexthop.gateway.v4.s_addr) ? 3 : 4;
  Row.dwForwardProto = 3;       // MIB_IPPROTO_NETMGMT
  Row.dwForwardAge = INFINITE;
  Row.dwForwardNextHopAS = 0;
  Row.dwForwardMetric1 = olsr_fib_metric(&rt->rt_metric);
  Row.dwForwardMetric2 = -1;
  Row.dwForwardMetric3 = -1;
  Row.dwForwardMetric4 = -1;
  Row.dwForwardMetric5 = -1;

  Res = DeleteIpForwardEntry(&Row);

  if (Res != NO_ERROR) {
    OLSR_WARN(LOG_NETWORKING, "DeleteIpForwardEntry() = %08lx, %s", Res, win32_strerror(Res));

    // XXX - report error in a different way

    errno = Res;

    return -1;
  }
  return 0;
}
/**
 *Remove a route from the kernel
 *
 *@param destination the route to remove
 *
 *@return negative on error
 */
int
olsr_ioctl_del_route(const struct rt_entry *rt)
{
  struct rtentry kernel_route;
  union olsr_ip_addr mask;
  int rslt;

  OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));

  memset(&kernel_route, 0, sizeof(struct rtentry));

  ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET;
  ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET;
  ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET;

  ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;

  if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
    ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
  }

  if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
    return -1;
  } else {
    ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
  }

  kernel_route.rt_flags = olsr_rt_flags(rt);
  kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric);

  /*
   * Set interface
   */
  kernel_route.rt_dev = NULL;

  if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {

    /*
     * Send IPC route update message
     */
    ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
  }

  return rslt;
}
Example #5
0
/**
 *IP version 4
 *
 *@param ifp the interface to send on
 *@return nada
 */
static bool
serialize_hna4(struct interface *ifp)
{
  uint16_t remainsize, curr_size, needsize;
  /* preserve existing data in output buffer */
  union olsr_message *m;
  struct hnapair *pair;
  struct ip_prefix_list *h;

  /* No hna nets */
  if (ifp == NULL) {
    return false;
  }
  if (olsr_cnf->ip_version != AF_INET) {
    return false;
  }
  h = olsr_cnf->hna_entries;
  if (h == NULL) {
    return false;
  }

  remainsize = net_outbuffer_bytes_left(ifp);

  curr_size = OLSR_HNA_IPV4_HDRSIZE;

  /* calculate size needed for HNA */
  needsize = curr_size;
  while (h) {
    needsize += olsr_cnf->ipsize*2;
    h = h->next;
  }

  h = olsr_cnf->hna_entries;

  /* Send pending packet if not room in buffer */
  if (needsize > remainsize) {
    net_output(ifp);
    remainsize = net_outbuffer_bytes_left(ifp);
  }
  check_buffspace(curr_size, remainsize, "HNA");

  m = (union olsr_message *)msg_buffer;

  /* Fill header */
  m->v4.originator = olsr_cnf->main_addr.v4.s_addr;
  m->v4.hopcnt = 0;
  m->v4.ttl = MAX_TTL;
  m->v4.olsr_msgtype = HNA_MESSAGE;
  m->v4.olsr_vtime = ifp->valtimes.hna;

  pair = m->v4.message.hna.hna_net;

  for (; h != NULL; h = h->next) {
    union olsr_ip_addr ip_addr;
    if ((curr_size + (2 * olsr_cnf->ipsize)) > remainsize) {
      /* Only add HNA message if it contains data */
      if (curr_size > OLSR_HNA_IPV4_HDRSIZE) {
#ifdef DEBUG
        OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
#endif
        m->v4.seqno = htons(get_msg_seqno());
        m->v4.olsr_msgsize = htons(curr_size);
        net_outbuffer_push(ifp, msg_buffer, curr_size);
        curr_size = OLSR_HNA_IPV4_HDRSIZE;
        pair = m->v4.message.hna.hna_net;
      }
      net_output(ifp);
      remainsize = net_outbuffer_bytes_left(ifp);
      check_buffspace(curr_size + (2 * olsr_cnf->ipsize), remainsize, "HNA2");
    }
#ifdef DEBUG
    OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net));
#endif

    olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len);
#ifdef linux
    if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&h->net)) {
      /* this is the default route, overwrite it with the smart gateway */
      olsr_modifiy_inetgw_netmask(&ip_addr, h->net.prefix_len);
    }
#endif
    pair->addr = h->net.prefix.v4.s_addr;
    pair->netmask = ip_addr.v4.s_addr;
    pair++;
    curr_size += (2 * olsr_cnf->ipsize);
  }

  m->v4.seqno = htons(get_msg_seqno());
  m->v4.olsr_msgsize = htons(curr_size);

  net_outbuffer_push(ifp, msg_buffer, curr_size);

  //printf("Sending HNA (%d bytes)...\n", outputsize);
  return false;
}
Example #6
0
void
olsrd_print_cnf(struct olsrd_config *cnf)
{
    struct ip_prefix_list *h = cnf->hna_entries;
    struct olsr_if *in = cnf->interfaces;
    struct plugin_entry *pe = cnf->plugins;
    struct ip_prefix_list *ie = cnf->ipc_nets;

    printf(" *** olsrd configuration ***\n");

    printf("Debug Level      : %d\n", cnf->debug_level);
    if (cnf->ip_version == AF_INET6)
        printf("IpVersion        : 6\n");
    else
        printf("IpVersion        : 4\n");
    if (cnf->allow_no_interfaces)
        printf("No interfaces    : ALLOWED\n");
    else
        printf("No interfaces    : NOT ALLOWED\n");
    printf("TOS              : 0x%02x\n", cnf->tos);
    printf("OlsrPort          : 0x%03x\n", cnf->olsrport);
    printf("RtTable          : %u\n", cnf->rt_table);
    printf("RtTableDefault   : %u\n", cnf->rt_table_default);
    printf("RtTableTunnel    : %u\n", cnf->rt_table_tunnel);
    if (cnf->willingness_auto)
        printf("Willingness      : AUTO\n");
    else
        printf("Willingness      : %d\n", cnf->willingness);

    printf("IPC connections  : %d\n", cnf->ipc_connections);
    while (ie) {
        struct ipaddr_str strbuf;
        if (ie->net.prefix_len == olsr_cnf->maxplen) {
            printf("\tHost %s\n", olsr_ip_to_string(&strbuf, &ie->net.prefix));
        } else {
            printf("\tNet %s/%d\n", olsr_ip_to_string(&strbuf, &ie->net.prefix), ie->net.prefix_len);
        }
        ie = ie->next;
    }

    printf("Pollrate         : %0.2f\n", cnf->pollrate);

    printf("NIC ChangPollrate: %0.2f\n", cnf->nic_chgs_pollrate);

    printf("TC redundancy    : %d\n", cnf->tc_redundancy);

    printf("MPR coverage     : %d\n", cnf->mpr_coverage);

    printf("LQ level         : %d\n", cnf->lq_level);

    printf("LQ fish eye      : %d\n", cnf->lq_fish);

    printf("LQ aging factor  : %f\n", cnf->lq_aging);

    printf("LQ algorithm name: %s\n", cnf->lq_algorithm ? cnf->lq_algorithm : "default");

    printf("NAT threshold    : %f\n", cnf->lq_nat_thresh);

    printf("Clear screen     : %s\n", cnf->clear_screen ? "yes" : "no");

    printf("Use niit         : %s\n", cnf->use_niit ? "yes" : "no");

    printf("Smart Gateway    : %s\n", cnf->smart_gw_active ? "yes" : "no");

    printf("SmGw. Allow NAT  : %s\n", cnf->smart_gw_allow_nat ? "yes" : "no");

    printf("Smart Gw. Uplink : %s\n", GW_UPLINK_TXT[cnf->smart_gw_type]);

    printf("SmGw. Uplink NAT : %s\n", cnf->smart_gw_uplink_nat ? "yes" : "no");

    printf("Smart Gw. speed  : %d kbit/s up, %d kbit/s down\n",
           cnf->smart_gw_uplink, cnf->smart_gw_downlink);

    if (olsr_cnf->smart_gw_prefix.prefix_len == 0) {
        printf("# Smart Gw. prefix : ::/0\n");
    }
    else {
        printf("Smart Gw. prefix : %s\n", olsr_ip_prefix_to_string(&cnf->smart_gw_prefix));
    }

    /* Interfaces */
    if (in) {
        /*print interface default config*/
        printf(" InterfaceDefaults: \n");
        olsrd_print_interface_cnf(cnf->interface_defaults, cnf->interface_defaults, true);

        while (in)
        {
            if (cnf->interface_defaults!=in->cnf)
            {
                printf(" dev: \"%s\"\n", in->name);

                olsrd_print_interface_cnf(in->cnf, in->cnfi, false);
            }
            in = in->next;
        }
    }

    /* Plugins */
    if (pe) {
        printf("Plugins:\n");

        while (pe) {
            printf("\tName: \"%s\"\n", pe->name);
            pe = pe->next;
        }
    }

    /* Hysteresis */
    if (cnf->use_hysteresis) {
        printf("Using hysteresis:\n");
        printf("\tScaling      : %0.2f\n", cnf->hysteresis_param.scaling);
        printf("\tThr high/low : %0.2f/%0.2f\n", cnf->hysteresis_param.thr_high, cnf->hysteresis_param.thr_low);
    } else {
        printf("Not using hysteresis\n");
    }

    /* HNA IPv4 and IPv6 */
    if (h) {
        printf("HNA%d entries:\n", cnf->ip_version == AF_INET ? 4 : 6);
        while (h) {
            struct ipaddr_str buf;
            printf("\t%s/", olsr_ip_to_string(&buf, &h->net.prefix));
            if (cnf->ip_version == AF_INET) {
                union olsr_ip_addr ip;
                olsr_prefix_to_netmask(&ip, h->net.prefix_len);
                printf("%s\n", olsr_ip_to_string(&buf, &ip));
            } else {
                printf("%d\n", h->net.prefix_len);
            }
            h = h->next;
        }
    }
}
/*
 * Sends an add or delete message via the routing socket.
 * The message consists of:
 *  - a header i.e. struct rt_msghdr
 *  - 0-8 socket address structures
 */
static int
add_del_route(const struct rt_entry *rt, int add)
{
  struct rt_msghdr *rtm;               /* message to send to the routing socket */
  unsigned char buff[512];
  unsigned char *walker;               /* points within the buffer */
  struct sockaddr_in sin4;             /* internet style sockaddr */
  struct sockaddr_dl *sdl;             /* link level sockaddr */
  struct ifaddrs *addrs;
  struct ifaddrs *awalker;
  const struct rt_nexthop *nexthop;
  union olsr_ip_addr mask;             /* netmask as ip address */
  int sin_size, sdl_size;              /* payload of the message */
  int len;                             /* message size written to routing socket */

  if (add) {
    OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
  } else {
    OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
  }

  memset(buff, 0, sizeof(buff));
  memset(&sin4, 0, sizeof(sin4));

  sin4.sin_len = sizeof(sin4);
  sin4.sin_family = AF_INET;

  sin_size = 1 + ((sizeof(struct sockaddr_in) - 1) | (sizeof(long) - 1));
  sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));

  /**********************************************************************
   *                  FILL THE ROUTING MESSAGE HEADER
   **********************************************************************/

  /* position header to the beginning of the buffer */
  rtm = (struct rt_msghdr *)buff;

  rtm->rtm_version = RTM_VERSION;
  rtm->rtm_type = add ? RTM_ADD : RTM_DELETE;
  rtm->rtm_index = 0;           /* is ignored in outgoing messages */
  rtm->rtm_flags = olsr_rt_flags(rt);
  rtm->rtm_pid = OLSR_PID;
  rtm->rtm_seq = ++seq;

  /* walk to the end of the header */
  walker = buff + sizeof(struct rt_msghdr);

  /**********************************************************************
   *                  SET  DESTINATION OF THE ROUTE
   **********************************************************************/

#ifdef _WRS_KERNEL
  /*
   * vxWorks: change proto or tos
   */
  OLSR_PRINTF(8, "\t- Setting Protocol: 0\n");
  ((struct sockaddr_rt *)(&sin4))->srt_proto = 0;
  OLSR_PRINTF(8, "\t- Setting TOS: 0\n");
  ((struct sockaddr_rt *)(&sin4))->srt_tos = 0;
#endif

  sin4.sin_addr = rt->rt_dst.prefix.v4;
  memcpy(walker, &sin4, sizeof(sin4));
  walker += sin_size;
  rtm->rtm_addrs = RTA_DST;

  /**********************************************************************
   *                  SET GATEWAY OF THE ROUTE
   **********************************************************************/

#ifdef _WRS_KERNEL
  /*
   * vxWorks: Route with no gateway is deleted
   */
  if (add) {
#endif
    nexthop = olsr_get_nh(rt);
    if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
      sin4.sin_addr = nexthop->gateway.v4;
      memcpy(walker, &sin4, sizeof(sin4));
      walker += sin_size;
      rtm->rtm_addrs |= RTA_GATEWAY;
    }
    else {
      /*
       * Host is directly reachable, so add
       * the output interface MAC address.
       */
      if (getifaddrs(&addrs)) {
        fprintf(stderr, "\ngetifaddrs() failed\n");
        return -1;
      }

      for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
        if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
          break;

      if (awalker == NULL) {
        fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
        freeifaddrs(addrs);
        return -1;
      }

      /* sdl is "struct sockaddr_dl" */
      sdl = (struct sockaddr_dl *)awalker->ifa_addr;
      memcpy(walker, sdl, sdl->sdl_len);
      walker += sdl_size;
      rtm->rtm_addrs |= RTA_GATEWAY;
#ifdef RTF_CLONING
      rtm->rtm_flags |= RTF_CLONING;
#endif
#ifndef _WRS_KERNEL
      rtm->rtm_flags &= ~RTF_HOST;
#endif
      freeifaddrs(addrs);
    }
#ifdef _WRS_KERNEL
  }
#endif

  /**********************************************************************
   *                         SET  NETMASK
   **********************************************************************/

  if (0 == (rtm->rtm_flags & RTF_HOST)) {
    olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
    sin4.sin_addr = mask.v4;
    memcpy(walker, &sin4, sizeof(sin4));
    walker += sin_size;
    rtm->rtm_addrs |= RTA_NETMASK;
  }

  /**********************************************************************
   *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
   **********************************************************************/

  rtm->rtm_msglen = (unsigned short)(walker - buff);
  len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
  if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
    fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n",
              rtm->rtm_errno,strerror(errno));
    if (add) {
      fprintf(stderr, " Failed on Adding %s\n", olsr_rtp_to_string(rt->rt_best));
    } else {
      fprintf(stderr, " Failed on Deleting %s\n",olsr_rt_to_string(rt));
    }
  }
  return 0;
}
static int
add_del_route6(const struct rt_entry *rt, int add)
{
  struct rt_msghdr *rtm;
  unsigned char buff[512];
  unsigned char *walker;
  struct sockaddr_in6 sin6;
  struct sockaddr_dl sdl;
  const struct rt_nexthop *nexthop;
  int sin_size, sdl_size;
  int len;

  if (add) {
    OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
  } else {
    OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
  }

  memset(buff, 0, sizeof(buff));
  memset(&sin6, 0, sizeof(sin6));
  memset(&sdl, 0, sizeof(sdl));

  sin6.sin6_len = sizeof(sin6);
  sin6.sin6_family = AF_INET6;
  sdl.sdl_len = sizeof(sdl);
  sdl.sdl_family = AF_LINK;

  sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | (sizeof(long) - 1));
  sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));

  /**********************************************************************
   *                  FILL THE ROUTING MESSAGE HEADER
   **********************************************************************/

  /* position header to the beginning of the buffer */
  rtm = (struct rt_msghdr *)buff;
  rtm->rtm_version = RTM_VERSION;
  rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
  rtm->rtm_index = 0;
  rtm->rtm_flags = olsr_rt_flags(rt);
  rtm->rtm_pid = OLSR_PID;
  rtm->rtm_seq = ++seq;

  /* walk to the end of the header */
  walker = buff + sizeof(struct rt_msghdr);

  /**********************************************************************
   *                  SET  DESTINATION OF THE ROUTE
   **********************************************************************/

  memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
  memcpy(walker, &sin6, sizeof(sin6));
  walker += sin_size;
  rtm->rtm_addrs = RTA_DST;

  /**********************************************************************
   *                  SET GATEWAY OF THE ROUTE
   **********************************************************************/

  nexthop = olsr_get_nh(rt);
  if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
    memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
    memset(&sin6.sin6_addr.s6_addr, 0, 8);
    sin6.sin6_addr.s6_addr[0] = 0xfe;
    sin6.sin6_addr.s6_addr[1] = 0x80;
    sin6.sin6_scope_id = nexthop->iif_index;
#ifdef __KAME__
    *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
    sin6.sin6_scope_id = 0;
#endif
    memcpy(walker, &sin6, sizeof(sin6));
    walker += sin_size;
    rtm->rtm_addrs |= RTA_GATEWAY;
  }
  else {
    /*
     * Host is directly reachable, so add
     * the output interface MAC address.
     */
    memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
    memset(&sin6.sin6_addr.s6_addr, 0, 8);
    sin6.sin6_addr.s6_addr[0] = 0xfe;
    sin6.sin6_addr.s6_addr[1] = 0x80;
    sin6.sin6_scope_id = nexthop->iif_index;
#ifdef __KAME__
    *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
    sin6.sin6_scope_id = 0;
#endif
    memcpy(walker, &sin6, sizeof(sin6));
    walker += sin_size;
    rtm->rtm_addrs |= RTA_GATEWAY;
    rtm->rtm_flags |= RTF_GATEWAY;
  }

  /**********************************************************************
   *                         SET  NETMASK
   **********************************************************************/

  if (0 == (rtm->rtm_flags & RTF_HOST)) {
    olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
    memcpy(walker, &sin6, sizeof(sin6));
    walker += sin_size;
    rtm->rtm_addrs |= RTA_NETMASK;
  }

  /**********************************************************************
   *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
   **********************************************************************/

  rtm->rtm_msglen = (unsigned short)(walker - buff);
  len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
  if (len < 0 && !(errno == EEXIST || errno == ESRCH)) {
    fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
  }

  /*
   * If we get an EEXIST error while adding, delete and retry.
   */
  if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
    struct rt_msghdr *drtm;
    unsigned char dbuff[512];

    memset(dbuff, 0, sizeof(dbuff));
    drtm = (struct rt_msghdr *)dbuff;
    drtm->rtm_version = RTM_VERSION;
    drtm->rtm_type = RTM_DELETE;
    drtm->rtm_index = 0;
    drtm->rtm_flags = olsr_rt_flags(rt);
    drtm->rtm_seq = ++seq;

    walker = dbuff + sizeof(struct rt_msghdr);
    memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
    memcpy(walker, &sin6, sizeof(sin6));
    walker += sin_size;
    drtm->rtm_addrs = RTA_DST;
    drtm->rtm_msglen = (unsigned short)(walker - dbuff);
    len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
    if (len < 0) {
      fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
    }
    rtm->rtm_seq = ++seq;
    len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
    if (len < 0) {
      fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
    }
  }
  return 0;
}