diff --git a/src/common/capwap_network.c b/src/common/capwap_network.c index 6a779e2..2b30a3c 100644 --- a/src/common/capwap_network.c +++ b/src/common/capwap_network.c @@ -143,6 +143,15 @@ int capwap_bind_sockets(struct capwap_network* net) { return result; } +/* */ +int capwap_connect_socket(struct capwap_network* net, union sockaddr_capwap *peeraddr) +{ + if (net->socket < 0) + return -1; + + return connect(net->socket, &peeraddr->sa, sizeof(peeraddr->ss)); +} + /* Close socket */ void capwap_close_sockets(struct capwap_network* net) { ASSERT(net != NULL); @@ -154,6 +163,17 @@ void capwap_close_sockets(struct capwap_network* net) { } } +/* */ +int capwap_getsockname(struct capwap_network* net, union sockaddr_capwap *addr) +{ + socklen_t addrlen = sizeof(addr->ss); + + if (net->socket < 0) + return -1; + + return getsockname(net->socket, &addr->sa, &addrlen); +} + /* */ int capwap_ipv4_mapped_ipv6(union sockaddr_capwap* addr) { uint32_t inetaddr; diff --git a/src/common/capwap_network.h b/src/common/capwap_network.h index 7de43eb..3928e82 100644 --- a/src/common/capwap_network.h +++ b/src/common/capwap_network.h @@ -56,8 +56,11 @@ int capwap_get_macaddress_from_interface(const char* interface, char* macaddress int capwap_network_get_localaddress(union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr, char* iface); int capwap_bind_sockets(struct capwap_network* net); +int capwap_connect_socket(struct capwap_network* net, union sockaddr_capwap *peeraddr); void capwap_close_sockets(struct capwap_network* net); +int capwap_getsockname(struct capwap_network* net, union sockaddr_capwap *addr); + int capwap_ipv4_mapped_ipv6(union sockaddr_capwap* addr); int capwap_compare_ip(union sockaddr_capwap* addr1, union sockaddr_capwap* addr2); diff --git a/src/wtp/wtp_dfa.c b/src/wtp/wtp_dfa.c index 7ed741f..549f6bd 100644 --- a/src/wtp/wtp_dfa.c +++ b/src/wtp/wtp_dfa.c @@ -363,8 +363,9 @@ int wtp_dfa_running(void) { int check; /* Check source */ - if (capwap_compare_ip(&g_wtp.dtls.peeraddr, &fromaddr)) { - capwap_logging_debug("WTP compare failed, drop packet"); + if (g_wtp.state != CAPWAP_DISCOVERY_STATE && + capwap_compare_ip(&g_wtp.dtls.peeraddr, &fromaddr)) { + capwap_logging_debug("CAPWAP packet from unknown WTP when not in DISCOVERY, drop packet"); continue; /* Unknown source */ } diff --git a/src/wtp/wtp_dfa_discovery.c b/src/wtp/wtp_dfa_discovery.c index e51c339..5d6c9d9 100644 --- a/src/wtp/wtp_dfa_discovery.c +++ b/src/wtp/wtp_dfa_discovery.c @@ -106,22 +106,30 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo if (peeraddr.ss.ss_family != AF_UNSPEC) { union sockaddr_capwap localaddr; - /* Retrieve local address */ - if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) { - CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr)); - - /* */ - capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr); - - /* */ - if (!g_wtp.enabledtls) { - wtp_send_join(); /* Bypass DTLS connection */ - } else { - wtp_start_dtlssetup(); /* Create DTLS connection */ - } - + if (capwap_connect_socket(&g_wtp.net, &peeraddr) < 0) { + capwap_logging_fatal("Cannot bind control address"); + capwap_close_sockets(&g_wtp.net); return; } + + /* Retrieve local address */ + if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) { + capwap_logging_fatal("Cannot get local endpoint address"); + capwap_close_sockets(&g_wtp.net); + return; + } + + /* */ + capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr); + + /* */ + if (!g_wtp.enabledtls) { + wtp_send_join(); /* Bypass DTLS connection */ + } else { + wtp_start_dtlssetup(); /* Create DTLS connection */ + } + + return; } } @@ -136,6 +144,12 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo struct capwap_header_data capwapheader; struct capwap_packet_txmng* txmngpacket; + if (g_wtp.net.socket < 0) + if (capwap_bind_sockets(&g_wtp.net) < 0) { + capwap_logging_fatal("Cannot bind control address"); + exit(-1); + } + /* Update status radio */ g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use(); @@ -184,7 +198,8 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo } /* */ -void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) { +void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) +{ unsigned short binding; struct capwap_array* controlip; @@ -192,7 +207,10 @@ void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) { /* */ binding = GET_WBID_HEADER(packet->rxmngpacket->header); - if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && (g_wtp.localseqnumber == packet->rxmngpacket->ctrlmsg.seq)) { + if ((binding == g_wtp.binding) && + (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && + (g_wtp.localseqnumber == packet->rxmngpacket->ctrlmsg.seq)) + { struct capwap_resultcode_element* resultcode; /* */ diff --git a/src/wtp/wtp_dfa_idle.c b/src/wtp/wtp_dfa_idle.c index de86bfd..10ec27b 100644 --- a/src/wtp/wtp_dfa_idle.c +++ b/src/wtp/wtp_dfa_idle.c @@ -2,6 +2,61 @@ #include "capwap_dfa.h" #include "wtp_dfa.h" +static int wtp_join_prefered_ac() +{ + if (g_wtp.acdiscoveryrequest || + g_wtp.acpreferedarray->count == 0) + /* goto discovery */ + return -1; + + while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) + { + union sockaddr_capwap localaddr; + union sockaddr_capwap *peeraddr; + + /* Found in configuration file the AC address */ + peeraddr = capwap_array_get_item_pointer(g_wtp.acpreferedarray, + g_wtp.acpreferedselected); + + /* Next AC */ + g_wtp.acpreferedselected++; + + /* restart and connect the control Socket */ + capwap_close_sockets(&g_wtp.net); + if (capwap_bind_sockets(&g_wtp.net) < 0) { + capwap_logging_fatal("Cannot bind control address"); + return -1; + } + + if (capwap_connect_socket(&g_wtp.net, peeraddr) < 0) { + capwap_logging_fatal("Cannot bind control address"); + capwap_close_sockets(&g_wtp.net); + return -1; + } + + /* Retrieve local address */ + if (capwap_getsockname(&g_wtp.net, &localaddr) < 0) { + capwap_logging_fatal("Cannot get local endpoint address"); + capwap_close_sockets(&g_wtp.net); + return -1; + } + + /* */ + capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, peeraddr); + + /* */ + if (!g_wtp.enabledtls) { + wtp_send_join(); /* Bypass DTLS connection */ + } else { + wtp_start_dtlssetup(); /* Create DTLS connection */ + } + + return 0; + } + + return -1; +} + /* */ void wtp_dfa_state_idle(void) { long discoveryinterval; @@ -10,36 +65,14 @@ void wtp_dfa_state_idle(void) { g_wtp.teardown = 0; capwap_timeout_unsetall(g_wtp.timeout); - /* */ - if (!g_wtp.acdiscoveryrequest && (g_wtp.acpreferedarray->count > 0)) { - while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) { - union sockaddr_capwap localaddr; - union sockaddr_capwap peeraddr; + if (wtp_join_prefered_ac() == 0) + return; - /* Found in configuration file the AC address */ - memcpy(&peeraddr, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(union sockaddr_capwap)); - - /* Next AC */ - g_wtp.acpreferedselected++; - - /* Retrieve local address */ - if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) { - CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr)); - - /* */ - capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr); - - /* */ - if (!g_wtp.enabledtls) { - wtp_send_join(); /* Bypass DTLS connection */ - } else { - wtp_start_dtlssetup(); /* Create DTLS connection */ - } - - return; - } + if (g_wtp.net.socket < 0) + if (capwap_bind_sockets(&g_wtp.net) < 0) { + capwap_logging_fatal("Cannot bind control address"); + exit(-1); } - } /* Discovery AC */ g_wtp.acpreferedselected = 0;