void network_interface::receive_dao(struct in6_addr from, struct in6_addr ip6_to, const time_t now, const u_char *dat, const int dao_len) { unsigned int dat_len = dao_len; debug->info(" processing dao(%u)",dao_len); struct nd_rpl_dao *dao = (struct nd_rpl_dao *)dat; unsigned char *dat2 = (unsigned char *)(dao+1); dat_len -= sizeof(struct nd_rpl_dao); if(this->packet_too_short("dao", dao_len, sizeof(*dao))) return; dagid_t dagid; char dagid_str[16*6]; dagid[0]=0; if(RPL_DAO_D(dao->rpl_flags)) { memcpy(&dagid, dat2, DAGID_LEN); dag_network::format_dagid(dagid_str, dat2); dat2 += DAGID_LEN; dat_len -= DAGID_LEN; } debug->info_more(" [instance:%u,daoseq:%u,%sdagid:%s]\n", dao->rpl_instanceid, dao->rpl_daoseq, RPL_DAO_K(dao->rpl_flags) ? "dao-ack," : "", dagid_str[0] ? dagid_str : "<elided>"); /* XXX if rpl_instanceid is 0, then we are using a default DAG? */ /* find the relevant DAG */ /* if watching, then we find_or_make, which returns us an * inactive DAO. This might be used to watch a network for RPL * activity. */ class dag_network *dn; if(watching) { dn = dag_network::find_or_make_by_dagid(dagid, this->debug, watching); } else { dn = dag_network::find_by_dagid(dagid); } if(dn) { /* and process it */ dn->receive_dao(this, from, ip6_to, now, dao, dat2, dat_len); } else { dag_network::globalStats[PS_DAO_PACKET_IGNORED]++; } }
/* * Process an incoming DAG Advertisement Object. * the DAO is the upward announcement. * */ void dag_network::receive_dao(network_interface *iface, struct in6_addr from, struct in6_addr ip6_to, const time_t now, const struct nd_rpl_dao *dao, unsigned char *data, int dao_len) { /* it has already been checked to be at least sizeof(*dio) */ //int dao_payload_len = dao_len - sizeof(*dao); /* increment stat of number of packets processed */ this->mStats[PS_PACKET_RECEIVED]++; this->mStats[PS_DAO_PACKET_RECEIVED]++; /* validate this packet, if possible */ bool secure = this->check_security(dao, dao_len); rpl_node *peer; /* find the node entry from this source IP, and update seen time */ /* this will create the node if it does not already exist! */ if((peer = this->update_child(iface, from, ip6_to, now)) == NULL) { return; } if(mActive == false) { this->mStats[PS_PACKETS_WATCHED]++; return; } /* look for the suboptions, process them */ rpl_dao decoded_dao(data, dao_len, this); unsigned int addrcount = 0; struct rpl_dao_target *rpltarget; while((rpltarget = decoded_dao.rpltarget()) != NULL) { char addrfound[SUBNETTOT_BUF]; unsigned char v6bytes[16]; int prefixbytes = ((rpltarget->rpl_dao_prefixlen+7) / 8); ip_subnet prefix; prefix.maskbits = rpltarget->rpl_dao_prefixlen; memset(v6bytes, 0, 16); memcpy(v6bytes, rpltarget->rpl_dao_prefix, prefixbytes); initaddr(v6bytes, 16, AF_INET6, &prefix.addr); addrcount++; subnettot(&prefix, 0, addrfound, sizeof(addrfound)); /* need to look at dag_members, and see if the child node already * exists, and add if not */ debug->verbose(" recv DAO rpltarget re: network %s, target %s (added)\n", addrfound, peer->node_name()); add_childnode(peer, iface, prefix); } maybe_send_dao(); /* now send a DAO-ACK back this the node, using the interface it arrived on, if asked to. */ if(RPL_DAO_K(dao->rpl_flags)) { debug->verbose("sending DAOACK about %u networks, to %s\n", addrcount, peer->node_name()); iface->send_daoack(*peer, *this, dao->rpl_daoseq); } /* increment stat of number of packets processed */ this->mStats[PS_PACKET_PROCESSED]++; }