/* * 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_assert.h" #include "ldp_hello.h" #include "ldp_msg.h" #include "ldp_pdu.h" #include "ldp_adj.h" #include "ldp_hello.h" #include "ldp_entity.h" #include "ldp_session.h" #include "ldp_inet_addr.h" #include "ldp_pdu_setup.h" #include "ldp_socket_impl.h" #include "ldp_timer_impl.h" #include "ldp_lock_impl.h" #include "ldp_trace_impl.h" void ldp_hello_timeout_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_adj* a = (ldp_adj*)extra; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Hello Timout fired: adj(%d)\n",a->index); ldp_lock_get(g->global_lock); ldp_adj_shutdown(g,a); /* timer is deleted inside of ldp_adj_shutdown */ /* the refcount release for the time is done in ldp_adj_shutdown as well */ ldp_lock_release(g->global_lock); } void ldp_hello_send_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_entity* e = (ldp_entity*)extra; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Hello Send fired: entity(%d)\n",e->index); ldp_lock_get(g->global_lock); ldp_hello_send(g,e); ldp_lock_release(g->global_lock); } ldp_return_enum ldp_hello_send(ldp_global* g,ldp_entity* e) { ldp_msg **hello = NULL; ldp_timer_handle* timer; int* oper_duration = 0; int targeted = 0; int duration = 0; int request = 0; LDP_ASSERT(g != NULL && e != NULL); switch(e->entity_type) { case LDP_DIRECT: LDP_ASSERT(e->p.iff != NULL); hello = &e->p.iff->hello; oper_duration = &e->p.iff->hellotime_send_timer_duration; timer = &e->p.iff->hellotime_send_timer; targeted = 0; request = 0; break; case LDP_INDIRECT: LDP_ASSERT(e->p.peer != NULL); hello = &e->p.peer->hello; oper_duration = &e->p.peer->hellotime_send_timer_duration; timer = &e->p.peer->hellotime_send_timer; targeted = 1; if(e->p.peer->target_role == LDP_ACTIVE) { request = 1; } else { request = 0; } break; default: LDP_ASSERT(0); } if(!*hello) { *hello = ldp_hello_create(g->message_identifier++, e->hellotime_timer,&e->transport_address, g->configuration_sequence_number,targeted,request); } duration = e->hellotime_interval; if(ldp_timer_handle_verify(g->timer_handle,*timer) == LDP_FALSE) { LDP_REFCNT_HOLD(e); *timer = ldp_timer_create(g->timer_handle,LDP_SEC,duration,(void*)e, g,ldp_hello_send_callback); if(ldp_timer_handle_verify(g->timer_handle,*timer) == LDP_FALSE) { *oper_duration = 0; LDP_REFCNT_RELEASE(e,ldp_entity_delete); return LDP_FAILURE; } *oper_duration = duration; ldp_timer_start(g->timer_handle,*timer,LDP_REOCCURRING); } else { if((*oper_duration) != duration) { ldp_timer_stop(g->timer_handle,*timer); *oper_duration = duration; ldp_timer_modify(g->timer_handle,*timer,duration); ldp_timer_start(g->timer_handle,*timer,LDP_REOCCURRING); } } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_PERIODIC, "Hello Send: entity(%d)\n",e->index); return ldp_msg_send_udp(g,e,*hello); } ldp_msg *ldp_hello_create(uint32_t msgid,int holdtime,ldp_inet_addr *traddr, uint32_t confnum,int targeted,int request) { mplsLdpHelloMsg_t *hello = NULL; ldp_msg *msg = NULL; msg = ldp_msg_create(MPLS_HELLO_MSGTYPE,msgid); if(msg != NULL) { hello = (mplsLdpHelloMsg_t*)msg->body; hello->trAdrTlvExists = 0; hello->csnTlvExists = 0; hello->chpTlvExists = 1; /* this assumes we always want to receive updates for targeted hellos */ hello->baseMsg.msgLength += setupChpTlv(&(hello->chp),targeted, request,0,holdtime); if(traddr && traddr->protocol == AF_INET && traddr->u.ipv4 > 0) { hello->trAdrTlvExists = 1; hello->baseMsg.msgLength +=setupTrAddrTlv(&(hello->trAdr),traddr->u.ipv4); } if(confnum > 0) { hello->csnTlvExists = 1; hello->baseMsg.msgLength += setupCsnTlv(&(hello->csn),confnum); } } return msg; } ldp_return_enum ldp_hello_process(ldp_global *g,ldp_adj *a,int hellotime, uint32_t csn,ldp_inet_addr *traddr,int targeted,int request) { ldp_entity *e = NULL; ldp_inet_addr *local = NULL,*remote = NULL; ldp_session *session = NULL; LDP_ASSERT(a != NULL); e = a->entity; LDP_ASSERT(e != NULL); LDP_ENTER(g->user_data,"ldp_hello_process"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_PERIODIC, "Hello Recv: entity(%d)\n",e->index); switch(e->entity_type) { case LDP_DIRECT: /* ldp-11 3.5.2. Hello Message */ if(hellotime == 0) hellotime = 15; local = &e->p.iff->local_source_address; break; case LDP_INDIRECT: /* ldp-11 3.5.2. Hello Message */ if(hellotime == 0) hellotime = 45; local = &e->p.peer->local_source_address; break; default: LDP_ASSERT(0); } if(hellotime < e->hellotime_timer) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_NORMAL, "ldp_hello_process: adjusting hellotime_timer to match adj\n"); e->hellotime_timer = hellotime; } if(traddr != NULL) { memcpy(&a->remote_transport_address,traddr, sizeof(struct ldp_inet_addr)); } if(csn != a->remote_csn) { /* the remote csn changes all we can do is clear the backoff time */ /* this will only enable a lsr in the active role to try again */ a->remote_csn = csn; if(ldp_timer_handle_verify(g->timer_handle,a->backoff_timer) == LDP_TRUE) { ldp_adj_backoff_stop(g,a); /* del timer zero a->backoff */ } } if(a->session != NULL) { /* we already have an established session */ LDP_EXIT(g->user_data,"ldp_hello_process"); return LDP_SUCCESS; } if(e->transport_address.protocol != 0) { local = &e->transport_address; } if(a->remote_transport_address.protocol != 0) { remote = &a->remote_transport_address; } else { remote = &a->remote_source_address; } switch(ldp_inet_addr_compare(local,remote)) { case 1: a->role = LDP_ACTIVE; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_STATE, "ldp_hello_process: ACTIVE(%d)\n",a->index); if(ldp_timer_handle_verify(g->timer_handle,a->backoff_timer) == LDP_TRUE) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_NORMAL, "ldp_hello_process: in backoff state(%d)\n",a->index); } else { session = ldp_session_create_active(g,a); if(session == NULL) { LDP_EXIT(g->user_data,"ldp_hello_process-error"); ldp_adj_backoff_start(g,a); return LDP_FAILURE; } } break; case -1: a->role = LDP_PASSIVE; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_STATE, "ldp_hello_process: PASSIVE(%d)\n",a->index); /* at one point we through WE were active and the session failed */ ldp_adj_backoff_stop(g,a); /* del timer zero a->backoff */ /* we only create a passive session when we recieve a CONNECT */ /* session = ldp_session_create_passive(g,a); */ break; default: LDP_PRINT(g->user_data, "ldp_hello_process: exit(%d) configuration error\n",a->index); ldp_adj_shutdown(g,a); return LDP_FAILURE; } LDP_EXIT(g->user_data,"ldp_hello_process"); return LDP_SUCCESS; }