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;
}
Esempio n. 2
0
/** 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;
}
Esempio n. 4
0
/** 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;
}
Esempio n. 6
0
/** 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",
              &ether_trace[0], &ether_trace[1], &ether_trace[2],
              &ether_trace[3], &ether_trace[4], &ether_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;
}
Esempio n. 8
0
/** 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);
}
Esempio n. 11
0
/** 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",
              &ether_trace[0], &ether_trace[1], &ether_trace[2],
              &ether_trace[3], &ether_trace[4], &ether_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;
}
Esempio n. 14
0
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;
    }
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
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;
}