static int prefha_iterator(void *data, void *args, struct in6_addr *addr, unsigned long *pref) { struct mipv6_halist_entry *entry = (struct mipv6_halist_entry *)data; struct prefha_iterator_args *state = (struct prefha_iterator_args *)args; if (mipv6_prefix_compare(&entry->global_addr, &state->prefix, state->plen)) { state->entry = entry; return ITERATOR_STOP; } return ITERATOR_CONT; }
/** * mn_handoff - called for every bul entry to send BU to CN * @rawentry: bul entry * @args: handoff event * @hashkey: * @sortkey: * * Since MN can have many home addresses and home networks, every BUL entry * needs to be checked **/ static int mn_handoff(void *rawentry, void *args, struct in6_addr *hashkey, unsigned long *sortkey) { __u32 lifetime; int athome; struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry; struct handoff *ho = (struct handoff *)args; int pfixlen = 64; /* Get the prefixlength instead of fixed 64 bits */ athome = mipv6_prefix_compare(&ho->rtr_new.raddr, &entry->home_addr, pfixlen); if (!athome) { lifetime = mipv6_mn_get_bulifetime(&entry->home_addr, &ho->rtr_new.CoA, entry->flags); } else { lifetime = 0; entry->flags = entry->flags | MIPV6_BU_F_DEREG; } if (entry->flags & MIPV6_BU_F_HOME) { DEBUG((DBG_INFO, "Sending home de ? %d registration for " "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" "to home agent %x:%x:%x:%x:%x:%x:%x:%x, " "with lifetime %ld, prefixlength %d", athome, NIPV6ADDR(&entry->home_addr), NIPV6ADDR(&entry->cn_addr), lifetime, entry->prefix)); mipv6_send_upd_option( &entry->home_addr, &entry->cn_addr, HA_BU_DELAY, INITIAL_BINDACK_TIMEOUT, MAX_BINDACK_TIMEOUT, 1, entry->flags, entry->prefix, lifetime, NULL); } else { DEBUG((DBG_INFO, "Sending BU for home address: %x:%x:%x:%x:%x:%x:%x:%x \n" "to CN: %x:%x:%x:%x:%x:%x:%x:%x, " "with lifetime %ld", NIPV6ADDR(&entry->home_addr), NIPV6ADDR(&entry->cn_addr), lifetime)); mipv6_send_upd_option( &entry->home_addr, &entry->cn_addr, CN_BU_DELAY, INITIAL_BINDACK_TIMEOUT, MAX_BINDACK_TIMEOUT, 1, entry->flags, entry->prefix, lifetime, NULL); } return ITERATOR_CONT; }
/** * init_home_registration - start Home Registration process * @hinfo: mn_info entry for the home address * @coa: care-of address * * Checks whether we have a Home Agent address for this home address. * If not starts Dynamic Home Agent Address Discovery. Otherwise * tries to register with home agent if not already registered. **/ int init_home_registration(struct mn_info *hinfo, struct in6_addr *coa) { __u32 lifetime; if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) { hinfo->is_at_home = 1; DEBUG((DBG_INFO, "Adding home address, MN at home")); return 0; } if (ipv6_addr_any(&hinfo->ha)) { DEBUG((DBG_INFO, "Home Agent address not set, initiating DHAAD")); mipv6_mn_dhaad_send_req(&hinfo->home_addr, hinfo->home_plen, &hinfo->dhaad_id); } else { struct mipv6_bul_entry *bul = mipv6_bul_get(&hinfo->ha); if (bul) { if (!ipv6_addr_cmp(&bul->home_addr, &hinfo->home_addr)){ DEBUG((DBG_INFO, "BU already sent to HA")); mipv6_bul_put(bul); return 0; } mipv6_bul_put(bul); } lifetime = mipv6_mn_get_bulifetime( &hinfo->home_addr, coa, MIPV6_BU_F_HOME | MIPV6_BU_F_ACK); DEBUG((DBG_INFO, "Sending initial home registration for " "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" "to home agent %x:%x:%x:%x:%x:%x:%x:%x, " "with lifetime %ld, prefixlength %d", NIPV6ADDR(&hinfo->home_addr), NIPV6ADDR(&hinfo->ha), lifetime, 0)); mipv6_send_upd_option( &hinfo->home_addr, &hinfo->ha, HA_BU_DELAY, INITIAL_BINDACK_DAD_TIMEOUT, MAX_BINDACK_TIMEOUT, 1, MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | MIPV6_BU_F_DAD, 0, lifetime, NULL); } return 0; }
/** * mipv6_mobile_node_moved - Sends BUs to all HAs and CNs * @ho: handoff structure contains the new and previous routers **/ int mipv6_mobile_node_moved(struct handoff *ho) { struct mn_info *hinfo = NULL; unsigned long lifetime = 1234; int bu_to_prev_router = 1; int dummy; DEBUG_FUNC(); if (!mipv6_is_initialized) return 0; ma_ctl_upd_iface(ho->rtr_new.ifindex, MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy); /* First send BUs to all nodes which are on BU list */ bul_iterate(mn_handoff, (void *)ho); /* Then go through the home infos to see if there's a new one * which has not been registered */ /* TODO: Should the previous router acting as a HA and the * previous CoA be also added to the mn_info list */ read_lock_bh(&mn_info_lock); for (hinfo = mn_info_base; hinfo; hinfo = hinfo->next) { if (mipv6_prefix_compare(&hinfo->home_addr, &ho->rtr_new.raddr, hinfo->home_plen)) { if (!hinfo->is_at_home) hinfo->is_at_home = 1; } else { hinfo->is_at_home = 0; if (!hinfo->has_home_reg) { init_home_registration(hinfo, &ho->rtr_new.CoA); } } /* Check here whether the previous CoA is in fact a regular * home address, which is being registered in any case * TODO: Add a mn_info for the previous router and purge it * or do DHAAD after the lifetime of the HA expires. Remove the * comparison between home agent address and prev. router address * after bul can handle multiple entries for same CN! */ if (ho->has_rtr_prev && (!ipv6_addr_cmp(&hinfo->home_addr, &ho->rtr_prev.CoA) || !ipv6_addr_cmp(&hinfo->ha, &ho->rtr_prev.raddr))) bu_to_prev_router = 0; } read_unlock_bh(&mn_info_lock); /* Send BU to previous router if it acts as a HA * TODO: Should the previous CoA be added to the mn_info list? */ if (ho->has_rtr_prev && ho->rtr_prev.flags & ND_RA_FLAG_HA && ho->rtr_prev.glob_addr && bu_to_prev_router) { lifetime = mipv6_mn_get_bulifetime(&ho->rtr_prev.CoA, &ho->rtr_new.CoA, MIPV6_BU_F_HOME | MIPV6_BU_F_ACK); mipv6_send_upd_option( &ho->rtr_prev.CoA, &ho->rtr_prev.raddr, HA_BU_DELAY, INITIAL_BINDACK_DAD_TIMEOUT, MAX_BINDACK_TIMEOUT, 1, MIPV6_BU_F_HOME | MIPV6_BU_F_ACK, 0, lifetime, NULL); } return 0; }