void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header, void *tcp_socket) { uint8_t *p_ptr; ipv6_send_buf = get_rpl_send_ipv6_buf(); p_ptr = get_rpl_send_payload_buf(ipv6_ext_hdr_len); packet_length = 0; ipv6_send_buf->version_trafficclass = IPV6_VER; ipv6_send_buf->trafficclass_flowlabel = 0; ipv6_send_buf->flowlabel = 0; ipv6_send_buf->nextheader = next_header; ipv6_send_buf->hoplimit = MULTIHOP_HOPLIMIT; ipv6_send_buf->length = p_len; memcpy(&(ipv6_send_buf->destaddr), destination, 16); ipv6_get_saddr(&(ipv6_send_buf->srcaddr), &(ipv6_send_buf->destaddr)); /* Wenn das Paket in der rpl.c "zusammegebaut" wurde, wurde dafür ohnehin * der rpl_send_buf verwendet. In diesem Fall muss also keine memcopy * Aktion durchgeführt werden, da sich der payload bereits im richtigen * Speicherbereich befindet. */ if(p_ptr != payload) { memcpy(p_ptr, payload, p_len); } packet_length = IPV6_HDR_LEN + p_len; if(ipv6_prefix_mcast_match(&ipv6_send_buf->destaddr)) { lowpan_init((ieee_802154_long_t *)&(ipv6_send_buf->destaddr.uint16[4]), (uint8_t *)ipv6_send_buf); } else { /* find right next hop before sending */ ipv6_addr_t *next_hop = rpl_get_next_hop(&ipv6_send_buf->destaddr); if(next_hop == NULL) { if(i_am_root) { /* oops... ich bin root und weiß nicht wohin mit dem paketn */ printf("[Error] destination unknown\n"); return; } else { next_hop = rpl_get_my_preferred_parent(); if(next_hop == NULL) { /* kein preferred parent eingetragen */ puts("[Error] no preferred parent, dropping package"); return; } } } lowpan_init((ieee_802154_long_t *)&(next_hop->uint16[4]), (uint8_t *)ipv6_send_buf); } }
void border_send_ipv6_over_lowpan(struct ipv6_hdr_t *packet, uint8_t aro_flag, uint8_t sixco_flag) { uint16_t offset = IPV6_HDR_LEN+HTONS(packet->length); packet->flowlabel = HTONS(packet->flowlabel); packet->length = HTONS(packet->length); memset(buffer, 0, BUFFER_SIZE); memcpy(buffer+LL_HDR_LEN, packet, offset); lowpan_init((ieee_802154_long_t*)&(packet->destaddr.uint16[4]), (uint8_t*)packet); }
void recv_rtr_sol(void) { opt_hdr_len = RTR_SOL_LEN; ipv6_buf = get_ipv6_buf(); /* check if source option is set*/ if (opt_stllao_buf->type == OPT_SLLAO_TYPE) { opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, opt_hdr_len); llao = (uint8_t *)opt_stllao_buf; opt_hdr_len += (opt_stllao_buf->length) << 3; } if (llao != NULL) { nbr_entry = nbr_cache_search(&ipv6_buf->srcaddr); if (nbr_entry != NULL) { /* found neighbor in cache, update values and check long addr */ if (memcmp(&llao[2], &nbr_entry->laddr, 8) == 0) { nbr_entry->isrouter = 0; } else { /* new long addr found, update */ memcpy(&nbr_entry->laddr, &llao[2], 8); nbr_entry->state = NBR_STATUS_STALE; nbr_entry->isrouter = 0; } } else { /* nothing found, add neigbor into cache*/ nbr_cache_add(&ipv6_buf->srcaddr, (ieee_802154_long_t *)&llao[2], 0, NBR_STATUS_STALE, NBR_CACHE_TYPE_TEN, NBR_CACHE_LTIME_TEN, NULL); } } /* send solicited router advertisment */ if (abr_count > 0) { init_rtr_adv(&ipv6_buf->srcaddr, 0, 0, OPT_PI, OPT_6CO, OPT_ABRO); } else { init_rtr_adv(&ipv6_buf->srcaddr, 0, 0, OPT_PI, 0, 0); } #if ENABLE_DEBUG printf("INFO: send router advertisment to: "); ipv6_print_addr(&ipv6_buf->destaddr); #endif lowpan_init((ieee_802154_long_t *)&(ipv6_buf->destaddr.uint16[4]), (uint8_t *)ipv6_buf); }
/* send router solicitation message - RFC4861 section 4.1 */ void init_rtr_sol(uint8_t sllao) { ipv6_buf = get_ipv6_buf(); icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len); packet_length = 0; icmp_buf->type = ICMP_RTR_SOL; icmp_buf->code = 0; ipv6_buf->version_trafficclass = IPV6_VER; ipv6_buf->trafficclass_flowlabel = 0; ipv6_buf->flowlabel = 0; ipv6_buf->nextheader = PROTO_NUM_ICMPV6; ipv6_buf->hoplimit = ND_HOPLIMIT; ipv6_set_all_rtrs_mcast_addr(&ipv6_buf->destaddr); //iface_find_src_ipaddr(&ipv6_buf->srcaddr, ADDR_STATE_PREFERRED, /* ADDR_TYPE_MULTICAST); */ ipv6_get_saddr(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr)); opt_hdr_len = RTR_SOL_LEN; ipv6_buf->length = ICMPV6_HDR_LEN + RTR_SOL_LEN + OPT_STLLAO_MAX_LEN; if (sllao == OPT_SLLAO) { opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, opt_hdr_len); set_llao(opt_stllao_buf, OPT_SLLAO_TYPE, 2); packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len + RTR_SOL_LEN + OPT_STLLAO_MAX_LEN; } else { packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len + RTR_SOL_LEN; } icmp_buf->checksum = 0; icmp_buf->checksum = ~icmpv6_csum(PROTO_NUM_ICMPV6); #if ENABLE_DEBUG printf("INFO: send router solicitation to: "); ipv6_print_addr(&ipv6_buf->destaddr); #endif lowpan_init((ieee_802154_long_t *)&(ipv6_buf->destaddr.uint16[4]), (uint8_t *)ipv6_buf); }
void recv_nbr_sol(void) { ipv6_buf = get_ipv6_buf(); llao = NULL; opt_hdr_len = NBR_SOL_LEN; uint8_t send_na = 0; uint8_t sllao_set = 0; uint8_t aro_state = OPT_ARO_STATE_SUCCESS; /* check whick options are set, we need that because an aro * option condition is that a sllao option is set. thus that we don't * know which option comes first we need to this here */ while (packet_length > IPV6HDR_ICMPV6HDR_LEN + opt_hdr_len) { opt_buf = get_opt_buf(ipv6_ext_hdr_len, opt_hdr_len); if (opt_buf->type == OPT_SLLAO_TYPE) { sllao_set = 1; } opt_hdr_len += (opt_buf->length * 8); } opt_hdr_len = NBR_SOL_LEN; while (packet_length > IPV6HDR_ICMPV6HDR_LEN + opt_hdr_len) { opt_buf = get_opt_buf(ipv6_ext_hdr_len, opt_hdr_len); switch(opt_buf->type) { case (OPT_SLLAO_TYPE): { opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, opt_hdr_len); llao = (uint8_t *)opt_stllao_buf; if (llao != NULL && !(ipv6_addr_unspec_match(&ipv6_buf->srcaddr))) { nbr_entry = nbr_cache_search(&(ipv6_buf->srcaddr)); if (nbr_entry != NULL) { switch(opt_stllao_buf->length) { case (1): { if (memcmp(&llao[2], &(nbr_entry->saddr), 2) == 0) { nbr_entry->isrouter = 0; } else { memcpy(&nbr_entry->saddr, &llao[2], 2); nbr_entry->state = NBR_STATUS_STALE; nbr_entry->isrouter = 0; } break; } case (2): { if (memcmp(&llao[2], &(nbr_entry->laddr), 8) == 0) { nbr_entry->isrouter = 0; } else { memcpy(&nbr_entry->laddr, &llao[2], 8); nbr_entry->state = NBR_STATUS_STALE; nbr_entry->isrouter = 0; } break; } default: break; } } else { switch(opt_stllao_buf->length) { case (1): { nbr_cache_add(&ipv6_buf->srcaddr, NULL , 0, NBR_STATUS_STALE, NBR_CACHE_TYPE_TEN, NBR_CACHE_LTIME_TEN, (ieee_802154_short_t *)&llao[2]); break; } case (2): { nbr_cache_add(&ipv6_buf->srcaddr, (ieee_802154_long_t *)&llao[2], 0, NBR_STATUS_STALE, NBR_CACHE_TYPE_TEN, NBR_CACHE_LTIME_TEN, NULL); break; } default: break; } } } break; } case (OPT_ARO_TYPE): { /* check if sllao option is set, and if address src address * isn't unspecified - draft-ietf-6lowpan-nd-15#section-6.5 */ if (!(ipv6_addr_unspec_match(&ipv6_buf->srcaddr)) && sllao_set == 1) { opt_aro_buf = get_opt_aro_buf(ipv6_ext_hdr_len, opt_hdr_len); if ((opt_aro_buf->length == 2) && (opt_aro_buf->status == 0)) { /* check neighbor cache for duplicates */ nbr_entry = nbr_cache_search(&(ipv6_buf->srcaddr)); if (nbr_entry == NULL) { /* create neighbor cache */ aro_state = nbr_cache_add(&ipv6_buf->srcaddr, &(opt_aro_buf->eui64), 0, NBR_STATUS_STALE, NBR_CACHE_TYPE_TEN, opt_aro_buf->reg_ltime, NULL); } else { if (memcmp(&(nbr_entry->addr.uint16[4]), &(opt_aro_buf->eui64.uint16[0]), 8) == 0) { /* update neighbor cache entry */ if (opt_aro_buf->reg_ltime == 0) { /* delete neighbor cache entry */ nbr_cache_rem(&nbr_entry->addr); } else { set_remaining_time(&(nbr_entry->ltime), (uint32_t)opt_aro_buf->reg_ltime); nbr_entry->state = NBR_STATUS_STALE; nbr_entry->isrouter = 0; memcpy(&(nbr_entry->addr.uint8[0]), &(ipv6_buf->srcaddr.uint8[0]), 16); } aro_state = OPT_ARO_STATE_SUCCESS; } else { /* duplicate found */ aro_state = OPT_ARO_STATE_DUP_ADDR; } } } } break; } default: break; } opt_hdr_len += (opt_buf->length * 8); } addr_list_t *alist_targ, *alist_dest; nbr_sol_buf = get_nbr_sol_buf(ipv6_ext_hdr_len); alist_targ = ipv6_iface_addr_match(&(nbr_sol_buf->tgtaddr)); if (alist_targ != NULL) { alist_dest = ipv6_iface_addr_match(&(ipv6_buf->destaddr)); if ((memcmp(&(alist_targ->addr), &(alist_dest->addr), 16) == 0) || ipv6_addr_sol_node_mcast_match(&ipv6_buf->destaddr)) { memcpy(&(ipv6_buf->destaddr.uint8[0]), &(ipv6_buf->srcaddr.uint8[0]), 16); memcpy(&(ipv6_buf->srcaddr.uint8[0]), &(nbr_sol_buf->tgtaddr.uint8[0]), 16); send_na = 1; } } if (send_na) { /* solicited na */ uint8_t flags = (NBR_ADV_FLAG_O | NBR_ADV_FLAG_S); init_nbr_adv(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr), &(alist_targ->addr), flags, 0, OPT_ARO, aro_state); #if ENABLE_DEBUG printf("INFO: send neighbor advertisment to: "); ipv6_print_addr(&ipv6_buf->destaddr); #endif lowpan_init((ieee_802154_long_t *) & (ipv6_buf->destaddr.uint16[4]), (uint8_t *)ipv6_buf); } }
void recv_rtr_adv(void) { int8_t trigger_ns = -1; int8_t abro_found = 0; int16_t abro_version = 0; /* later replaced, just to supress warnings */ ipv6_addr_t abro_addr; ipv6_buf = get_ipv6_buf(); opt_hdr_len = RTR_ADV_LEN; rtr_adv_buf = get_rtr_adv_buf(ipv6_ext_hdr_len); ipv6_addr_t newaddr; recvd_cids_len = 0; /* update interface reachable time and retrans timer */ if (rtr_adv_buf->reachable_time != 0) { iface.adv_reachable_time = HTONL(rtr_adv_buf->reachable_time); } if (rtr_adv_buf->retrans_timer != 0) { iface.adv_retrans_timer = HTONL(rtr_adv_buf->retrans_timer); } def_rtr_entry = def_rtr_lst_search(&ipv6_buf->srcaddr); if (rtr_adv_buf->router_lifetime != 0) { if (def_rtr_entry != NULL) { set_remaining_time(&(def_rtr_entry->inval_time), HTONL(rtr_adv_buf->router_lifetime)); } else { def_rtr_lst_add(&(ipv6_buf->srcaddr), HTONL(rtr_adv_buf->router_lifetime)); trigger_ns = 1; } } else { /* remove router from default router list */ if (def_rtr_entry != NULL) { def_rtr_lst_rem(def_rtr_entry); } } mutex_lock(&lowpan_context_mutex); /* read options */ while (packet_length > IPV6HDR_ICMPV6HDR_LEN + opt_hdr_len) { opt_buf = get_opt_buf(ipv6_ext_hdr_len, opt_hdr_len); switch(opt_buf->type) { case (OPT_SLLAO_TYPE): { break; } case (OPT_MTU_TYPE): { break; } /* rfc 4862 section 5.5.3 */ case (OPT_PI_TYPE): { opt_pi_buf = get_opt_pi_buf(ipv6_ext_hdr_len, opt_hdr_len); /* crazy condition, read 5.5.3a-b-c for further information */ if (ipv6_prefix_ll_match(&opt_pi_buf->addr) || (HTONL(opt_pi_buf->pref_ltime) > HTONL(opt_pi_buf->val_ltime))) { break; } else { /* check if on-link flag is set */ if (opt_pi_buf->l_a_reserved1 & OPT_PI_FLAG_L) { /* TODO: do on-link pi handling */ } if (opt_pi_buf->l_a_reserved1 & OPT_PI_FLAG_A) { addr_list_ptr = ipv6_iface_addr_prefix_eq(&opt_pi_buf->addr); if (addr_list_ptr == NULL) { /* 5.5.3d */ if (opt_pi_buf->val_ltime != 0) { /* iid will also be added here */ ipv6_init_addr_prefix(&newaddr, &opt_pi_buf->addr); /* add into address list * TODO: duplicate address detection is not * implementet yet, so all new addresse will * be added with state PREFFERED */ ipv6_iface_add_addr(&newaddr, ADDR_STATE_PREFERRED, opt_pi_buf->val_ltime, opt_pi_buf->pref_ltime, ADDR_CONFIGURED_AUTO); printf("INFO: added address to interface\n"); trigger_ns = 1; } } else { /* 5.5.3e */ set_remaining_time(&(addr_list_ptr->pref_ltime), opt_pi_buf->pref_ltime); /* 7200 = 2hours in seconds */ if (HTONL(opt_pi_buf->val_ltime) > 7200 || HTONL(opt_pi_buf->val_ltime) > get_remaining_time(&(addr_list_ptr->val_ltime))) { set_remaining_time(&(addr_list_ptr->val_ltime), HTONL(opt_pi_buf->val_ltime)); } else { /* reset valid lifetime to 2 hours */ set_remaining_time(&(addr_list_ptr->val_ltime), 7200); } } } } /* TODO: save found prefixes */ break; } case (OPT_6CO_TYPE): { uint8_t comp; uint8_t num; opt_6co_hdr_buf = get_opt_6co_hdr_buf(ipv6_ext_hdr_len, opt_hdr_len); get_opt_6co_flags(&comp, &num, opt_6co_hdr_buf->c_flags); ipv6_addr_t prefix; memset(&prefix, 0, 16); opt_6co_prefix_buf = get_opt_6co_prefix_buf(ipv6_ext_hdr_len, opt_hdr_len + OPT_6CO_HDR_LEN); memcpy(&prefix, opt_6co_prefix_buf, opt_6co_hdr_buf->c_length); lowpan_context_update( num, &prefix, opt_6co_hdr_buf->c_length, comp, HTONS(opt_6co_hdr_buf->val_ltime) ); recvd_cids[recvd_cids_len] = num; recvd_cids_len = (recvd_cids_len + 1) % LOWPAN_CONTEXT_MAX; break; } case (OPT_ABRO_TYPE): { opt_abro_buf = get_opt_abro_buf(ipv6_ext_hdr_len, opt_hdr_len); abro_found = 1; abro_version = HTONS(opt_abro_buf->version); memcpy(&(abro_addr), &(opt_abro_buf->addr), sizeof(ipv6_addr_t)); break; } default: break; } /* multiplied with 8 because options length is in units of 8 bytes */ opt_hdr_len += (opt_buf->length * 8); } if (abro_found) { int i; for (i = 0; i < recvd_cids_len; i++) { abr_add_context(abro_version, &abro_addr, recvd_cids[i]); } } mutex_unlock(&lowpan_context_mutex, 0); if (trigger_ns >= 0) { /* send ns - draft-ietf-6lowpan-nd-15#section-5.5.1 * * section-10.2.4 * "Next the 6LN registers that address with one or more of its * default routers by sending a unicast NS message with an ARO * containing its tentative global IPv6 address to register * * if new address was configured, set src to newaddr(gp16) */ init_nbr_sol(&newaddr, &(ipv6_buf->srcaddr), &(ipv6_buf->srcaddr), OPT_SLLAO, OPT_ARO); #if ENABLE_DEBUG printf("INFO: send neighbor solicitation to: "); ipv6_print_addr(&(ipv6_buf->destaddr)); #endif lowpan_init((ieee_802154_long_t *) & (ipv6_buf->destaddr.uint16[4]), (uint8_t *)ipv6_buf); } }