/** * Load plugins and call the init callback * @param fail_fast if true OLSRd will exit if a plugin throws an error * during initialization */ void olsr_plugins_init(bool fail_fast) { struct plugin_entry *entry; struct olsr_plugin *plugin; OLSR_INFO(LOG_PLUGINS, "Loading configured plugins...\n"); /* first load anything requested but not already loaded */ for (entry = olsr_cnf->plugins; entry != NULL; entry = entry->next) { if (olsr_init_plugin(entry->name) == NULL) { if (fail_fast) { OLSR_ERROR(LOG_PLUGINS, "Cannot load plugin %s.\n", entry->name); olsr_exit(1); } OLSR_WARN(LOG_PLUGINS, "Cannot load plugin %s.\n", entry->name); } } /* now hookup parameters to plugins */ for (entry = olsr_cnf->plugins; entry != NULL; entry = entry->next) { plugin = olsr_get_plugin(entry->name); if (plugin == NULL) { if (fail_fast) { OLSR_ERROR(LOG_PLUGINS, "Internal error in plugin storage tree, cannot find plugin %s\n", entry->name); olsr_exit(1); } OLSR_WARN(LOG_PLUGINS, "Internal error in plugin storage tree, cannot find plugin %s\n", entry->name); } plugin->internal_params = entry->params; } }
/* * Creates a zero-length locking file and use fcntl to * place an exclusive lock over it. The lock will be * automatically erased when the olsrd process ends, * so it will even work well with a SIGKILL. * * Additionally the lock can be killed by removing the * locking file. */ static int olsr_create_lock_file(bool noExitOnFail) { #ifdef WIN32 HANDLE lck = CreateEvent(NULL, TRUE, FALSE, lock_file_name); if (NULL == lck || ERROR_ALREADY_EXISTS == GetLastError()) { if (noenoExitOnFail) { return -1; } if (NULL == lck) { fprintf(stderr, "Error, cannot create OLSR lock '%s'.\n", lock_file_name); } else { CloseHandle(lck); fprintf(stderr, "Error, cannot aquire OLSR lock '%s'.\n" "Another OLSR instance might be running.\n", lock_file_name); } olsr_exit("", EXIT_FAILURE); } #else struct flock lck; /* create file for lock */ lock_fd = open(lock_file_name, O_WRONLY | O_CREAT, S_IRWXU); if (lock_fd == 0) { if (noExitOnFail) { return -1; } fprintf(stderr, "Error, cannot create OLSR lock '%s'.\n", lock_file_name); olsr_exit("", EXIT_FAILURE); } /* create exclusive lock for the whole file */ lck.l_type = F_WRLCK; lck.l_whence = SEEK_SET; lck.l_start = 0; lck.l_len = 0; lck.l_pid = 0; if (fcntl(lock_fd, F_SETLK, &lck) == -1) { close(lock_fd); if (noExitOnFail) { return -1; } fprintf(stderr, "Error, cannot aquire OLSR lock '%s'.\n" "Another OLSR instance might be running.\n", lock_file_name); olsr_exit("", EXIT_FAILURE); } #endif return 0; }
/** *Create the socket to use for IPC to the *GUI front-end * *@return the socket FD */ int ipc_init(void) { //int flags; struct sockaddr_in sin; int yes = 1; /* Add parser function */ olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS, 0); /* get an internet domain socket */ if ((ipc_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("IPC socket"); olsr_exit("IPC socket", EXIT_FAILURE); } if(setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) { perror("SO_REUSEADDR failed"); return 0; } /* complete the socket structure */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(IPC_PORT); /* bind the socket to the port number */ if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) { perror("IPC bind"); OLSR_PRINTF(1, "Will retry in 10 seconds...\n"); sleep(10); if(bind(ipc_sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) { perror("IPC bind"); olsr_exit("IPC bind", EXIT_FAILURE); } OLSR_PRINTF(1, "OK\n"); } /* show that we are willing to listen */ if(listen(ipc_sock, olsr_cnf->ipc_connections) == -1) { perror("IPC listen"); olsr_exit("IPC listen", EXIT_FAILURE); } /* Register the socket with the socket parser */ add_olsr_socket(ipc_sock, &ipc_accept); return ipc_sock; }
void olsr_pktbuf_grow_capa(olsr_pktbuf_t *self) { int new_capa = (int)self->capa + BUF_GROW_SIZE; if (self->capa == 0) { olsr_exit("try to modify read only pktbuf.", 1); } self->data = (olsr_u8_t *)realloc(self->data, new_capa); if (self->data == NULL) { olsr_exit("cannot allocate memory.", 1); } self->capa = new_capa; }
void ipc_accept(int fd) { socklen_t addrlen; struct sockaddr_in pin; char *addr; addrlen = sizeof (struct sockaddr_in); if ((ipc_conn = accept(fd, (struct sockaddr *) &pin, &addrlen)) == -1) { perror("IPC accept"); olsr_exit("IPC accept", EXIT_FAILURE); } else { OLSR_PRINTF(1, "Front end connected\n"); addr = inet_ntoa(pin.sin_addr); if(ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr)) { ipc_active = OLSR_TRUE; ipc_send_net_info(ipc_conn); ipc_send_all_routes(ipc_conn); OLSR_PRINTF(1, "Connection from %s\n",addr); } else { OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr); olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr); CLOSE(ipc_conn); } } }
/** * Init datastructures for maintaining timers. */ void olsr_init_timers(void) { int idx; OLSR_PRINTF(3, "Initializing scheduler.\n"); /* Grab initial timestamp */ if (gettimeofday(&first_tv, NULL)) { olsr_exit("OS clock is not working, have to shut down OLSR", 1); } last_tv = first_tv; now_times = olsr_times(); for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) { list_head_init(&timer_wheel[idx]); } /* * Reset the last timer run. */ timer_last_run = now_times; /* Allocate a cookie for the block based memeory manager. */ timer_mem_cookie = olsr_alloc_cookie("timer_entry", OLSR_COOKIE_TYPE_MEMORY); olsr_cookie_set_memory_size(timer_mem_cookie, sizeof(struct timer_entry)); }
unsigned char *zpacket_redistribute (uint16_t cmd, unsigned char type) { unsigned char *data, *pnt; uint16_t size; data = olsr_malloc(ZEBRA_MAX_PACKET_SIZ , "QUAGGA: New redistribute packet"); pnt = &data[2]; switch (zebra.version) { case 0: *pnt++ = (unsigned char) cmd; break; case 1: case 2: *pnt++ = ZEBRA_HEADER_MARKER; *pnt++ = zebra.version; cmd = htons(cmd); memcpy(pnt, &cmd, sizeof cmd); pnt += sizeof cmd; break; default: olsr_exit("(QUAGGA) Unsupported zebra packet version!\n", EXIT_FAILURE); break; } *pnt++ = type; size = htons(pnt - data); memcpy(data, &size, sizeof size); return data; }
/* * A wrapper around times(2). Note, that this function has some * portability problems, so do not rely on absolute values returned. * Under Linux, uclibc and libc directly call the sys_times() located * in kernel/sys.c and will only return an error if the tms_buf is * not writeable. */ static uint32_t olsr_times(void) { struct timeval tv; uint32_t t; if (gettimeofday(&tv, NULL) != 0) { olsr_exit("OS clock is not working, have to shut down OLSR", 1); } /* test if time jumped backward or more than 60 seconds forward */ if (tv.tv_sec < last_tv.tv_sec || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec) || tv.tv_sec - last_tv.tv_sec > 60) { OLSR_PRINTF(1, "Time jump (%d.%06d to %d.%06d)\n", (int32_t) (last_tv.tv_sec), (int32_t) (last_tv.tv_usec), (int32_t) (tv.tv_sec), (int32_t) (tv.tv_usec)); t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000; t++; /* advance time by one millisecond */ first_tv = tv; first_tv.tv_sec -= (t / 1000); first_tv.tv_usec -= ((t % 1000) * 1000); if (first_tv.tv_usec < 0) { first_tv.tv_sec--; first_tv.tv_usec += 1000000; } last_tv = tv; return t; } last_tv = tv; return (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000; }
/** * Setup global interface options (icmp redirect, ip forwarding, rp_filter) * @return 1 on success 0 on failure */ void net_os_set_global_ifoptions(void) { if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, olsr_cnf->set_ip_forward ? OLSRD_FORWARD_VALUE : 0 )) { OLSR_PRINTF(1, "Warning, could not enable IP forwarding!\n" "you should manually ensure that IP forwarding is enabled!\n\n"); olsr_startup_sleep(3); } else if ((!olsr_cnf->set_ip_forward) && (orig_fwd_state != OLSRD_FORWARD_VALUE)) { olsr_exit("IP forwarding not activated, shutting down.\n", 1); } if (olsr_cnf->smart_gw_active) { char procfile[FILENAME_MAX]; /* Generate the procfile name */ if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) { snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF); if (writeToProc(procfile, &orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) { OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel!\n" "you should manually ensure that IP spoof filtering is disabled!\n\n"); olsr_startup_sleep(3); } } #if 0 // should not be necessary for IPv6 if (olsr_cnf->ip_version == AF_INET6) { snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF6); if (writeToProc(procfile, &orig_tunnel6_rp_filter, OLSRD_SPOOF_VALUE)) { OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel6!\n" "you should manually ensure that IP spoof filtering is disabled!\n\n"); olsr_startup_sleep(3); } } #endif } if (olsr_cnf->ip_version == AF_INET) { if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) { OLSR_PRINTF(1, "WARNING! Could not disable ICMP redirects!\n" "you should manually ensure that ICMP redirects are disabled!\n\n"); olsr_startup_sleep(3); } /* check kernel version and disable global rp_filter */ if (is_at_least_linuxkernel_2_6_31()) { if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, OLSRD_SPOOF_VALUE)) { OLSR_PRINTF(1, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n" "you should manually ensure that rp_filter is disabled!\n\n"); olsr_startup_sleep(3); } } } return; }
static void check_buffspace(int msgsize, int buffsize, const char *type) { if (msgsize > buffsize) { char buf[1024]; snprintf(buf, sizeof(buf), "%s: %s build, output buffer too small (%d/%u)", __func__, type, msgsize, buffsize); olsr_exit(buf, EXIT_FAILURE); } }
static void check_buffspace(int msgsize, int buffsize, const char *type) { if (msgsize > buffsize) { OLSR_PRINTF(1, "%s build, outputbuffer to small(%d/%u)!\n", type, msgsize, buffsize); olsr_syslog(OLSR_LOG_ERR, "%s build, outputbuffer to small(%d/%u)!\n", type, msgsize, buffsize); olsr_exit(__func__, EXIT_FAILURE); } }
/** * Activate a LQ handler * @param name */ static void activate_lq_handler(const char *name) { struct lq_handler_node *node; node = (struct lq_handler_node *)avl_find(&lq_handler_tree, name); if (node == NULL) { OLSR_PRINTF(1, "Error, unknown lq_handler '%s'\n", name); olsr_exit("", 1); } OLSR_PRINTF(1, "Using '%s' algorithm for lq calculation.\n", name); active_lq_handler = node->handler; active_lq_handler->initialize(); }
void * olsr_malloc(size_t size, const char *id) { void *ptr = NULL; if (size > 0 ) //Zero byte memory allocation fix { if ((ptr = malloc(size)) == 0) { olsr_exit((char *)id, EXIT_FAILURE); } //Added for Solaris mismatch memset(ptr, 0, size); //Added for Solaris mismatch } return ptr; }
/** * Enables all plugins of a certain type * @param type PLUGIN_TYPE_ALL, PLUGIN_TYPE_LQ or PLUGIN_TYPE_DEFAULT * @param fail_fast if true OLSRd will exit if a plugin throws an error * by the enable callback */ void olsr_plugins_enable(enum plugin_type type, bool fail_fast) { struct olsr_plugin *plugin, *iterator; /* activate all plugins (configured and static linked ones) */ OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, iterator) { if ((type != PLUGIN_TYPE_ALL && type != plugin->type) || plugin->internal_active) { continue; } if (olsr_enable_plugin(plugin)) { if (fail_fast) { OLSR_ERROR(LOG_PLUGINS, "Error, cannot activate plugin %s.\n", plugin->name); olsr_exit(1); } OLSR_WARN(LOG_PLUGINS, "Error, cannot activate plugin %s.\n", plugin->name); } } OLSR_INFO(LOG_PLUGINS, "All plugins loaded.\n"); }
/** *Creates a nonblocking IPv6 socket *@param sin sockaddr_in6 struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int os_getsocket6(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto) { struct sockaddr_in6 sin6; int on; int sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno)); olsr_exit(EXIT_FAILURE); } #ifdef IPV6_V6ONLY on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno)); } #endif //#ifdef SO_BROADCAST /* if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); close(sock); return (-1); } */ //#endif #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) { OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on); break; } if (on <= 8 * 1024) { OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno)); break; } } } #endif on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } /* * we are abusing "on" here. The value is 1 which is our intended * hop limit value. */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, if_name) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } if (bindto == NULL) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); bindto = (union olsr_sockaddr *)&sin6; } if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } os_socket_set_nonblocking(sock); return sock; }
/** *Creates a nonblocking broadcast socket. *@param sa sockaddr struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int os_getsocket4(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto) { struct sockaddr_in sin4; int on; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno)); olsr_exit(EXIT_FAILURE); } on = 1; #ifdef SO_BROADCAST if (bindto) { if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } } #endif if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) { OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on); break; } if (on <= 8 * 1024) { OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno)); break; } } } #endif /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, if_name) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } if (bindto == NULL) { memset(&sin4, 0, sizeof(sin4)); sin4.sin_family = AF_INET; sin4.sin_port = htons(port); sin4.sin_addr.s_addr = 0; bindto = (union olsr_sockaddr *)&sin4; } if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) { #if !defined(REMOVE_LOG_ERROR) struct ipaddr_str buf; #endif OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to %s/%d: %s (%d)\n", inet_ntop(AF_INET, &sin4.sin_addr, buf.buf, sizeof(buf)), port, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } os_socket_set_nonblocking(sock); return sock; }
/* * Allocate a fixed amount of memory based on a passed in cookie type. */ void * olsr_cookie_malloc(struct olsr_cookie_info *ci) { void *ptr; struct olsr_cookie_mem_brand *branding; struct list_node *free_list_node; #ifdef OLSR_COOKIE_DEBUG bool reuse = false; #endif /* * Check first if we have reusable memory. */ if (!ci->ci_free_list_usage) { /* * No reusable memory block on the free_list. */ ptr = calloc(1, ci->ci_size + sizeof(struct olsr_cookie_mem_brand)); if (!ptr) { const char *const err_msg = strerror(errno); OLSR_PRINTF(1, "OUT OF MEMORY: %s\n", err_msg); olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %s\n", err_msg); olsr_exit(ci->ci_name, EXIT_FAILURE); } } else { /* * There is a memory block on the free list. * Carve it out of the list, and clean. */ free_list_node = ci->ci_free_list.next; list_remove(free_list_node); ptr = (void *)free_list_node; memset(ptr, 0, ci->ci_size); ci->ci_free_list_usage--; #ifdef OLSR_COOKIE_DEBUG reuse = true; #endif } /* * Now brand mark the end of the memory block with a short signature * indicating presence of a cookie. This will be checked against * When the block is freed to detect corruption. */ branding = (struct olsr_cookie_mem_brand *)ARM_NOWARN_ALIGN(((unsigned char *)ptr + ci->ci_size)); memcpy(&branding->cmb_sig, "cookie", 6); branding->cmb_id = ci->ci_id; /* Stats keeping */ olsr_cookie_usage_incr(ci->ci_id); #ifdef OLSR_COOKIE_DEBUG OLSR_PRINTF(1, "MEMORY: alloc %s, %p, %u bytes%s\n", ci->ci_name, ptr, ci->ci_size, reuse ? ", reuse" : ""); #endif return ptr; }
void olsr_remove_interface(struct olsr_if * iface) { struct interface *ifp, *tmp_ifp; ifp = iface->interf; OLSR_PRINTF(1, "Removing interface %s (%d)\n", iface->name, ifp->if_index); olsr_syslog(OLSR_LOG_INFO, "Removing interface %s\n", iface->name); olsr_delete_link_entry_by_ip(&ifp->ip_addr); /* *Call possible ifchange functions registered by plugins */ olsr_trigger_ifchange(ifp->if_index, ifp, IFCHG_IF_REMOVE); /* cleanup routes over this interface */ olsr_delete_interface_routes(ifp->if_index); /* Dequeue */ if (ifp == ifnet) { ifnet = ifp->int_next; } else { tmp_ifp = ifnet; while (tmp_ifp->int_next != ifp) { tmp_ifp = tmp_ifp->int_next; } tmp_ifp->int_next = ifp->int_next; } /* Remove output buffer */ net_remove_buffer(ifp); /* Check main addr */ /* deactivated to prevent change of originator IP */ #if 0 if (ipequal(&olsr_cnf->main_addr, &ifp->ip_addr)) { if (ifnet == NULL) { /* No more interfaces */ memset(&olsr_cnf->main_addr, 0, olsr_cnf->ipsize); OLSR_PRINTF(1, "No more interfaces...\n"); } else { struct ipaddr_str buf; olsr_cnf->main_addr = ifnet->ip_addr; OLSR_PRINTF(1, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr)); olsr_syslog(OLSR_LOG_INFO, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr)); } } #endif /* 0 */ /* * Deregister functions for periodic message generation */ olsr_stop_timer(ifp->hello_gen_timer); olsr_stop_timer(ifp->tc_gen_timer); olsr_stop_timer(ifp->mid_gen_timer); olsr_stop_timer(ifp->hna_gen_timer); iface->configured = 0; iface->interf = NULL; /* Close olsr socket */ remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL); close(ifp->olsr_socket); remove_olsr_socket(ifp->send_socket, &olsr_input, NULL); close(ifp->send_socket); /* Free memory */ free(ifp->int_name); free(ifp); if ((ifnet == NULL) && (!olsr_cnf->allow_no_interfaces)) { olsr_syslog(OLSR_LOG_INFO, "No more active interfaces - exiting.\n"); olsr_exit("No more active interfaces - exiting.\n", EXIT_FAILURE); } }
unsigned char *zpacket_route(uint16_t cmd, struct zroute *r) { int count; uint8_t len; uint16_t size, safi; uint32_t ind, metric; unsigned char *cmdopt, *t; cmdopt = olsr_malloc(ZEBRA_MAX_PACKET_SIZ, "QUAGGA: New route packet"); t = &cmdopt[2]; switch (zebra.version) { case 0: *t++ = (unsigned char) cmd; break; case 1: case 2: *t++ = ZEBRA_HEADER_MARKER; *t++ = zebra.version; cmd = htons(cmd); memcpy(t, &cmd, sizeof cmd); t += sizeof cmd; break; default: olsr_exit("(QUAGGA) Unsupported zebra packet version!\n", EXIT_FAILURE); break; } *t++ = r->type; *t++ = r->flags; *t++ = r->message; switch (zebra.version) { case 0: case 1: break; case 2: safi = htons(r->safi); memcpy(t, &safi, sizeof safi); t += sizeof safi; break; default: olsr_exit("(QUAGGA) Unsupported zebra packet version!\n", EXIT_FAILURE); break; } *t++ = r->prefixlen; len = (r->prefixlen + 7) / 8; if (olsr_cnf->ip_version == AF_INET) memcpy(t, &r->prefix.v4.s_addr, len); else memcpy(t, r->prefix.v6.s6_addr, len); t = t + len; if (r->message & ZAPI_MESSAGE_NEXTHOP) { *t++ = r->nexthop_num + r->ifindex_num; for (count = 0; count < r->nexthop_num; count++) { if (olsr_cnf->ip_version == AF_INET) { *t++ = ZEBRA_NEXTHOP_IPV4; memcpy(t, &r->nexthop[count].v4.s_addr, sizeof r->nexthop[count].v4.s_addr); t += sizeof r->nexthop[count].v4.s_addr; } else { *t++ = ZEBRA_NEXTHOP_IPV6; memcpy(t, r->nexthop[count].v6.s6_addr, sizeof r->nexthop[count].v6.s6_addr); t += sizeof r->nexthop[count].v6.s6_addr; } } for (count = 0; count < r->ifindex_num; count++) { *t++ = ZEBRA_NEXTHOP_IFINDEX; ind = htonl(r->ifindex[count]); memcpy(t, &ind, sizeof ind); t += sizeof ind; } } if ((r->message & ZAPI_MESSAGE_DISTANCE) > 0) *t++ = r->distance; if ((r->message & ZAPI_MESSAGE_METRIC) > 0) { metric = htonl(r->metric); memcpy(t, &metric, sizeof metric); t += sizeof metric; } size = htons(t - cmdopt); memcpy(cmdopt, &size, sizeof size); return cmdopt; }
/* * Creates a zero-length locking file and use fcntl to * place an exclusive lock over it. The lock will be * automatically erased when the olsrd process ends, * so it will even work well with a SIGKILL. * * Additionally the lock can be killed by removing the * locking file. */ static int olsr_create_lock_file(bool noExitOnFail) { #ifdef WIN32 bool success; HANDLE lck; lck = CreateFile(lock_file_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); CreateEvent(NULL, TRUE, FALSE, lock_file_name); if (INVALID_HANDLE_VALUE == lck || ERROR_ALREADY_EXISTS == GetLastError()) { if (noExitOnFail) { return -1; } if (NULL == lck) { fprintf(stderr, "Error, cannot create OLSR lock '%s'.\n", lock_file_name); } else { CloseHandle(lck); fprintf(stderr, "Error, cannot aquire OLSR lock '%s'.\n" "Another OLSR instance might be running.\n", lock_file_name); } olsr_exit("", EXIT_FAILURE); } success = LockFile( lck, 0, 0, 0, 0); if (!success) { CloseHandle(lck); if (noExitOnFail) { return -1; } fprintf(stderr, "Error, cannot aquire OLSR lock '%s'.\n" "Another OLSR instance might be running.\n", lock_file_name); olsr_exit("", EXIT_FAILURE); } #else struct flock lck; /* create file for lock */ lock_fd = open(lock_file_name, O_WRONLY | O_CREAT, S_IRWXU); if (lock_fd == 0) { if (noExitOnFail) { return -1; } fprintf(stderr, "Error, cannot create OLSR lock '%s'.\n", lock_file_name); olsr_exit("", EXIT_FAILURE); } /* create exclusive lock for the whole file */ lck.l_type = F_WRLCK; lck.l_whence = SEEK_SET; lck.l_start = 0; lck.l_len = 0; lck.l_pid = 0; if (fcntl(lock_fd, F_SETLK, &lck) == -1) { close(lock_fd); if (noExitOnFail) { return -1; } fprintf(stderr, "Error, cannot aquire OLSR lock '%s'.\n" "Another OLSR instance might be running.\n", lock_file_name); olsr_exit("", EXIT_FAILURE); } #endif return 0; }
/** * Process command line arguments passed to olsrd * */ static int olsr_process_arguments(int argc, char *argv[], struct olsrd_config *cnf, struct if_config_options *ifcnf) { while (argc > 1) { NEXT_ARG; #ifdef WIN32 /* *Interface list */ if (strcmp(*argv, "-int") == 0) { ListInterfaces(); exit(0); } #endif /* *Configfilename */ if (strcmp(*argv, "-f") == 0) { fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n"); olsr_exit(__func__, EXIT_FAILURE); } /* *Use IP version 6 */ if (strcmp(*argv, "-ipv6") == 0) { cnf->ip_version = AF_INET6; continue; } /* *Broadcast address */ if (strcmp(*argv, "-bcast") == 0) { struct in_addr in; NEXT_ARG; CHECK_ARGC; if (inet_aton(*argv, &in) == 0) { printf("Invalid broadcast address! %s\nSkipping it!\n", *argv); continue; } memcpy(&ifcnf->ipv4_multicast.v4, &in.s_addr, sizeof(ifcnf->ipv4_multicast.v4)); continue; } /* * Set LQ level */ if (strcmp(*argv, "-lql") == 0) { int tmp_lq_level; NEXT_ARG; CHECK_ARGC; /* Sanity checking is done later */ sscanf(*argv, "%d", &tmp_lq_level); olsr_cnf->lq_level = tmp_lq_level; continue; } /* * Set LQ winsize */ if (strcmp(*argv, "-lqa") == 0) { float tmp_lq_aging; NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &tmp_lq_aging); if (tmp_lq_aging < MIN_LQ_AGING || tmp_lq_aging > MAX_LQ_AGING) { printf("LQ aging factor %f not allowed. Range [%f-%f]\n", tmp_lq_aging, MIN_LQ_AGING, MAX_LQ_AGING); olsr_exit(__func__, EXIT_FAILURE); } olsr_cnf->lq_aging = tmp_lq_aging; continue; } /* * Set NAT threshold */ if (strcmp(*argv, "-lqnt") == 0) { float tmp_lq_nat_thresh; NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &tmp_lq_nat_thresh); if (tmp_lq_nat_thresh < 0.1 || tmp_lq_nat_thresh > 1.0) { printf("NAT threshold %f not allowed. Range [%f-%f]\n", tmp_lq_nat_thresh, 0.1, 1.0); olsr_exit(__func__, EXIT_FAILURE); } olsr_cnf->lq_nat_thresh = tmp_lq_nat_thresh; continue; } /* * Enable additional debugging information to be logged. */ if (strcmp(*argv, "-d") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%d", &cnf->debug_level); continue; } /* * Interfaces to be used by olsrd. */ if (strcmp(*argv, "-i") == 0) { NEXT_ARG; CHECK_ARGC; if (*argv[0] == '-') { fprintf(stderr, "You must provide an interface label!\n"); olsr_exit(__func__, EXIT_FAILURE); } printf("Queuing if %s\n", *argv); olsr_create_olsrif(*argv, false); while ((argc - 1) && (argv[1][0] != '-')) { NEXT_ARG; printf("Queuing if %s\n", *argv); olsr_create_olsrif(*argv, false); } continue; } /* * Set the hello interval to be used by olsrd. * */ if (strcmp(*argv, "-hint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &ifcnf->hello_params.emission_interval); ifcnf->hello_params.validity_time = ifcnf->hello_params.emission_interval * 3; continue; } /* * Set the HNA interval to be used by olsrd. * */ if (strcmp(*argv, "-hnaint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &ifcnf->hna_params.emission_interval); ifcnf->hna_params.validity_time = ifcnf->hna_params.emission_interval * 3; continue; } /* * Set the MID interval to be used by olsrd. * */ if (strcmp(*argv, "-midint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &ifcnf->mid_params.emission_interval); ifcnf->mid_params.validity_time = ifcnf->mid_params.emission_interval * 3; continue; } /* * Set the tc interval to be used by olsrd. * */ if (strcmp(*argv, "-tcint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &ifcnf->tc_params.emission_interval); ifcnf->tc_params.validity_time = ifcnf->tc_params.emission_interval * 3; continue; } /* * Set the polling interval to be used by olsrd. */ if (strcmp(*argv, "-T") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%f", &cnf->pollrate); continue; } /* * Should we display the contents of packages beeing sent? */ if (strcmp(*argv, "-dispin") == 0) { parser_set_disp_pack_in(true); continue; } /* * Should we display the contents of incoming packages? */ if (strcmp(*argv, "-dispout") == 0) { net_set_disp_pack_out(true); continue; } /* * Should we set up and send on a IPC socket for the front-end? */ if (strcmp(*argv, "-ipc") == 0) { cnf->ipc_connections = 1; continue; } /* * IPv6 multicast addr */ if (strcmp(*argv, "-multi") == 0) { struct in6_addr in6; NEXT_ARG; CHECK_ARGC; if (inet_pton(AF_INET6, *argv, &in6) <= 0) { fprintf(stderr, "Failed converting IP address %s\n", *argv); exit(EXIT_FAILURE); } memcpy(&ifcnf->ipv6_multicast, &in6, sizeof(struct in6_addr)); continue; } /* * Host emulation */ if (strcmp(*argv, "-hemu") == 0) { struct in_addr in; struct olsr_if *ifa; NEXT_ARG; CHECK_ARGC; if (inet_pton(AF_INET, *argv, &in) <= 0) { fprintf(stderr, "Failed converting IP address %s\n", *argv); exit(EXIT_FAILURE); } /* Add hemu interface */ ifa = olsr_create_olsrif("hcif01", true); if (!ifa) continue; ifa->cnf = get_default_if_config(); ifa->host_emul = true; memcpy(&ifa->hemu_ip, &in, sizeof(union olsr_ip_addr)); cnf->host_emul = true; continue; } /* * Delete possible default GWs */ if (strcmp(*argv, "-delgw") == 0) { olsr_cnf->del_gws = true; continue; } if (strcmp(*argv, "-nofork") == 0) { cnf->no_fork = true; continue; } return -1; } return 0; }
int main(int argc, char *argv[]) { struct if_config_options *default_ifcnf; char conf_file_name[FILENAME_MAX]; struct ipaddr_str buf; bool loadedConfig = false; int i; #ifdef LINUX_NETLINK_ROUTING struct interface *ifn; #endif #ifdef WIN32 WSADATA WsaData; size_t len; #endif /* paranoia checks */ assert(sizeof(uint8_t) == 1); assert(sizeof(uint16_t) == 2); assert(sizeof(uint32_t) == 4); assert(sizeof(int8_t) == 1); assert(sizeof(int16_t) == 2); assert(sizeof(int32_t) == 4); printf("\n *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host); if (argc == 2) { if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "/?") == 0) { print_usage(false); exit(0); } if (strcmp(argv[1], "-v") == 0) { exit(0); } } debug_handle = stdout; #ifndef WIN32 olsr_argv = argv; #endif setbuf(stdout, NULL); setbuf(stderr, NULL); #ifndef WIN32 /* Check if user is root */ if (geteuid()) { fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n"); exit(EXIT_FAILURE); } #else DisableIcmpRedirects(); if (WSAStartup(0x0202, &WsaData)) { fprintf(stderr, "Could not initialize WinSock.\n"); olsr_exit(__func__, EXIT_FAILURE); } #endif /* Open syslog */ olsr_openlog("olsrd"); /* Using PID as random seed */ srandom(getpid()); /* Init widely used statics */ memset(&all_zero, 0, sizeof(union olsr_ip_addr)); /* * Set configfile name and * check if a configfile name was given as parameter */ #ifdef WIN32 #ifndef WINCE GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11); #else conf_file_name[0] = 0; #endif len = strlen(conf_file_name); if (len == 0 || conf_file_name[len - 1] != '\\') conf_file_name[len++] = '\\'; strscpy(conf_file_name + len, "olsrd.conf", sizeof(conf_file_name) - len); #else strscpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, sizeof(conf_file_name)); #endif olsr_cnf = olsrd_get_default_cnf(); for (i=1; i < argc-1;) { if (strcmp(argv[i], "-f") == 0) { loadedConfig = true; if (olsrmain_load_config(argv[i+1]) < 0) { exit(EXIT_FAILURE); } if (i+2 < argc) { memmove(&argv[i], &argv[i+2], sizeof(*argv) * (argc-i-1)); } argc -= 2; } else { i++; } } /* * set up configuration prior to processing commandline options */ if (!loadedConfig && olsrmain_load_config(conf_file_name) == 0) { loadedConfig = true; } if (!loadedConfig) { olsrd_free_cnf(olsr_cnf); olsr_cnf = olsrd_get_default_cnf(); } default_ifcnf = get_default_if_config(); if (default_ifcnf == NULL) { fprintf(stderr, "No default ifconfig found!\n"); exit(EXIT_FAILURE); } /* Initialize timers */ olsr_init_timers(); /* * Process olsrd options. */ if (olsr_process_arguments(argc, argv, olsr_cnf, default_ifcnf) < 0) { print_usage(true); olsr_exit(__func__, EXIT_FAILURE); } /* * Set configuration for command-line specified interfaces */ set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf); /* free the default ifcnf */ free(default_ifcnf); /* Sanity check configuration */ if (olsrd_sanity_check_cnf(olsr_cnf) < 0) { fprintf(stderr, "Bad configuration!\n"); olsr_exit(__func__, EXIT_FAILURE); } /* * Establish file lock to prevent multiple instances */ if (olsr_cnf->lock_file) { strscpy(lock_file_name, olsr_cnf->lock_file, sizeof(lock_file_name)); } else { size_t l; #ifdef DEFAULT_LOCKFILE_PREFIX strscpy(lock_file_name, DEFAULT_LOCKFILE_PREFIX, sizeof(lock_file_name)); #else strscpy(lock_file_name, conf_file_name, sizeof(lock_file_name)); #endif l = strlen(lock_file_name); snprintf(&lock_file_name[l], sizeof(lock_file_name) - l, "-ipv%d.lock", olsr_cnf->ip_version == AF_INET ? 4 : 6); } /* * Print configuration */ if (olsr_cnf->debug_level > 1) { olsrd_print_cnf(olsr_cnf); } def_timer_ci = olsr_alloc_cookie("Default Timer Cookie", OLSR_COOKIE_TYPE_TIMER); /* * socket for ioctl calls */ olsr_cnf->ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0); if (olsr_cnf->ioctl_s < 0) { #ifndef WIN32 olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m"); #endif olsr_exit(__func__, 0); } #ifdef LINUX_NETLINK_ROUTING olsr_cnf->rtnl_s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (olsr_cnf->rtnl_s < 0) { olsr_syslog(OLSR_LOG_ERR, "rtnetlink socket: %m"); olsr_exit(__func__, 0); } fcntl(olsr_cnf->rtnl_s, F_SETFL, O_NONBLOCK); if ((olsr_cnf->rt_monitor_socket = rtnetlink_register_socket(RTMGRP_LINK)) < 0) { olsr_syslog(OLSR_LOG_ERR, "rtmonitor socket: %m"); olsr_exit(__func__, 0); } #endif /* * create routing socket */ #if defined __FreeBSD__ || __FreeBSD_kernel__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__ olsr_cnf->rts = socket(PF_ROUTE, SOCK_RAW, 0); if (olsr_cnf->rts < 0) { olsr_syslog(OLSR_LOG_ERR, "routing socket: %m"); olsr_exit(__func__, 0); } #endif #ifdef LINUX_NETLINK_ROUTING /* initialize gateway system */ if (olsr_cnf->smart_gw_active) { if (olsr_init_gateways()) { olsr_exit("Cannot initialize gateway tunnels", 1); } } /* initialize niit if index */ if (olsr_cnf->use_niit) { olsr_init_niit(); } #endif /* Init empty TC timer */ set_empty_tc_timer(GET_TIMESTAMP(0)); /* enable ip forwarding on host */ /* Disable redirects globally */ #ifndef WIN32 net_os_set_global_ifoptions(); #endif /* Initialize parser */ olsr_init_parser(); /* Initialize route-exporter */ olsr_init_export_route(); /* Initialize message sequencnumber */ init_msg_seqno(); /* Initialize dynamic willingness calculation */ olsr_init_willingness(); /* *Set up willingness/APM */ if (olsr_cnf->willingness_auto) { if (apm_init() < 0) { OLSR_PRINTF(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT); olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT); olsr_cnf->willingness_auto = 0; olsr_cnf->willingness = WILL_DEFAULT; } else { olsr_cnf->willingness = olsr_calculate_willingness(); OLSR_PRINTF(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, olsr_cnf->will_int); } } /* Initialize net */ init_net(); /* Initializing networkinterfaces */ if (!olsr_init_interfacedb()) { if (olsr_cnf->allow_no_interfaces) { fprintf( stderr, "No interfaces detected! This might be intentional, but it also might mean that your configuration is fubar.\nI will continue after 5 seconds...\n"); olsr_startup_sleep(5); } else { fprintf(stderr, "No interfaces detected!\nBailing out!\n"); olsr_exit(__func__, EXIT_FAILURE); } } olsr_do_startup_sleep(); /* Print heartbeat to stdout */ #if !defined WINCE if (olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO)) { olsr_start_timer(STDOUT_PULSE_INT, 0, OLSR_TIMER_PERIODIC, &generate_stdout_pulse, NULL, 0); } #endif /* Initialize the IPC socket */ if (olsr_cnf->ipc_connections > 0) { ipc_init(); } /* Initialisation of different tables to be used. */ olsr_init_tables(); /* daemon mode */ #ifndef WIN32 if (olsr_cnf->debug_level == 0 && !olsr_cnf->no_fork) { printf("%s detaching from the current process...\n", olsrd_version); if (daemon(0, 0) < 0) { printf("daemon(3) failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } #endif /* * Create locking file for olsrd, will be cleared after olsrd exits */ for (i=5; i>=0; i--) { OLSR_PRINTF(3, "Trying to get olsrd lock...\n"); if (olsr_create_lock_file(i > 0) == 0) { /* lock sucessfully created */ break; } sleep (1); } /* Load plugins */ olsr_load_plugins(); OLSR_PRINTF(1, "Main address: %s\n\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr)); #ifdef LINUX_NETLINK_ROUTING /* create policy routing priorities if necessary */ if (DEF_RT_NONE != olsr_cnf->rt_table_pri) { olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rt_table, olsr_cnf->rt_table_pri, NULL, true); } if (DEF_RT_NONE != olsr_cnf->rt_table_tunnel_pri) { olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rt_table_tunnel, olsr_cnf->rt_table_tunnel_pri, NULL, true); } if (DEF_RT_NONE != olsr_cnf->rt_table_default_pri) { olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rt_table_default, olsr_cnf->rt_table_default_pri, NULL, true); } /* OLSR sockets */ if (DEF_RT_NONE != olsr_cnf->rt_table_defaultolsr_pri) { for (ifn = ifnet; ifn; ifn = ifn->int_next) { olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rt_table_default, olsr_cnf->rt_table_defaultolsr_pri, ifn->int_name, true); } } /* trigger gateway selection */ if (olsr_cnf->smart_gw_active) { olsr_trigger_inetgw_startup(); } /* trigger niit static route setup */ if (olsr_cnf->use_niit) { olsr_setup_niit_routes(); } /* create lo:olsr interface */ if (olsr_cnf->use_src_ip_routes) { olsr_os_localhost_if(&olsr_cnf->main_addr, true); } #endif /* Start syslog entry */ olsr_syslog(OLSR_LOG_INFO, "%s successfully started", olsrd_version); /* *signal-handlers */ /* ctrl-C and friends */ #ifdef WIN32 #ifndef WINCE SetConsoleCtrlHandler(SignalHandler, true); #endif #else signal(SIGHUP, olsr_reconfigure); signal(SIGINT, olsr_shutdown); signal(SIGQUIT, olsr_shutdown); signal(SIGILL, olsr_shutdown); signal(SIGABRT, olsr_shutdown); // signal(SIGSEGV, olsr_shutdown); signal(SIGTERM, olsr_shutdown); signal(SIGPIPE, SIG_IGN); // Ignoring SIGUSR1 and SIGUSR1 by default to be able to use them in plugins signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); #endif link_changes = false; /* Starting scheduler */ olsr_scheduler(); /* Like we're ever going to reach this ;-) */ return 1; } /* main */
static struct zroute *zparse_route(unsigned char *opt) { struct zroute *r; int c; size_t size; uint16_t length; unsigned char *pnt; memcpy(&length, opt, sizeof length); length = ntohs (length); r = olsr_malloc(sizeof *r, "QUAGGA: New zebra route"); pnt = (zebra.version ? &opt[6] : &opt[3]); r->type = *pnt++; r->flags = *pnt++; r->message = *pnt++; r->prefixlen = *pnt++; size = (r->prefixlen + 7) / 8; memset(&r->prefix, 0, sizeof r->prefix); if (olsr_cnf->ip_version == AF_INET) memcpy(&r->prefix.v4.s_addr, pnt, size); else memcpy(r->prefix.v6.s6_addr, pnt, size); pnt += size; switch (zebra.version) { case 0: case 1: if (r->message & ZAPI_MESSAGE_NEXTHOP) { r->nexthop_num = *pnt++; r->nexthop = olsr_malloc((sizeof *r->nexthop) * r->nexthop_num, "QUAGGA: New zebra route nexthop"); for (c = 0; c < r->nexthop_num; c++) { if (olsr_cnf->ip_version == AF_INET) { memcpy(&r->nexthop[c].v4.s_addr, pnt, sizeof r->nexthop[c].v4.s_addr); pnt += sizeof r->nexthop[c].v4.s_addr; } else { memcpy(r->nexthop[c].v6.s6_addr, pnt, sizeof r->nexthop[c].v6.s6_addr); pnt += sizeof r->nexthop[c].v6.s6_addr; } } } if (r->message & ZAPI_MESSAGE_IFINDEX) { r->ifindex_num = *pnt++; r->ifindex = olsr_malloc(sizeof(uint32_t) * r->ifindex_num, "QUAGGA: New zebra route ifindex"); for (c = 0; c < r->ifindex_num; c++) { memcpy(&r->ifindex[c], pnt, sizeof r->ifindex[c]); r->ifindex[c] = ntohl (r->ifindex[c]); pnt += sizeof r->ifindex[c]; } } break; default: OLSR_PRINTF(1, "(QUAGGA) Unsupported zebra packet version!\n"); break; } if (r->message & ZAPI_MESSAGE_DISTANCE) { r->distance = *pnt++; } // Quagga v0.98.6 BUG workaround: metric is always sent by zebra // even without ZAPI_MESSAGE_METRIC message. // if (r.message & ZAPI_MESSAGE_METRIC) { memcpy(&r->metric, pnt, sizeof r->metric); r->metric = ntohl(r->metric); pnt += sizeof r->metric; // } if (pnt - opt != length) { olsr_exit("(QUAGGA) Length does not match!", EXIT_FAILURE); } return r; }