/* Check if binding has been used recently and send a binding refresh * request to get a new BU */ void mh_send_brr(struct in6_addr *mn_addr, struct in6_addr *local) { struct iovec mh_vec; struct in6_addr_bundle addrs; struct timespec now; long last_used; clock_gettime(CLOCK_REALTIME, &now); last_used = xfrm_last_used(mn_addr, local, IPPROTO_ROUTING, &now); if (last_used < 0) return; if (last_used > CN_BRR_TIME_THRESH) { dbg("Binding is about to expire, no need to send a BRR\n"); return; } /* Should we check for a BUL entry here? */ dbg("Binding is about to expire, sending a BRR\n"); addrs.src = local; addrs.dst = mn_addr; addrs.remote_coa = NULL; addrs.local_coa = NULL; if (!mh_create(&mh_vec, IP6_MH_TYPE_BRR)) return; mh_send(&addrs, &mh_vec, 1, NULL, 0); free_iov_data(&mh_vec, 1); }
void mh_send_ba(const struct in6_addr_bundle *addrs, uint8_t status, uint8_t flags, uint16_t sequence, const struct timespec *lifetime, const uint8_t *key, int iif) { int iovlen = 1; struct ip6_mh_binding_ack *ba; struct iovec mh_vec[2]; MDBG("status %d\n", status); ba = mh_create(mh_vec, IP6_MH_TYPE_BACK); if (!ba) return; ba->ip6mhba_status = status; ba->ip6mhba_flags = flags; ba->ip6mhba_seqno = htons(sequence); ba->ip6mhba_lifetime = htons(lifetime->tv_sec >> 2); if (status < IP6_MH_BAS_UNSPECIFIED && !conf.NonVolatileBindingCache) { struct timespec refresh; tsclear(refresh); if (conf.pmgr.use_bradv(addrs->dst, addrs->bind_coa, addrs->src, lifetime, &refresh) && tsbefore(*lifetime, refresh)) mh_create_opt_refresh_advice(&mh_vec[iovlen++], refresh.tv_sec); } if (key) mh_create_opt_auth_data(&mh_vec[iovlen++]); mh_send(addrs, mh_vec, iovlen, key, iif); free_iov_data(mh_vec, iovlen); }
void mh_send_be(struct in6_addr *dst, struct in6_addr *hoa, struct in6_addr *src, uint8_t status, int iif) { struct ip6_mh_binding_error *be; struct iovec iov; struct in6_addr_bundle out; if (IN6_IS_ADDR_UNSPECIFIED(dst) || IN6_IS_ADDR_LOOPBACK(dst) || IN6_IS_ADDR_MULTICAST(dst)) { MDBG("Omit BE for non-unicast " "%x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(dst)); return; } out.remote_coa = NULL; out.local_coa = NULL; be = mh_create(&iov, IP6_MH_TYPE_BERROR); if (!be) return; be->ip6mhbe_status = status; out.src = src; out.dst = dst; if (hoa) be->ip6mhbe_homeaddr = *hoa; out.dst = dst; mh_send(&out, &iov, 1, NULL, iif); free_iov_data(&iov, 1); }
//--------------------------------------------------------------------------------------------------------------------- static int pmip_cache_delete_each(void *data, void *arg) //--------------------------------------------------------------------------------------------------------------------- { pmip_entry_t *bce = (pmip_entry_t *) data; if (is_mag()) { //Delete existing route & rule for the deleted MN mag_remove_route(&bce->mn_addr, bce->link); int usercount = tunnel_getusers(bce->tunnel); dbg("# of binding entries %d \n", usercount); if (usercount == 1) { route_del(bce->tunnel, RT6_TABLE_PMIP, IP6_RT_PRIO_MIP6_FWD, &in6addr_any, 0, &in6addr_any, 0, NULL); } //decrement users of old tunnel. pmip_tunnel_del(bce->tunnel); } //Delete existing route for the deleted MN if (is_lma()) { lma_remove_route(&bce->mn_addr, bce->tunnel); //decrement users of old tunnel. pmip_tunnel_del(bce->tunnel); } //Delete the Entry. free_iov_data((struct iovec *) &bce->mh_vec, bce->iovlen); pmip_bce_delete(bce); return 0; }
//--------------------------------------------------------------------------------------------------------------------- void pmip_timer_retrans_pbu_handler(struct tq_elem *tqe) { int mutex_return_code; mutex_return_code = pthread_rwlock_wrlock(&pmip_lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_wrlock(&pmip_lock) %s\n", strerror(mutex_return_code)); } printf("-------------------------------------\n"); if (!task_interrupted()) { pmip_entry_t *e = tq_data(tqe, pmip_entry_t, tqe); mutex_return_code = pthread_rwlock_wrlock(&e->lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_wrlock(&e->lock) %s\n", strerror(mutex_return_code)); } dbg("Retransmissions counter : %d\n", e->n_rets_counter); if (e->n_rets_counter == 0) { free_iov_data((struct iovec *) &e->mh_vec, e->iovlen); dbg("No PBA received from LMA....\n"); dbg("Abort Trasmitting the PBU....\n"); mutex_return_code = pthread_rwlock_unlock(&e->lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&e->lock) %s\n", strerror(mutex_return_code)); } pmip_bce_delete(e); } else { //Decrement the N trasnmissions counter. e->n_rets_counter--; struct in6_addr_bundle addrs; addrs.src = &conf.OurAddress; addrs.dst = &conf.LmaAddress; //sends a PBU dbg("Send PBU again....\n"); // INCREMENT SEQ NUMBER OF PBU e->seqno_out = get_new_pbu_sequence_number(); ((struct ip6_mh_binding_update *)(e->mh_vec[0].iov_base))->ip6mhbu_seqno = htons(e->seqno_out); pmip_mh_send(&addrs, e->mh_vec, e->iovlen, e->link); //add a new task for PBU retransmission. struct timespec expires; clock_gettime(CLOCK_REALTIME, &e->add_time); tsadd(e->add_time, conf.RetransmissionTimeOut, expires); add_task_abs(&expires, &e->tqe, pmip_timer_retrans_pbu_handler); dbg("PBU Retransmissions timer is triggered again....\n"); mutex_return_code = pthread_rwlock_unlock(&e->lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&e->lock) %s\n", strerror(mutex_return_code)); } } } mutex_return_code = pthread_rwlock_unlock(&pmip_lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&pmip_lock) %s\n", strerror(mutex_return_code)); } }
int ndisc_send_na(int ifindex, const struct in6_addr *src, const struct in6_addr *dst, const struct in6_addr *target, uint32_t flags) { struct nd_neighbor_advert *na; struct iovec iov[2]; uint8_t l2addr[L2ADDR_MAX_SIZE]; int len, iovlen = 0; memset(iov, 0, sizeof(iov)); if ((len = ndisc_l2addr_to_opt(ifindex, l2addr)) < 0) return -EINVAL; na = icmp6_create(iov, ND_NEIGHBOR_ADVERT, iovlen++); if (na == NULL) return -ENOMEM; if (len > 0) { if (nd_opt_create(&iov[iovlen], ND_OPT_TARGET_LINKADDR, len, l2addr) == NULL) { free_iov_data(iov, iovlen); return -ENOMEM; } iovlen++; } na->nd_na_target = *target; na->nd_na_flags_reserved = flags; icmp6_send(ifindex, 255, src, dst, iov, iovlen); free_iov_data(iov, iovlen); statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_NA); return 0; }
//--------------------------------------------------------------------------------------------------------------------- void pmip_timer_bce_expired_handler(struct tq_elem *tqe) { int mutex_return_code; mutex_return_code = pthread_rwlock_wrlock(&pmip_lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_wrlock(&pmip_lock) %s\n", strerror(mutex_return_code)); } printf("-------------------------------------\n"); if (!task_interrupted()) { pmip_entry_t *e = tq_data(tqe, pmip_entry_t, tqe); mutex_return_code = pthread_rwlock_wrlock(&e->lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_wrlock(&e->lock) %s\n", strerror(mutex_return_code)); } dbg("Retransmissions counter : %d\n", e->n_rets_counter); if (e->n_rets_counter == 0) { dbg("Retransmissions counter expired\n"); free_iov_data((struct iovec *) &e->mh_vec, e->iovlen); if (is_mag()) { //++e->seqno_out; dbg("Calling deregistration\n"); mag_dereg(e, 1); pmipcache_release_entry(e); pmip_bce_delete(e); return; } //Delete existing route for the deleted MN if (is_ha()) { lma_dereg(e, 0, 0); pmipcache_release_entry(e); pmip_bce_delete(e); return; } mutex_return_code = pthread_rwlock_unlock(&pmip_lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&pmip_lock) %s\n", strerror(mutex_return_code)); } return; } if (is_mag()) { dbg("Send NS for Neighbour Reachability for:%x:%x:%x:%x:%x:%x:%x:%x iif=%d\n", NIP6ADDR(&e->mn_hw_address), e->link); //Create NS for Reachability test! //ndisc_send_ns(e->link, &conf.MagAddressIngress[0], solicited_mcast(&e->mn_suffix), get_mn_addr(e)); ndisc_send_ns(e->link, get_mn_addr(e)); struct timespec expires; clock_gettime(CLOCK_REALTIME, &e->add_time); tsadd(e->add_time, conf.RetransmissionTimeOut, expires); // Add a new task for deletion of entry if No Na is received. add_task_abs(&expires, &e->tqe, pmip_timer_bce_expired_handler); dbg("Start the Timer for Retransmission/Deletion ....\n"); //Decrements the Retransmissions counter. e->n_rets_counter--; mutex_return_code = pthread_rwlock_unlock(&e->lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&e->lock) %s\n", strerror(mutex_return_code)); } } if (is_ha()) { lma_dereg(e, 0, 0); pmipcache_release_entry(e); pmip_bce_delete(e); return; } } mutex_return_code = pthread_rwlock_unlock(&pmip_lock); if (mutex_return_code != 0) { dbg("pthread_rwlock_unlock(&pmip_lock) %s\n", strerror(mutex_return_code)); } }