int olsr_db_rt_report_so(char** str_out) { int report_str_len = 70; olsr_db_rt_t* current_entry = rt_set; char* output; char entry_str[report_str_len + 1]; output = malloc(sizeof(char) * report_str_len * (HASH_COUNT(rt_set)) + 1); if(output == NULL) { return false; } struct timeval curr_time; gettimeofday(&curr_time, NULL); // initialize first byte to \0 to mark output as empty *output = '\0'; while(current_entry != NULL) { snprintf(entry_str, report_str_len + 1, MAC "\t" MAC "\t" MAC "\t%i\t%5.2f\n", EXPLODE_ARRAY6(current_entry->dest_addr), EXPLODE_ARRAY6(current_entry->next_hop), EXPLODE_ARRAY6(current_entry->precursor_addr), current_entry->hop_count, current_entry->link_quality); strcat(output, entry_str); current_entry = current_entry->hh.next; } *str_out = output; return true; }
/** Handle trace packets * * Prints the content of a trace request packet and sends the same packet with * an appended trace reply extension back if no trace reply is yet present. * If there is a trace request and a trace reply extension, both are printed but * no packet is send. * The whole trace mechanism is basically a ping/pong with additional tracing. * * @param *msg dessert_msg_t frame received * @param len length of the buffer pointed to from dessert_msg_t * @param *proc local processing buffer passed along the callback pipeline - may be NULL * @param *meshif interface received packet on - may be NULL * @param id unique internal frame id of the packet * * @retval DESSERT_MSG_DROP if this host is the destination of the trace request * @retval DESSERT_MSG_KEEP if this host is not the destination of the trace request */ dessert_cb_result dessert_mesh_trace(dessert_msg_t* msg, uint32_t len, dessert_msg_proc_t* proc, dessert_meshif_t* meshif, dessert_frameid_t id) { struct ether_header* l25h = dessert_msg_getl25ether(msg); if(l25h && proc->lflags & DESSERT_RX_FLAG_L25_DST) { char buf[1024]; memset(buf, 0x0, sizeof(buf)); dessert_ext_t* request_ext; if(dessert_msg_getext(msg, &request_ext, DESSERT_EXT_TRACE_REQ, 0)) { dessert_msg_trace_dump(msg, DESSERT_EXT_TRACE_REQ, buf, sizeof(buf)); dessert_debug("trace request from " MAC "\n%s", EXPLODE_ARRAY6(l25h->ether_shost), buf); if(_dessert_callbacks_cli != NULL) { cli_print(_dessert_callbacks_cli, "\ntrace request from " MAC "\n%s", EXPLODE_ARRAY6(l25h->ether_shost), buf); } uint8_t temp[ETHER_ADDR_LEN]; memcpy(temp, l25h->ether_shost, ETHER_ADDR_LEN); memcpy(l25h->ether_shost, l25h->ether_dhost, ETHER_ADDR_LEN); memcpy(l25h->ether_dhost, temp, ETHER_ADDR_LEN); int len = dessert_ext_getdatalen(request_ext) == DESSERT_MSG_TRACE_IFACE ? DESSERT_MSG_TRACE_IFACE : DESSERT_MSG_TRACE_HOST; dessert_msg_trace_initiate(msg, DESSERT_EXT_TRACE_RPL, len); dessert_meshsend(msg, NULL); return DESSERT_MSG_DROP; } dessert_ext_t* reply_ext; if(dessert_msg_getext(msg, &reply_ext, DESSERT_EXT_TRACE_RPL, 0)) { dessert_msg_trace_dump(msg, DESSERT_EXT_TRACE_RPL, buf, sizeof(buf)); dessert_debug("trace reply from " MAC "\n%s", EXPLODE_ARRAY6(l25h->ether_shost), buf); if(_dessert_callbacks_cli != NULL) { cli_print(_dessert_callbacks_cli, "\ntrace reply from " MAC "\n%s", EXPLODE_ARRAY6(l25h->ether_shost), buf); } return DESSERT_MSG_DROP; } } return DESSERT_MSG_KEEP; }
dessert_cb_result_t lsr_forward_unicast(dessert_msg_t* msg, uint32_t len, dessert_msg_proc_t *proc, dessert_meshif_t *iface, dessert_frameid_t id) { //don't forward if we are the destination if(proc->lflags.l25_dst) { return DESSERT_MSG_KEEP; } //don't forward if we are not the intended intermediate hop if(!proc->lflags.l2_dst) { return DESSERT_MSG_KEEP; } struct ether_header* l25h = dessert_msg_getl25ether(msg); dessert_meshif_t *out_iface; mac_addr next_hop; dessert_result_t result = lsr_db_get_next_hop(l25h->ether_dhost, &next_hop, &out_iface); if(result == DESSERT_OK) { memcpy(msg->l2h.ether_dhost, next_hop, ETH_ALEN); lsr_send(msg, out_iface); } else { dessert_debug("no route to dest " MAC, EXPLODE_ARRAY6(l25h->ether_dhost)); } return DESSERT_MSG_DROP; }
/** Handle ping packets * * @param *msg dessert_msg_t frame received * @param len length of the buffer pointed to from dessert_msg_t * @param *proc local processing buffer passed along the callback pipeline - may be NULL * @param *meshif interface received packet on - may be NULL * @param id unique internal frame id of the packet * * @retval DESSERT_MSG_DROP if the ping is destined to this host * @retval DESSERT_MSG_KEEP if some other host is the destination */ dessert_cb_result dessert_mesh_ping(dessert_msg_t* msg, uint32_t len, dessert_msg_proc_t* proc, dessert_meshif_t* meshif, dessert_frameid_t id) { dessert_ext_t* ext; struct ether_header* l25h; u_char temp[ETHER_ADDR_LEN]; l25h = dessert_msg_getl25ether(msg); if(l25h && proc->lflags & DESSERT_RX_FLAG_L25_DST && dessert_msg_getext(msg, &ext, DESSERT_EXT_PING, 0)) { dessert_debug("got ping packet from " MAC " - sending pong", EXPLODE_ARRAY6(l25h->ether_shost)); memcpy(temp, l25h->ether_shost, ETHER_ADDR_LEN); memcpy(l25h->ether_shost, l25h->ether_dhost, ETHER_ADDR_LEN); memcpy(l25h->ether_dhost, temp, ETHER_ADDR_LEN); ext->type = DESSERT_EXT_PONG; memcpy(ext->data, "pong", 5); dessert_meshsend(msg, NULL); return DESSERT_MSG_DROP; } return DESSERT_MSG_KEEP; }
dessert_cb_result_t lsr_sys2mesh(dessert_msg_t *msg, uint32_t len, dessert_msg_proc_t *proc, dessert_sysif_t *sysif, dessert_frameid_t id) { struct ether_header* l25h = dessert_msg_getl25ether(msg); msg->ttl = LSR_TTL_MAX; if(proc->lflags.l25_multicast) { msg->u16 = htons(lsr_db_broadcast_get_seq_nr()); memcpy(msg->l2h.ether_dhost, ether_broadcast, ETH_ALEN); dessert_result_t result = lsr_send_randomized(msg); if(result != DESSERT_OK) { dessert_crit("error while trying to send multicast"); } } else { msg->u16 = htons(lsr_db_unicast_get_seq_nr()); dessert_meshif_t *out_iface; mac_addr next_hop; dessert_result_t result = lsr_db_get_next_hop(l25h->ether_dhost, &next_hop, &out_iface); if(result == DESSERT_OK) { memcpy(msg->l2h.ether_dhost, next_hop, ETH_ALEN); dessert_result_t result = lsr_send(msg, out_iface); if(result != DESSERT_OK) { dessert_crit("error while trying to send unicast"); } } else { dessert_info("no route to dest " MAC, EXPLODE_ARRAY6(l25h->ether_dhost)); } } return DESSERT_MSG_DROP; }
/** Send a ping packet * * @param cli the handle of the cli structure. This must be passed to all cli functions, including cli_print(). * @param command the entire command which was entered. This is after command expansion. * @param argv the list of arguments entered * @param argc the number of arguments entered * * @retval CLI_OK if ping sent * @retval CLI_ERROR on error */ int dessert_cli_cmd_ping(struct cli_def* cli, char* command, char* argv[], int argc) { u_char ether_trace[ETHER_ADDR_LEN]; dessert_msg_t* msg; dessert_ext_t* ext; struct ether_header* l25h; if(argc < 1 || argc > 2 || sscanf(argv[0], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", ðer_trace[0], ðer_trace[1], ðer_trace[2], ðer_trace[3], ðer_trace[4], ðer_trace[5]) != 6 ) { cli_print(cli, "usage %s [mac-address in xx:xx:xx:xx:xx:xx notation] ([text])\n", command); return CLI_ERROR; } cli_print(cli, "sending ping packet to " MAC "...\n", EXPLODE_ARRAY6(ether_trace)); dessert_info("sending ping packet to " MAC, EXPLODE_ARRAY6(ether_trace)); dessert_msg_new(&msg); dessert_msg_addext(msg, &ext, DESSERT_EXT_ETH, ETHER_HDR_LEN); l25h = (struct ether_header*) ext->data; memcpy(l25h->ether_shost, dessert_l25_defsrc, ETHER_ADDR_LEN); memcpy(l25h->ether_dhost, ether_trace, ETHER_ADDR_LEN); l25h->ether_type = htons(0x0000); if(argc == 2) { int len = strlen(argv[1]); len = len > DESSERT_MAXEXTDATALEN ? DESSERT_MAXEXTDATALEN : len; dessert_msg_addext(msg, &ext, DESSERT_EXT_PING, len); memcpy(ext->data, argv[1], len); } else { dessert_msg_addext(msg, &ext, DESSERT_EXT_PING, 5); memcpy(ext->data, "ping", 5); } dessert_meshsend(msg, NULL); dessert_msg_destroy(msg); _dessert_callbacks_cli = cli; return CLI_OK; }
int olsr_db_ns_report(char** str_out) { int report_ns_str_len = 98; olsr_db_ns_tuple_t* current_entry = neighbor_set; char* output; char entry_str[report_ns_str_len + 1]; output = malloc(sizeof(char) * report_ns_str_len * (4 + HASH_COUNT(current_entry)) + 1); if(output == NULL) { return false; } // initialize first byte to \0 to mark output as empty *output = '\0'; strcat(output, "+-------------------+-------+--------------+-------------+----------------------------+---------+\n"); strcat(output, "| neighbor address | MPR | MPR selector | willingness | best link | quality |\n"); strcat(output, "+-------------------+-------+--------------+-------------+----------------------------+---------+\n"); while(current_entry != NULL) { if(current_entry->best_link.local_iface == NULL) { snprintf(entry_str, report_ns_str_len + 1, "| " MAC " | %5s | %12s | %11i | NULL | - |\n", EXPLODE_ARRAY6(current_entry->neighbor_main_addr), (current_entry->mpr == true) ? "true" : "false", (current_entry->mpr_selector == true) ? "true" : "false", current_entry->willingness); } else { snprintf(entry_str, report_ns_str_len + 1, "| " MAC " | %5s | %12s | %11i | (%7s)" MAC " | %7i |\n", EXPLODE_ARRAY6(current_entry->neighbor_main_addr), (current_entry->mpr == true) ? "true" : "false", (current_entry->mpr_selector == true) ? "true" : "false", current_entry->willingness, current_entry->best_link.local_iface->if_name, EXPLODE_ARRAY6(current_entry->best_link.neighbor_iface_addr), current_entry->best_link.quality); } strcat(output, entry_str); current_entry = current_entry->hh.next; } strcat(output, "+-------------------+-------+--------------+-------------+----------------------------+---------+\n"); *str_out = output; return true; }
/** Handle pong packets * * @param *msg dessert_msg_t frame received * @param len length of the buffer pointed to from dessert_msg_t * @param *proc local processing buffer passed along the callback pipeline - may be NULL * @param *meshif interface received packet on - may be NULL * @param id unique internal frame id of the packet * * @retval DESSERT_MSG_DROP if the pong is destined to this host * @retval DESSERT_MSG_KEEP if some other host is the destination */ dessert_cb_result dessert_mesh_pong(dessert_msg_t* msg, uint32_t len, dessert_msg_proc_t* proc, dessert_meshif_t* meshif, dessert_frameid_t id) { dessert_ext_t* ext; struct ether_header* l25h; u_char temp[ETHER_ADDR_LEN]; l25h = dessert_msg_getl25ether(msg); if(l25h && proc->lflags & DESSERT_RX_FLAG_L25_DST && dessert_msg_getext(msg, &ext, DESSERT_EXT_PONG, 0)) { dessert_debug("got pong packet from " MAC, EXPLODE_ARRAY6(l25h->ether_shost)); if(_dessert_callbacks_cli != NULL) cli_print(_dessert_callbacks_cli, "\ngot pong packet from " MAC, EXPLODE_ARRAY6(l25h->ether_shost)); return DESSERT_MSG_DROP; } return DESSERT_MSG_KEEP; }
int olsr_db_rt_report(char** str_out) { int report_str_len = 150; olsr_db_rt_t* current_entry = rt_set; char* output; char entry_str[report_str_len + 1]; output = malloc(sizeof(char) * report_str_len * (4 + HASH_COUNT(rt_set)) + 1); if(output == NULL) { return false; } struct timeval curr_time; gettimeofday(&curr_time, NULL); // initialize first byte to \0 to mark output as empty *output = '\0'; strcat(output, "+-------------------+-------------------+-------------------+-----------+--------------+\n"); if(rc_metric != RC_METRIC_ETX_ADD) { strcat(output, "| destination | next hop | precursor | hop count | link quality |\n"); } else { strcat(output, "| destination | next hop | precursor | hop count | ETX-sum |\n"); } strcat(output, "+-------------------+-------------------+-------------------+-----------+--------------+\n"); while(current_entry != NULL) { snprintf(entry_str, report_str_len + 1, "| " MAC " | " MAC " | "MAC" | %9i | %12.2f |\n", EXPLODE_ARRAY6(current_entry->dest_addr), EXPLODE_ARRAY6(current_entry->next_hop), EXPLODE_ARRAY6(current_entry->precursor_addr), current_entry->hop_count, current_entry->link_quality); strcat(output, entry_str); current_entry = current_entry->hh.next; } strcat(output, "+-------------------+-------------------+-------------------+-----------+--------------+\n"); *str_out = output; return true; }
void _rlfile_log(const uint8_t src_addr[ETH_ALEN], const uint8_t dest_addr[ETH_ALEN], const uint32_t seq_num, const uint8_t hop_count, const uint8_t in_iface[ETH_ALEN], const uint8_t out_iface[ETH_ALEN], const uint8_t next_hop_addr[ETH_ALEN]) { pthread_rwlock_wrlock(&rlflock); FILE* f = fopen(routing_log_file, "a+"); if(f == NULL) { dessert_debug("file = 0"); } if(out_iface == NULL) { fprintf(f, MAC "\t" MAC "\t%u\t%u\t" MAC "\t%s\t%s\n", EXPLODE_ARRAY6(src_addr), EXPLODE_ARRAY6(dest_addr), seq_num, hop_count, EXPLODE_ARRAY6(in_iface), "NULL", "NULL"); } else if(in_iface == NULL) { fprintf(f, MAC "\t" MAC "\t%u\t%u\t%s\t" MAC "\t" MAC "\n", EXPLODE_ARRAY6(src_addr), EXPLODE_ARRAY6(dest_addr), seq_num, hop_count, "NULL", EXPLODE_ARRAY6(out_iface), EXPLODE_ARRAY6(next_hop_addr)); } else { fprintf(f, MAC "\t" MAC "\t%u\t%u\t" MAC "\t" MAC "\t" MAC "\n", EXPLODE_ARRAY6(src_addr), EXPLODE_ARRAY6(dest_addr), seq_num, hop_count, EXPLODE_ARRAY6(in_iface), EXPLODE_ARRAY6(out_iface), EXPLODE_ARRAY6(next_hop_addr)); } fclose(f); pthread_rwlock_unlock(&rlflock); }
/** Trace route to destination * * Sends a packet with a trace request to a host. You will * asynchronously receive a reply if the destination is present in * in the network and no packet is lost. * * @param cli the handle of the cli structure. This must be passed to all cli functions, including cli_print(). * @param command the entire command which was entered. This is after command expansion. * @param argv the list of arguments entered * @param argc the number of arguments entered * * @retval CLI_OK if trace packet sent * @retval CLI_ERROR on error */ int dessert_cli_cmd_traceroute(struct cli_def* cli, char* command, char* argv[], int argc) { u_char ether_trace[ETHER_ADDR_LEN]; dessert_msg_t* msg; dessert_ext_t* ext; struct ether_header* l25h; if(argc < 1 || argc > 2 || sscanf(argv[0], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", ðer_trace[0], ðer_trace[1], ðer_trace[2], ðer_trace[3], ðer_trace[4], ðer_trace[5]) != 6 ) { cli_print(cli, "usage %s [mac-address in xx:xx:xx:xx:xx:xx notation] ([i])\n", command); return CLI_ERROR; } cli_print(cli, "sending trace packet to " MAC " ...\n", EXPLODE_ARRAY6(ether_trace)); dessert_info("sending trace packet to " MAC, EXPLODE_ARRAY6(ether_trace)); dessert_msg_new(&msg); dessert_msg_addext(msg, &ext, DESSERT_EXT_ETH, ETHER_HDR_LEN); l25h = (struct ether_header*) ext->data; memcpy(l25h->ether_shost, dessert_l25_defsrc, ETHER_ADDR_LEN); memcpy(l25h->ether_dhost, ether_trace, ETHER_ADDR_LEN); l25h->ether_type = htons(0x0000); if(argc == 2 && argv[1][0] == 'i') { dessert_msg_trace_initiate(msg, DESSERT_EXT_TRACE_REQ, DESSERT_MSG_TRACE_IFACE); } else { dessert_msg_trace_initiate(msg, DESSERT_EXT_TRACE_REQ, DESSERT_MSG_TRACE_HOST); } dessert_meshsend(msg, NULL); dessert_msg_destroy(msg); _dessert_callbacks_cli = cli; return CLI_OK; }
int olsr_db_ett_report(char** str_out) { int report_ett_str_len = 98; olsr_db_neighbors_ett_entry_t* current_entry = neighbor_set_ett; char* output; char entry_str[report_ett_str_len + 1]; output = malloc(sizeof(char) * report_ett_str_len * (4 + HASH_COUNT(current_entry)) + 1); if(output == NULL) { return false; } // initialize first byte to \0 to mark output as empty *output = '\0'; strcat(output, "+-------------------+----------------------+\n"); strcat(output, "| neighbor address | shortest time [usec] |\n"); strcat(output, "+-------------------+----------------------+\n"); uint32_t min_time; while(current_entry != NULL) { if((min_time = get_min_time_from_neighbor(current_entry->neighbor_main_addr)) != false) { snprintf(entry_str, report_ett_str_len + 1, "|" MAC "| %20i |\n", EXPLODE_ARRAY6(current_entry->neighbor_main_addr), min_time); } else { snprintf(entry_str, report_ett_str_len + 1, "|" MAC "| %20s |\n", EXPLODE_ARRAY6(current_entry->neighbor_main_addr), "none"); } strcat(output, entry_str); current_entry = current_entry->hh.next; } strcat(output, "+-------------------+----------------------+\n"); *str_out = output; return true; }
/** CLI command - show trapped packets * * Print the content of the packet trap. */ int cli_showpackettrap(struct cli_def* cli, char* command, char* argv[], int argc) { packettrap_t* tr = NULL; pthread_rwlock_rdlock(&traped_packets_lock); for(tr = traped_packets; tr != NULL; tr = (tr->hh).next) { trapped_packet_t* pkti = NULL; int i = 0; cli_print(cli, "\ndst=" MAC ":", EXPLODE_ARRAY6(tr->dst)); for(pkti = tr->pkgs; pkti->pkg != NULL; pkti++) { ara_proc_t* ap = ara_proc_get(pkti->proc); cli_print(cli, "\t#%04d seq=%06d trapcount=%03d", i++, ap->seq, ap->trapcount); } } pthread_rwlock_unlock(&traped_packets_lock); return CLI_OK; }
int olsr_db_ns_report_so(char** str_out) { int report_ns_str_len = 25; olsr_db_ns_tuple_t* current_entry = neighbor_set; char* output; char entry_str[report_ns_str_len + 1]; output = malloc(sizeof(char) * report_ns_str_len * (HASH_COUNT(current_entry)) + 1); if(output == NULL) { return false; } // initialize first byte to \0 to mark output as empty *output = '\0'; while(current_entry != NULL) { snprintf(entry_str, report_ns_str_len + 1, MAC "\t%i\n", EXPLODE_ARRAY6(current_entry->neighbor_main_addr), current_entry->best_link.quality); strcat(output, entry_str); current_entry = current_entry->hh.next; } *str_out = output; return true; }
/** trap an undeliverable packet (no next hop available) * * @arg dst destination with discovery waiting * @arg pkg packet to trap - pointer will simply be copied, so you MUST NOT free it * @returns count of packets now trapped for this dst, -1 if packet was discarded */ int trap_packet(ara_address_t dst, dessert_msg_t* pkg, size_t len, dessert_msg_proc_t* proc, dessert_frameid_t id) { ara_proc_t* ap = ara_proc_get(proc); packettrap_t* mytrap = NULL; trapped_packet_t* pkti = NULL; int i = 0; /* check if the packet has been trapped too often */ assert(proc != NULL); if(++(ap->trapcount) > ara_retry_max) { dessert_debug("discarding packet %d to " MAC " after %d times in trap", ap->seq, EXPLODE_ARRAY6(dst), ap->trapcount); return(-1); } else { dessert_debug("trapping packet %d to " MAC " for the %d. time", ap->seq, EXPLODE_ARRAY6(dst), ap->trapcount); } pthread_rwlock_wrlock(&traped_packets_lock); /* look up dst in hashtable - otherwise build list */ HASH_FIND(hh, traped_packets, dst, sizeof(dst), mytrap); /* no packets trapped yet - build trap... */ if(mytrap == NULL) { /* create the trap */ mytrap = malloc(sizeof(packettrap_t)); if(mytrap == NULL) { dessert_err("failed to allocate new hash table entry for packet trap"); goto trap_packet_out; } memcpy((mytrap->dst), dst, sizeof(ara_address_t)); mytrap->pkgs = malloc(ARA_TRAP_SLOTCHUNKSIZE * sizeof(trapped_packet_t)); if(mytrap->pkgs == NULL) { dessert_err("failed to allocate new hash table entry for packet trap"); free(mytrap); goto trap_packet_out; } mytrap->pkgs->pkg = NULL; mytrap->pkgs->len = 0; mytrap->pkgs->proc = NULL; mytrap->pkgs->id = 0; HASH_ADD_KEYPTR(hh, traped_packets, &(mytrap->dst), sizeof(dst), mytrap); } /* look for free slot */ i = 0; for(pkti = mytrap->pkgs; pkti->pkg != NULL; pkti++) { i++; } /* do we need to grow ? */ if(i % ARA_TRAP_SLOTCHUNKSIZE == ARA_TRAP_SLOTCHUNKSIZE - 1) { pkti = realloc(mytrap->pkgs, (i + ARA_TRAP_SLOTCHUNKSIZE + 1) * sizeof(trapped_packet_t)); if(pkti == NULL) { dessert_err("failed to modify hash table entry for packet trap"); goto trap_packet_out; } mytrap->pkgs = pkti; pkti += i; } /* copy/insert packet */ dessert_msg_clone(&(pkti->pkg), pkg, false); dessert_msg_proc_clone(&(pkti->proc), proc); pkti->len = len; pkti->id = id; /* fix list */ pkti++; i++; pkti->pkg = NULL; pkti->len = 0; pkti->proc = NULL; pkti->id = 0; /* done! */ trap_packet_out: pthread_rwlock_unlock(&traped_packets_lock); return(i); }
int batman_fwd2dest(dessert_msg_t* msg, size_t len, dessert_msg_proc_t* proc, const dessert_meshif_t* iface, dessert_frameid_t id) { struct ether_header* l25h = dessert_msg_getl25ether(msg); dessert_ext_t* rl_ext; uint32_t rl_seq_num = 0; uint8_t rl_hop_count = 0; if(dessert_msg_getext(msg, &rl_ext, RL_EXT_TYPE, 0) != 0) { struct rl_seq* rl_data = (struct rl_seq*) rl_ext->data; rl_seq_num = rl_data->seq_num; pthread_rwlock_wrlock(&rlseqlock); int pk = rl_check_seq(l25h->ether_shost, l25h->ether_dhost, rl_seq_num, time(0)); pthread_rwlock_unlock(&rlseqlock); if(pk == true) { // this packet was already processed if(be_verbose == true) { dessert_debug("DUP! from " MAC " to " MAC " hops %i", EXPLODE_ARRAY6(l25h->ether_shost), EXPLODE_ARRAY6(l25h->ether_dhost), rl_data->hop_count + 1); } return DESSERT_MSG_DROP; } pthread_rwlock_wrlock(&rlseqlock); rl_add_seq(l25h->ether_shost, l25h->ether_dhost, rl_seq_num, time(0)); pthread_rwlock_unlock(&rlseqlock); if(rl_data->hop_count != 255) { rl_hop_count = ++rl_data->hop_count; } } if(proc->lflags & DESSERT_RX_FLAG_L25_BROADCAST || proc->lflags & DESSERT_RX_FLAG_L25_MULTICAST) { // BROADCAST // re-send broadcast only if received form BEST NEXT HOP towards source // AND // over the local interface for this BEST NEXT HOP dessert_ext_t* brc_ext; dessert_msg_getext(msg, &brc_ext, BRC_STAMP_EXT_TYPE, 0); struct batman_msg_brc* data = (struct batman_msg_brc*) brc_ext->data; batman_db_wlock(); int result = batman_db_brct_addid(l25h->ether_shost, data->id); batman_db_unlock(); if(result == true) { dessert_meshsend_fast(msg, NULL); return DESSERT_MSG_KEEP; } else { return DESSERT_MSG_DROP; } } else if(((proc->lflags & DESSERT_RX_FLAG_L2_DST && !(proc->lflags & DESSERT_RX_FLAG_L2_OVERHEARD)) || proc->lflags & DESSERT_RX_FLAG_L2_BROADCAST) && !(proc->lflags & DESSERT_RX_FLAG_L25_DST)) { // NOT BROADCAST // route packets addressed direct to me(and for this interface), // or if next hop unknown(broadcast) // AND // not for me struct rl_seq* rl_data = (struct rl_seq*) rl_ext->data; uint8_t ether_best_next_hop[ETH_ALEN]; const dessert_meshif_t* output_iface; // find and set NEXT HOP and output interface for message towards destination batman_db_rlock(); int result = batman_db_rt_getroute_arl(l25h->ether_dhost, &output_iface, ether_best_next_hop, rl_data->precursor_if_list, &rl_data->prec_iface_count); batman_db_unlock(); if(result == true) { if(routing_log_file != NULL) { _rlfile_log(l25h->ether_shost, l25h->ether_dhost, rl_seq_num, rl_hop_count, iface->hwaddr, output_iface->hwaddr, ether_best_next_hop); } memcpy(msg->l2h.ether_dhost, ether_best_next_hop, ETH_ALEN); dessert_meshsend_fast(msg, output_iface); // HINT no lock need since no change in iftable after setup } // packet addressed not to me -> drop return DESSERT_MSG_DROP; } return DESSERT_MSG_KEEP; }
int batman_handle_ogm(dessert_msg_t* msg, size_t len, dessert_msg_proc_t* proc, const dessert_meshif_t* iface, dessert_frameid_t id) { dessert_ext_t* ogm_ext; if(dessert_msg_getext(msg, &ogm_ext, OGM_EXT_TYPE, 0) != 0) { struct batman_msg_ogm* ogm = (struct batman_msg_ogm*) ogm_ext->data; struct ether_header* l25h = dessert_msg_getl25ether(msg); if(be_verbose == true) { dessert_debug("--- OGM%u from " MAC , ogm->sequence_num, EXPLODE_ARRAY6(l25h->ether_shost)); } // if unidirectional flag is set -> // switch to directed flag and send this OGM back to originator if(ogm->flags & BATMAN_OGM_UFLAG) { ogm->flags = (ogm->flags & ~BATMAN_OGM_UFLAG) | BATMAN_OGM_DFLAG; memcpy(msg->l2h.ether_dhost, msg->l2h.ether_shost, ETH_ALEN); dessert_meshsend(msg, iface); // reset dhost to broadcast memset(msg->l2h.ether_dhost, 255, ETH_ALEN); // and set next hop towards source memcpy(ogm->next_hop, iface->hwaddr, ETH_ALEN); ogm->flags = ogm->flags & ~BATMAN_OGM_DFLAG; } batman_db_wlock(); int bd = batman_db_nt_check2Dneigh(msg->l2h.ether_shost, iface); batman_db_unlock(); batman_db_wlock(); int last_seq_num_irt = batman_db_irt_getroutesn(l25h->ether_shost); // if reset flag is set -> delete old destination if(ogm->flags & BATMAN_OGM_RFLAG) { if(last_seq_num_irt >= 0 && (last_seq_num_irt - ogm->sequence_num >= OGM_RESET_COUNT)) { dessert_debug("--- " MAC " - was restarted", EXPLODE_ARRAY6(l25h->ether_shost)); batman_db_irt_deleteroute(l25h->ether_shost); batman_db_brt_deleteroute(l25h->ether_dhost); } } batman_db_unlock(); // search for rt entry addressed to me and capture if found dessert_ext_t* invrt_ext; int irt_ext_num = 0; while(dessert_msg_getext(msg, &invrt_ext, OGM_INVRT_EXT_TYPE, irt_ext_num++) > 0) { void* pointer = invrt_ext->data; int entry_count = (invrt_ext->len - DESSERT_EXTLEN) / sizeof(struct batman_ogm_invrt); while(entry_count-- > 0) { struct batman_ogm_invrt* invrt_data = pointer; pointer += sizeof(struct batman_ogm_invrt); if(memcmp(invrt_data->source_addr, dessert_l25_defsrc, ETH_ALEN) == 0) { const dessert_meshif_t* iflist = dessert_meshiflist_get(); const dessert_meshif_t* myiface = NULL; while(iflist != NULL) { if(iflist->if_index == invrt_data->output_iface_num) { myiface = iflist; break; } iflist = iflist->next; } if(myiface != NULL) { batman_db_wlock(); batman_db_rt_captureroute(l25h->ether_shost, myiface, invrt_data->next_hop); batman_db_unlock(); } } } } // capture all OGM not processed by me. // We assume that the OGM with known sequence number but // not containing my default address in precursor list were not processed. // Re-send OGMs only with newer seq_num to avoid routing loops if((_check_precursors(ogm) == false) && ( (hf_seq_comp_i_j(ogm->sequence_num, last_seq_num_irt) >= 0) || (last_seq_num_irt == -1))) { // also: don't process old OGM // add or change route to destination (l25h->ether_shost) batman_db_wlock(); time_t timestamp = time(0); batman_db_irt_addroute(l25h->ether_shost, ogm->output_iface_num, timestamp, ogm->next_hop, ogm->sequence_num); if(bd == true) batman_db_brt_addroute(l25h->ether_shost, iface, timestamp, msg->l2h.ether_shost, ogm->sequence_num); batman_db_unlock(); } if((hf_seq_comp_i_j(last_seq_num_irt, ogm->sequence_num) < 0) || (last_seq_num_irt == -1)) { if(be_verbose == true) { dessert_debug("--- OGM%u rebroadcast", ogm->sequence_num); } // if not processed -> add myself to precursors and send out _add_myself_to_precursors(ogm); dessert_meshsend_fast_randomized(msg); } return DESSERT_MSG_DROP; } else { return DESSERT_MSG_KEEP; } }
dessert_cb_result olsr_fwd2dest(dessert_msg_t* msg, size_t len, dessert_msg_proc_t* proc, dessert_meshif_t* iface, dessert_frameid_t id) { struct ether_header* l25h = dessert_msg_getl25ether(msg); dessert_ext_t* rl_ext; uint32_t rl_seq_num = 0; uint8_t rl_hop_count = 0; if(dessert_msg_getext(msg, &rl_ext, RL_EXT_TYPE, 0) != 0) { struct rl_seq* rl_data = (struct rl_seq*) rl_ext->data; rl_seq_num = rl_data->seq_num; pthread_rwlock_wrlock(&rlseqlock); uint8_t pk = rl_check_seq(l25h->ether_shost, l25h->ether_dhost, rl_seq_num); pthread_rwlock_unlock(&rlseqlock); if(pk == true) { // this packet was already processed dessert_debug("DUP! from L25 src=" MAC " to dst=" MAC ", hops=%i", EXPLODE_ARRAY6(l25h->ether_shost), EXPLODE_ARRAY6(l25h->ether_dhost), rl_data->hop_count + 1); return DESSERT_MSG_DROP; } pthread_rwlock_wrlock(&rlseqlock); rl_add_seq(l25h->ether_shost, l25h->ether_dhost, rl_seq_num); pthread_rwlock_unlock(&rlseqlock); if(rl_data->hop_count != 255) { rl_hop_count = ++rl_data->hop_count; } } if(proc->lflags & DESSERT_RX_FLAG_L25_BROADCAST || proc->lflags & DESSERT_RX_FLAG_L25_MULTICAST) { // BROADCAST dessert_ext_t* ext; if(dessert_msg_getext(msg, &ext, BROADCAST_ID_EXT_TYPE, 0) != 0) { uint8_t prev_hop_main_addr[ETH_ALEN]; struct olsr_msg_brc* brc_data = (struct olsr_msg_brc*) ext->data; struct timeval curr_time, hold_time, purge_time; gettimeofday(&curr_time, NULL); hold_time.tv_sec = BRCLOG_HOLD_TIME; hold_time.tv_usec = 0; hf_add_tv(&curr_time, &hold_time, &purge_time); olsr_db_wlock(); uint8_t result = olsr_db_brct_addid(l25h->ether_shost, brc_data->id, &purge_time); if(result == true) { result = olsr_db_ls_getmainaddr(iface, msg->l2h.ether_shost, prev_hop_main_addr); } else { olsr_db_unlock(); dessert_debug("drop broadcast %i duplicate", brc_data->id); return DESSERT_MSG_DROP; } if(result == true) { result = olsr_db_ns_ismprselector(prev_hop_main_addr); } olsr_db_unlock(); if(result == true) { // resend only if combination of source address and broadcast id is new // AND // previous host has selected me as MPR dessert_meshsend_fast_randomized(msg); } } return DESSERT_MSG_KEEP; } else if(((proc->lflags & DESSERT_RX_FLAG_L2_DST && !(proc->lflags & DESSERT_RX_FLAG_L2_OVERHEARD)) || proc->lflags & DESSERT_RX_FLAG_L2_BROADCAST) && !(proc->lflags & DESSERT_RX_FLAG_L25_DST)) { // Directed message uint8_t next_hop[ETH_ALEN]; uint8_t next_hop_iface[ETH_ALEN]; dessert_meshif_t* output_iface; // find and set (if found) NEXT HOP towards destination olsr_db_rlock(); uint8_t result = olsr_db_rt_getnexthop(l25h->ether_dhost, next_hop); if(result == true) { result = olsr_db_ns_getbestlink(next_hop, &output_iface, next_hop_iface); } olsr_db_unlock(); if(result == true) { memcpy(msg->l2h.ether_dhost, next_hop_iface, ETH_ALEN); dessert_meshsend_fast(msg, output_iface); } return DESSERT_MSG_DROP; } return DESSERT_MSG_KEEP; }
int aodv_metric_do(metric_t* metric, uint8_t last_hop[ETH_ALEN], dessert_meshif_t* iface) { switch(metric_type) { case AODV_METRIC_HOP_COUNT: { (*metric)++; break; } case AODV_METRIC_RSSI: { struct avg_node_result sample = dessert_rssi_avg(last_hop, iface); uint8_t interval = hf_rssi2interval(sample.avg_rssi); dessert_trace("incomming rssi_metric=%" AODV_PRI_METRIC ", add %" PRIu8 " (rssi=%" PRId8 ") for the last hop " MAC, (*metric), interval, sample.avg_rssi, EXPLODE_ARRAY6(last_hop)); (*metric) += interval; break; } case AODV_METRIC_ETX: { dessert_crit("AODV_METRIC_ETX -> not implemented! -> using AODV_METRIC_HOP_COUNT as fallback"); (*metric)++; /* HOP_COUNT */ break; } case AODV_METRIC_ETT: { dessert_crit("AODV_METRIC_ETT -> not implemented! -> using AODV_METRIC_HOP_COUNT as fallback"); (*metric)++; /* HOP_COUNT */ break; } default: { dessert_crit("unknown metric=%" PRIu8 " -> using HOP_COUNT as fallback", metric_type); (*metric)++; /* HOP_COUNT */ return false; } } return true; }
int aodv_metric_do(metric_t* metric, mac_addr last_hop, dessert_meshif_t* iface, struct timeval* timestamp) { switch(metric_type) { case AODV_METRIC_HOP_COUNT: { (*metric)++; break; } #ifndef ANDROID case AODV_METRIC_RSSI: { struct avg_node_result sample = dessert_rssi_avg(last_hop, iface); metric_t interval = hf_rssi2interval(sample.avg_rssi); dessert_trace("incoming rssi_metric=%" AODV_PRI_METRIC ", add %" PRIu8 " (rssi=%" PRId8 ") for the last hop " MAC, (*metric), interval, sample.avg_rssi, EXPLODE_ARRAY6(last_hop)); *metric += interval; break; } #endif case AODV_METRIC_ETX_ADD: { metric_t link_etx_add = AODV_MAX_METRIC; if(aodv_db_pdr_get_etx_add(last_hop, &link_etx_add, timestamp)) { dessert_debug("Old metricval %" AODV_PRI_METRIC " ETX_ADD rcvd =%" PRIu16 " for this hop " MAC, (*metric), link_etx_add, EXPLODE_ARRAY6(last_hop)); } else { dessert_debug("Old metricval %" AODV_PRI_METRIC " ETX_ADD for hop " MAC " failed", *metric, EXPLODE_ARRAY6(last_hop)); } /**prevent overflow*/ if(AODV_MAX_METRIC - link_etx_add > *metric) { *metric += link_etx_add; } else { *metric = AODV_MAX_METRIC; } dessert_debug("New metric value =%" AODV_PRI_METRIC " for hop " MAC, *metric, EXPLODE_ARRAY6(last_hop)); break; } case AODV_METRIC_ETX_MUL: { metric_t link_etx_mul = 0; if(aodv_db_pdr_get_etx_mul(last_hop, &link_etx_mul, timestamp) == true) { dessert_debug("Old metricval %" AODV_PRI_METRIC " ETX_MUL rcvd =%" PRIu16 " for this hop " MAC, (*metric), link_etx_mul, EXPLODE_ARRAY6(last_hop)); uintmax_t result = (*metric) * (uintmax_t)link_etx_mul; result /= (AODV_MAX_METRIC/32); (*metric) = (metric_t) result; } else { dessert_debug("Old metricval %" AODV_PRI_METRIC " ETX_MUL for hop " MAC " failed", (*metric), EXPLODE_ARRAY6(last_hop)); (*metric) = 0; } dessert_debug("New metric value =%" AODV_PRI_METRIC " for hop " MAC, (*metric), EXPLODE_ARRAY6(last_hop)); break; } case AODV_METRIC_PDR: { uint16_t link_pdr = 0; if(aodv_db_pdr_get_pdr(last_hop, &link_pdr, timestamp) == true){ dessert_debug("Old metricval %" AODV_PRI_METRIC " PDR rcvd =%" PRIu16 " for this hop " MAC, (*metric), link_pdr, EXPLODE_ARRAY6(last_hop)); uint32_t result = (*metric) * (uint32_t)link_pdr; result = result / AODV_MAX_METRIC; (*metric) = (metric_t) result; } else { dessert_debug("Old metricval %" AODV_PRI_METRIC " PDR for hop " MAC " failed", (*metric), EXPLODE_ARRAY6(last_hop)); (*metric) = 0; } dessert_debug("New metric value =%" AODV_PRI_METRIC " for hop " MAC, (*metric), EXPLODE_ARRAY6(last_hop)); break; } case AODV_METRIC_RFC: { break; } default: { dessert_crit("unknown metric set -> using AODV_METRIC_RFC as fallback"); return false; } } return true; }
/** Handles a trapped packet after timeout * */ dessert_per_result_t handleTrappedPacket(void *data, struct timeval *scheduled, struct timeval *interval) { trappedpacket_t* t = (trappedpacket_t*) data; uint8_t forwarded = 0; switch(gossip) { // forward if less than m duplicates received case gossip_14: case gossip_3: if((t->counter)-1 < m) { dessert_debug("forwarding msg: src=" MAC ", seq=%d, received %d<%d duplicates", EXPLODE_ARRAY6(t->key.addr), t->msg->u16, t->counter-1, m); t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } break; // send if not all neighbors sent a copy case gossip_5: if((t->counter) < numNeighbors()) { dessert_debug("forwarding msg: src=" MAC ", seq=%d, received %d<%d (=neighbors) duplicates", EXPLODE_ARRAY6(t->key.addr), t->msg->u16, t->counter, numNeighbors()); t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } break; // forward if less than m duplicates received with adapted probability case gossip_6: if((t->counter)-1 < m) { float new_p = (p/(m + 1)); if(random() < (((long double) new_p)*((long double) RAND_MAX))) { dessert_debug("forwarding msg: src=" MAC ", seq=%d, received %d<%d duplicates and send with probability %f", EXPLODE_ARRAY6(t->key.addr), t->msg->u16, t->counter-1, m, new_p); t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } } break; // forward if less than m-1 duplicates received case gossip_7: if((t->counter-1) <= m) { if(random() < (((long double) p)*((long double) RAND_MAX))) { dessert_debug("forwarding msg: src=" MAC ", seq=%d, received %d<=%d duplicates", EXPLODE_ARRAY6(t->key.addr), t->msg->u16, t->counter-1, m); t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } } break; case gossip_10: if(t->forwarded) { if((max(0, t->counter) + t->counter2) < m) { t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } // always drop packet after 2nd forwarding chance } else { // like gossip_3 if(max(0, t->counter - 1) < m) { t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); t->forwarded = 1; uint32_t sec = timeout.tv_sec; uint32_t usec = timeout.tv_usec; struct timeval handle_interval; gettimeofday(&handle_interval, NULL); TIMEVAL_ADD(&handle_interval, sec, usec); dessert_periodic_add((dessert_periodiccallback_t *) handleTrappedPacket, t, &handle_interval, NULL); dessert_debug("keeping packet to monitor forwarding of neighbors: src=" MAC ", seq=%d", EXPLODE_ARRAY6(t->key.addr), t->key.seq); return 0; // do not delete msg and give it a second chance } } break; case gossip_11: // TODO: remove/replace if((t->counter)-1 < m) { float new_p = (p+(((1-p)*p)/(m + 1))); if(random() < (((long double) new_p)*((long double) RAND_MAX))) { dessert_debug("forwarding msg: src=" MAC ", seq=%d, received %d<%d duplicates, p_new=%f", EXPLODE_ARRAY6(t->key.addr), t->msg->u16, t->counter-1, m, new_p); t->msg->u8 |= DELAYED; dessert_meshif_t* iface = NULL; logForwarded(t->msg, 0, NULL, iface); dessert_meshsend(t->msg, iface); forwarded = 1; } } break; default: dessert_warn("unsupported gossip variant"); } if(!forwarded) { dessert_debug("packet not forwarded, dropping it now: src=" MAC ", seq=%d", EXPLODE_ARRAY6(t->key.addr), t->key.seq); } /*###*/ pthread_rwlock_wrlock(&packettrap_lock); HASH_DEL(trappedpackets, t); pthread_rwlock_unlock(&packettrap_lock); /*###*/ destroyTrappedPacket(t); return 0; }
/** Check if this packet is a duplicate * * Registers the sequence number as received if it is the first copy of the packet. * All subsequent received copies (duplicates) are dropped and the packet count is * increased, if the first copy is still in the packet trap. * * Looping packets sent by this host are also dropped. * The hop count value in the corresponding extension is incremented. */ int checkSeq(dessert_msg_t* msg, size_t len, dessert_msg_proc_t *proc, dessert_meshif_t *iface, dessert_frameid_t id) { if(/*proc->lflags & DESSERT_RX_FLAG_L2_SRC ||*/ proc->lflags & DESSERT_RX_FLAG_L25_SRC) { // TODO gossip_10 dessert_debug("dropped looping packet from myself"); return DESSERT_MSG_DROP; } seqlog_t* s = NULL; u_char* shost = dessert_msg_getl25ether(msg)->ether_shost; /*###*/ pthread_rwlock_rdlock(&seqlog_lock); HASH_FIND(hh, seqlog, shost, ETHER_ADDR_LEN, s); pthread_rwlock_unlock(&seqlog_lock); /*###*/ bool seq2_duplicate = false; if(s) { /*###*/ pthread_rwlock_wrlock(&seqlog_lock); uint8_t dup = isDuplicate(s, msg->u16); if(!dup) { insertSeq(s, msg->u16); #ifndef ANDROID seq2_duplicate = gossip13_rx_packet(s, msg, false); #endif pthread_rwlock_unlock(&seqlog_lock); /*###*/ } else { pthread_rwlock_unlock(&seqlog_lock); /*###*/ if(!(msg->u8 & HELLO)) { // HELLOs are never trapped trappedpacket_t* t; pkey_t lookup_key; memcpy(lookup_key.addr, shost, ETHER_ADDR_LEN); lookup_key.seq = msg->u16; /*###*/ pthread_rwlock_wrlock(&packettrap_lock); HASH_FIND(hh, trappedpackets, &lookup_key, sizeof(pkey_t), t); if(t) { // TODO gossip_10 t->counter++; } pthread_rwlock_unlock(&packettrap_lock); /*###*/ } return DESSERT_MSG_DROP; } } else { s = malloc(sizeof(seqlog_t)); if(!s) { dessert_crit("could not allocate memory"); return DESSERT_MSG_KEEP; } uint16_t i = 0; for(i=0; i<LOG_SIZE; i++) { s->seqs[i] = msg->u16; } s->next_seq = 1; #ifndef ANDROID // what the other node tells me gossip13_new_history(&(s->rx_history), false); // does not require observation initialization gossip13_new_history(&(s->tx_history), false); // does not require observation initialization gossip13_new_history(&(s->total_tx_history), false); // does not require observation initialization gossip13_new_history_mean(&(s->hops_history), false); // does not require observation initialization gossip13_new_history(&(s->nodes_history), false); // does not require observation initialization gossip13_new_history_mean(&(s->mean_dist_history), false); // does not require observation initialization gossip13_new_history_mean(&(s->eccentricity_history), false); // does not require observation initialization // what I know about the other node gossip13_new_history(&(s->observed_history), true); gossip13_new_observation(&(s->observed_history->observations)); gossip13_new_history_mean(&(s->my_hops_history), true); gossip13_new_observation_mean(&(s->my_hops_history->observations)); #endif s->tau = 0; memcpy(s->addr, shost, ETHER_ADDR_LEN); dessert_debug("registering seq=%d for src=" MAC " (previously unknown host)", msg->u16, EXPLODE_ARRAY6(shost)); #ifndef ANDROID seq2_duplicate = gossip13_rx_packet(s, msg, true); #endif /*###*/ pthread_rwlock_wrlock(&seqlog_lock); HASH_ADD(hh, seqlog, addr, ETHER_ADDR_LEN, s); pthread_rwlock_unlock(&seqlog_lock); /*###*/ } #ifndef ANDROID if(seq2_duplicate && gossip13_drop_seq2_duplicates && (proc->lflags & DESSERT_RX_FLAG_L25_DST || proc->lflags & DESSERT_RX_FLAG_L25_BROADCAST)) { return DESSERT_MSG_DROP; } #endif dessert_ext_t* ext = NULL; if(dessert_msg_getext(msg, &ext, EXT_HOPS, 0)) { gossip_ext_hops_t* h = (gossip_ext_hops_t*) ext->data; h->hops++; } return DESSERT_MSG_KEEP; }