/* * 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 #include "ldp_struct.h" #include "ldp_session.h" #include "ldp_pdu_setup.h" #include "ldp_addr.h" #include "ldp_pdu.h" #include "ldp_msg.h" #include "ldp_ifmgr_impl.h" #include "ldp_mm_impl.h" #include "ldp_trace_impl.h" #include "ldp_tree_impl.h" static uint32_t _ldp_addr_next_index = 1; ldp_addr* ldp_addr_create(ldp_inet_addr *address) { ldp_addr* a = (ldp_addr*)ldp_malloc(sizeof(ldp_addr)); if(a) { LDP_REFCNT_INIT(a,0); LDP_LIST_INIT(&a->session_root,ldp_session_elem); memcpy(&a->address,address,sizeof(ldp_inet_addr)); a->index = _ldp_session_get_next_index(); } return a; } void ldp_addr_delete(ldp_addr* a) { //LDP_PRINT(g->user_data,"addr delete\n"); ldp_free(a); } struct ldp_addr_elem* ldp_addr_elem_create(ldp_addr* addr) { struct ldp_addr_elem* e = (struct ldp_addr_elem*)ldp_malloc(sizeof(struct ldp_addr_elem)); if(e != NULL) { LDP_LIST_ELEM_INIT(e,_elem); LDP_REFCNT_HOLD(addr); e->addr = addr; } return e; } ldp_return_enum ldp_addr_elem_delete(struct ldp_addr_elem* e) { if(e == NULL) return LDP_FAILURE; LDP_REFCNT_RELEASE(e->addr,ldp_addr_delete); ldp_free(e); return LDP_SUCCESS; } ldp_return_enum _ldp_addr_add_session(ldp_addr* a,ldp_session* s) { if(a && s) { struct ldp_session_elem* e = ldp_session_elem_create(s); if(e) { LDP_LIST_ADD_HEAD(&a->session_root,e,_elem,ldp_session_elem); return LDP_SUCCESS; } } return LDP_FAILURE; } ldp_return_enum _ldp_addr_del_session(ldp_addr* a,ldp_session* s) { struct ldp_session_elem* e = NULL; if(a && s) { e = LDP_LIST_HEAD(&a->session_root); while(e != NULL) { if((e->session != NULL) && e->session->index == s->index) { LDP_LIST_REMOVE(&a->session_root,e,_elem); ldp_session_elem_delete(e); return LDP_SUCCESS; } e = LDP_LIST_NEXT(&a->session_root,e,_elem); } } return LDP_FAILURE; } uint32_t _ldp_addr_get_next_index() { uint32_t retval = _ldp_addr_next_index; _ldp_addr_next_index++; if(retval > _ldp_addr_next_index++) { _ldp_addr_next_index = 1; } return retval; } ldp_msg* ldp_addr_msg_create(ldp_global* g,uint32_t msgid,ldp_if* i) { ldp_msg *msg = ldp_msg_create(MPLS_ADDR_MSGTYPE,msgid); ldp_inet_addr if_addr; MPLS_MSGPTR(Adr); LDP_ENTER(g->user_data,"ldp_addr_msg_create"); if(msg != NULL) { MPLS_MSGCAST(Adr,msg->body); if(ldp_ifmgr_get_address(g->ifmgr_handle,i->handle,&if_addr,NULL,NULL) == LDP_FAILURE) return NULL; MPLS_MSGPARAM(Adr)->adrListTlvExists = 1; MPLS_MSGPARAM(Adr)->baseMsg.msgLength += setupAddrTlv(&(MPLS_MSGPARAM(Adr)->addressList)); MPLS_MSGPARAM(Adr)->baseMsg.msgLength += addAddrElem2AddrTlv(&(MPLS_MSGPARAM(Adr)->addressList),if_addr.u.ipv4); } LDP_EXIT(g->user_data,"ldp_addr_msg_create"); return msg; } ldp_return_enum ldp_addr_send(ldp_global* g,ldp_session* s,ldp_if* i) { ldp_msg *addr = NULL; ldp_return_enum result = LDP_FAILURE; LDP_ASSERT(s != NULL && i != NULL); LDP_ENTER(g->user_data,"ldp_addr_send"); if((addr = ldp_addr_msg_create(g,g->message_identifier++,i)) == NULL) return LDP_FAILURE; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_ADDRESS, "Addr Send: session(%d)\n",s->index); result = ldp_msg_send_tcp(g,s,addr); ldp_msg_delete(addr); LDP_EXIT(g->user_data,"ldp_addr_send"); return result; } ldp_return_enum ldp_addr_process(ldp_global* g,ldp_session* s,ldp_entity *e, ldp_msg *msg) { mplsLdpAdrMsg_t* body = ((mplsLdpAdrMsg_t*)msg->body); ldp_inet_addr inet; ldp_addr *addr = NULL; int len = (body->addressList.baseTlv.length - MPLS_ADDFAMFIXLEN) / MPLS_IPv4LEN; int i; LDP_ENTER(g->user_data,"ldp_addr_process"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_RECV,LDP_TRACE_FLAG_ADDRESS, "Addr Recv: session(%d)\n",s->index); for(i = 0;i < len;i++) { inet.protocol = AF_INET; inet.u.ipv4 = body->addressList.address[i]; if(((mplsLdpMsg_t*)msg->body)->flags.flags.msgType == MPLS_ADDR_MSGTYPE) { if(ldp_tree_get(g->addr_tree,inet.u.ipv4,32,(void**)&addr) == LDP_FAILURE) { /* it's not in the tree, put it there! */ if((addr = ldp_addr_create(&inet)) == NULL) { LDP_PRINT(g->user_data,"ldp_addr_process: error creating address\n"); goto ldp_addr_process_end; } LDP_REFCNT_HOLD(addr); if(ldp_tree_insert(g->addr_tree,inet.u.ipv4,32,(void*)addr) == LDP_FAILURE) { LDP_PRINT(g->user_data,"ldp_addr_process: error adding addr\n"); goto ldp_addr_process_end; } } /* the addr is in the tree */ if(ldp_session_add_addr(s,addr) == LDP_FAILURE) { LDP_PRINT(g->user_data, "ldp_addr_process: error adding address to session\n"); return LDP_FAILURE; } } else { /* addr withdrawl */ if(ldp_tree_get(g->addr_tree,inet.u.ipv4,32,(void**)&addr) == LDP_SUCCESS) { ldp_session_del_addr(s,addr); if(LDP_REFCNT_VALUE(addr) == 1) { /* the tree is the last one holding a ref to this addr */ ldp_tree_remove(g->addr_tree,inet.u.ipv4,32,(void**)&addr); LDP_REFCNT_RELEASE(addr,ldp_addr_delete); } } } } LDP_EXIT(g->user_data,"ldp_addr_process"); return LDP_SUCCESS; ldp_addr_process_end: if(addr != NULL) ldp_addr_delete(addr); LDP_EXIT(g->user_data,"ldp_addr_process-error"); return LDP_FAILURE; }