/* * Copyright (C) James R. Leu 2000 * jleu@mindspring.com * * This software is covered under the LGPL, for more * info check out http://www.gnu.org/copyleft/lgpl.html */ #include #include #include "ldp_struct.h" #include "ldp_global.h" #include "ldp_session.h" #include "ldp_hello.h" #include "ldp_global.h" #include "ldp_entity.h" #include "ldp_adj.h" #include "ldp_mm_impl.h" #include "ldp_peer.h" #include "ldp_assert.h" #include "ldp_timer_impl.h" #include "ldp_lock_impl.h" #include "ldp_trace_impl.h" static uint32_t _ldp_adj_next_index = 1; ldp_adj* ldp_adj_create(ldp_inet_addr *source,ldp_inet_addr *lsraddr, int labelspace,int remote_hellotime,ldp_inet_addr *remote_transport_address, uint32_t remote_csn) { ldp_adj* a = (ldp_adj*)ldp_malloc(sizeof(ldp_adj)); if(lsraddr == NULL || source == NULL) return NULL; if(a) { memset(a,0,sizeof(ldp_adj)); LDP_REFCNT_INIT(a,0); LDP_LIST_ELEM_INIT(a,_entity); a->index = _ldp_adj_get_next_index(); /* these are operational values */ /* JLEU: where do I grab these values from */ /* these values are learned form the remote peer */ memcpy(&a->remote_source_address,source,sizeof(ldp_inet_addr)); memcpy(&a->remote_lsr_address,lsraddr,sizeof(ldp_inet_addr)); if(remote_transport_address) { memcpy(&a->remote_transport_address,remote_transport_address, sizeof(ldp_inet_addr)); } else { memset(&a->remote_transport_address,0,sizeof(ldp_inet_addr)); } a->remote_hellotime = remote_hellotime; a->remote_csn = remote_csn; } return a; } void ldp_adj_delete(ldp_adj* a) { // LDP_PRINT(g->user_data,"adj delete\n"); LDP_REFCNT_ASSERT(a,0); ldp_free(a); } ldp_return_enum ldp_adj_startup(ldp_global* g,ldp_adj* a,int request) { ldp_entity *e = a->entity; LDP_ASSERT(a != NULL && a->entity != NULL); LDP_ENTER(g->user_data,"ldp_adj_startup"); /* ldp-11 3.5.2. Hello Message */ if(e->hellotime_timer != 0xFFFF) { LDP_REFCNT_HOLD(a); a->hellotime_recv_timer = ldp_timer_create(g->timer_handle,LDP_SEC, e->hellotime_timer,(void*)a,g,ldp_hello_timeout_callback); if(ldp_timer_handle_verify(g->timer_handle,a->hellotime_recv_timer) == LDP_FALSE) { LDP_REFCNT_RELEASE(a,ldp_adj_delete); LDP_EXIT(g->user_data,"ldp_adj_startup-error"); return LDP_FAILURE; } ldp_timer_start(g->timer_handle,a->hellotime_recv_timer,LDP_ONESHOT); _ldp_global_add_adj(g,a); } if(request && ldp_timer_handle_verify(g->timer_handle, a->entity->p.peer->hellotime_send_timer) == LDP_FALSE) { /* request is ONLY specific with indirect adj */ ldp_hello_send(g,e); } LDP_EXIT(g->user_data,"ldp_adj_startup"); return LDP_SUCCESS; } ldp_return_enum ldp_adj_restart(ldp_global* g,ldp_adj* a) { LDP_ENTER(g->user_data,"ldp_adj_restart"); if(a->session != NULL) { ldp_session_shutdown(g,a->session,0); /* session_shutdown does this already ldp_adj_del_session(a); */ } ldp_timer_stop(g->timer_handle,a->hellotime_recv_timer); ldp_timer_start(g->timer_handle,a->hellotime_recv_timer,LDP_ONESHOT); LDP_EXIT(g->user_data,"ldp_adj_restart"); return LDP_SUCCESS; } ldp_return_enum ldp_adj_shutdown(ldp_global* g,ldp_adj* a) { LDP_ASSERT(g != NULL && a != NULL); LDP_ENTER(g->user_data,"ldp_adj_shutdown"); LDP_REFCNT_HOLD(a); if(a->session != NULL) { ldp_session_shutdown(g,a->session,0); /* session_shutdown does this already ldp_adj_del_session(a); */ } ldp_adj_recv_stop(g,a); LDP_ASSERT(a != NULL); ldp_adj_backoff_stop(g,a); LDP_ASSERT(a != NULL); /* JLEU: this assumes only one ADJ per INDIRECT entity!!! */ if(a->entity->entity_type == LDP_INDIRECT && a->entity->p.peer->target_role == LDP_PASSIVE) { /* we started sending due to a targeted hello with "request" now that the adj is down we can stop */ ldp_peer_send_stop(g,a->entity->p.peer); } LDP_ASSERT(a != NULL); ldp_entity_del_adj(a->entity,a); _ldp_global_del_adj(g,a); LDP_EXIT(g->user_data,"ldp_adj_shutdown"); LDP_REFCNT_RELEASE(a,ldp_adj_delete); return LDP_SUCCESS; } ldp_return_enum ldp_adj_maintain_timer(ldp_global *g,ldp_adj *a) { ldp_return_enum retval; LDP_ENTER(g->user_data,"ldp_adj_maintain_timer"); ldp_timer_stop(g->timer_handle,a->hellotime_recv_timer); retval = ldp_timer_start(g->timer_handle,a->hellotime_recv_timer,LDP_ONESHOT); LDP_EXIT(g->user_data,"ldp_adj_maintain_timer"); return retval; } ldp_return_enum ldp_adj_backoff_stop(ldp_global* g,ldp_adj* a) { LDP_ENTER(g->user_data,"ldp_adj_backoff_stop"); a->backoff = 0; if(ldp_timer_handle_verify(g->timer_handle,a->backoff_timer) == LDP_TRUE) { ldp_timer_stop(g->timer_handle,a->backoff_timer); ldp_timer_delete(g->timer_handle,a->backoff_timer); a->backoff_timer = (ldp_timer_handle)0; LDP_REFCNT_RELEASE(a,ldp_adj_delete); } LDP_EXIT(g->user_data,"ldp_adj_backoff_stop"); return LDP_SUCCESS; } ldp_return_enum ldp_adj_recv_stop(ldp_global* g,ldp_adj* a) { LDP_ENTER(g->user_data,"ldp_adj_recv_stop"); if(ldp_timer_handle_verify(g->timer_handle,a->hellotime_recv_timer) == LDP_TRUE) { ldp_timer_stop(g->timer_handle,a->hellotime_recv_timer); ldp_timer_delete(g->timer_handle,a->hellotime_recv_timer); a->hellotime_recv_timer = (ldp_timer_handle)0; LDP_REFCNT_RELEASE(a,ldp_adj_delete); } LDP_EXIT(g->user_data,"ldp_adj_recv_stop"); return LDP_SUCCESS; } void ldp_adj_backoff_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_adj* a = (ldp_adj*)extra; LDP_ENTER(g->user_data,"ldp_adj_backoff"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Adj Backoff Timer fired: adj(%d)\n",a->index); ldp_lock_get(g->global_lock); a->backoff_timer = 0; if(ldp_session_create_active(g,a) == NULL) { a->backoff += g->backoff_step; a->backoff_timer = timer; ldp_timer_start(g->timer_handle,timer,LDP_ONESHOT); LDP_EXIT(g->user_data,"ldp_adj_backoff-error"); goto ldp_adj_backoff_end; } ldp_timer_stop(g->timer_handle,timer); ldp_timer_delete(g->timer_handle,timer); LDP_REFCNT_RELEASE(a,ldp_adj_delete); ldp_adj_backoff_end: ldp_lock_release(g->global_lock); LDP_EXIT(g->user_data,"ldp_adj_backoff"); } ldp_return_enum ldp_adj_backoff_start(ldp_global* g,ldp_adj* a) { ldp_return_enum retval; LDP_ASSERT(a != NULL); LDP_ENTER(g->user_data,"ldp_adj_backoff_start"); a->backoff += g->backoff_step; if(ldp_timer_handle_verify(g->timer_handle,a->backoff_timer) == LDP_TRUE) { /* this should never happen, but if so */ ldp_timer_stop(g->timer_handle,a->backoff_timer); ldp_timer_delete(g->timer_handle,a->backoff_timer); LDP_REFCNT_RELEASE(a,ldp_adj_delete); a->backoff_timer = (ldp_timer_handle)0; } if(a == NULL) { /* if we deleted adj due to the above RELEASE */ LDP_EXIT(g->user_data,"ldp_adj_backoff_start-error"); return LDP_FAILURE; } LDP_REFCNT_HOLD(a); a->backoff_timer = ldp_timer_create(g->timer_handle,LDP_SEC,a->backoff, (void*)a,g,ldp_adj_backoff_callback); if(ldp_timer_handle_verify(g->timer_handle,a->backoff_timer) == LDP_FALSE) { LDP_REFCNT_RELEASE(a,ldp_adj_delete); LDP_EXIT(g->user_data,"ldp_adj_backoff_start-error"); return LDP_FAILURE; } retval = ldp_timer_start(g->timer_handle,a->backoff_timer,LDP_ONESHOT); LDP_EXIT(g->user_data,"ldp_adj_backoff_start"); return retval; } ldp_return_enum _ldp_adj_add_entity(ldp_adj* a,ldp_entity* e) { if(a && e) { LDP_REFCNT_HOLD(e); a->entity = e; return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum _ldp_adj_del_entity(ldp_adj* a) { if(a && a->entity) { LDP_REFCNT_RELEASE(a->entity,ldp_entity_delete); a->entity = NULL; return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum ldp_adj_add_session(ldp_adj* a,ldp_session* s) { if(a && s && a->entity) { LDP_REFCNT_HOLD(s); a->session = s; _ldp_session_add_adj(s,a); _ldp_entity_add_session(a->entity,s); return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum ldp_adj_del_session(ldp_adj* a) { if(a && a->session && a->entity) { _ldp_session_del_adj(a->session); _ldp_entity_del_session(a->entity,a->session); LDP_REFCNT_RELEASE(a->session,ldp_session_delete); a->session = NULL; return LDP_SUCCESS; } return LDP_FAILURE; } uint32_t _ldp_adj_get_next_index() { uint32_t retval = _ldp_adj_next_index; _ldp_adj_next_index++; if(retval > _ldp_adj_next_index++) { _ldp_adj_next_index = 1; } return retval; }