diff --git a/src/Makefile.am b/src/Makefile.am index 501579e..175a2f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,8 @@ network_inador_SOURCES = network-inador.c network-inador.h \ rta_aux.c rta_aux.h \ routes.c routes.h \ manager-events.c manager-events.h \ - dhcp.c dhcp.h + dhcp.c dhcp.h \ + wireless.c #network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) diff --git a/src/interfaces.c b/src/interfaces.c index 167abce..de20766 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -42,6 +42,7 @@ #include #include "interfaces.h" +#include "wireless.h" #include "manager-events.h" Interface * interfaces_locate_by_index (Interface *list, int index); @@ -331,8 +332,15 @@ void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlm } } break; + //default: + //printf ("RTA Attribute \"%hu\" no procesado\n", attribute->rta_type); } } + + if (was_new) { + /* Como la interfaz es nueva, buscar si tiene extensiones wireless */ + wireless_check_is_wireless_interface (handle, new); + } } void interfaces_del_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h) { @@ -340,6 +348,7 @@ void interfaces_del_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h) Interface *to_del, *last; IPv4 *address; struct rtattr *attribute; + char real_hw[10]; int len; int index; @@ -903,7 +912,7 @@ void interfaces_list_all (NetworkInadorHandle *handle, int sock) { req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); req.hdr.nlmsg_type = RTM_GETLINK; - req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.hdr.nlmsg_seq = global_nl_seq++; req.hdr.nlmsg_pid = local_nl.nl_pid; req.gen.rtgen_family = AF_PACKET; /* no preferred AF, we will get *all* interfaces */ diff --git a/src/network-inador.c b/src/network-inador.c index 098aeab..86a1cb9 100644 --- a/src/network-inador.c +++ b/src/network-inador.c @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include @@ -46,6 +48,7 @@ #include "manager.h" #include "bridge.h" #include "routes.h" +#include "wireless.h" #include "manager-events.h" #include "dhcp.h" @@ -72,14 +75,88 @@ int create_route_netlink_socket (int groups) { return -1; } + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (fd, (struct sockaddr *) &local_nl, &local_size); + + printf ("Primer puerto es %ld\n", local_nl.nl_pid); + return fd; } +static int sigterm_pipe_fds[2] = { -1, -1 }; + +static void sigterm_handler (int signum) { + //fprintf (stderr, "SIGTERM SIGINT Handler\n"); + if (sigterm_pipe_fds[1] >= 0) { + if (write (sigterm_pipe_fds[1], "", 1) == -1 ) { + //fprintf (stderr, "Write to sigterm_pipe failed.\n"); + } + close (sigterm_pipe_fds[1]); + sigterm_pipe_fds[1] = -1; + } +} + +static gboolean quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) { + g_main_loop_quit (loop); +} + +static void setup_signal (void) { + struct sigaction act; + sigset_t empty_mask; + + /* Preparar el pipe para la señal de cierre */ + if (pipe (sigterm_pipe_fds) != 0) { + perror ("Failed to create SIGTERM pipe"); + sigterm_pipe_fds[0] = -1; + } + + /* Instalar un manejador de señales para SIGTERM */ + sigemptyset (&empty_mask); + act.sa_mask = empty_mask; + act.sa_flags = 0; + act.sa_handler = &sigterm_handler; + if (sigaction (SIGTERM, &act, NULL) < 0) { + perror ("Failed to register SIGTERM handler"); + } + + if (sigaction (SIGINT, &act, NULL) < 0) { + perror ("Failed to register SIGINT handler"); + } + + if (sigterm_pipe_fds[0] != -1) { + GIOChannel *io; + + io = g_io_channel_unix_new (sigterm_pipe_fds[0]); + g_io_channel_set_close_on_unref (io, TRUE); + + g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, quit_handler, NULL); + } +} + +void clean_process (NetworkInadorHandle *handle) { + Interface *iface; + + iface = handle->interfaces; + + while (iface != NULL) { + if (iface->dhcp_info.process_pid != 0) { + kill (iface->dhcp_info.process_pid, SIGTERM); + } + } +} + int main (int argc, char *argv[]) { NetworkInadorHandle handle; int nl_sock; int nl_watch; + Interface *to_up; + //signal (SIGPIPE, SIG_IGN); + //signal (SIGCHLD, SIG_IGN); #if !defined(GLIB_VERSION_2_36) g_type_init (); @@ -87,16 +164,21 @@ int main (int argc, char *argv[]) { loop = g_main_loop_new (NULL, FALSE); + setup_signal (); + + /* Inicializar nuestra estructura principal */ handle.interfaces = NULL; handle.rtable_v4 = NULL; - Interface *to_up; - - nl_sock = create_ntlink_socket (0); + /* Crear los sockets de petición */ + nl_sock = create_route_netlink_socket (0); handle.netlink_sock_request = nl_sock; - nl_watch = create_ntlink_socket (-1); + nl_watch = create_route_netlink_socket (-1); + + wireless_init (&handle); manager_events_setup (&handle); + manager_setup_socket (&handle); interfaces_list_all (&handle, nl_sock); @@ -104,8 +186,6 @@ int main (int argc, char *argv[]) { netlink_events_setup_loop (&handle, nl_watch); - manager_setup_socket (&handle); - g_main_loop_run (loop); return 0; diff --git a/src/network-inador.h b/src/network-inador.h index 66bf168..0de19bd 100644 --- a/src/network-inador.h +++ b/src/network-inador.h @@ -65,6 +65,20 @@ typedef struct _IPv4 { struct _IPv4 *next; } IPv4; +typedef struct _WirelessAccessPoint { + int freq; + int essid; + char bssid[10]; + + struct _WirelessAccessPoint *next; +} WirelessAccessPoint; + +typedef struct { + int wiphy; + + WirelessAccessPoint *scaned_aps; +} WirelessInfo; + typedef struct _Interface { char name[IFNAMSIZ]; int ifi_type; @@ -92,6 +106,9 @@ typedef struct _Interface { DHCPStateInfo dhcp_info; + /* Información wireless */ + WirelessInfo *wireless; + struct _Interface *next; } Interface; @@ -113,6 +130,7 @@ typedef struct { Routev4 *rtable_v4; int netlink_sock_request; + int netlink_sock_request_generic; } NetworkInadorHandle; #endif diff --git a/src/wireless.c b/src/wireless.c new file mode 100644 index 0000000..669e6d7 --- /dev/null +++ b/src/wireless.c @@ -0,0 +1,611 @@ +/* + * wireless.c + * This file is part of Network-inador + * + * Copyright (C) 2018 - Félix Arreola Rodríguez + * + * Network-inador is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Network-inador is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Network-inador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "wireless.h" +#include "network-inador.h" +#include "interfaces.h" +#include "rta_aux.h" + +static uint16_t nl80211_id = 0; +static uint16_t scan_multicast_group_id = 0; + +static void _wireless_find_ssid (uint8_t *ies, uint32_t ies_len, unsigned char *ssid, uint32_t *ssid_len) { +#define WLAN_EID_SSID 0 + ssid[0] = 0; + *ssid_len = 0; + + while (ies_len > 2 && ies[0] != WLAN_EID_SSID) { + ies_len -= ies[1] + 2; + ies += ies[1] + 2; + } + if (ies_len < 2) + return; + if (ies_len < (uint32_t)(2 + ies[1])) + return; + + *ssid_len = ies[1]; + memcpy (ssid, ies + 2, ies[1]); +} + +static int _wireless_create_generic_netlink_socket (void) { + int fd; + struct sockaddr_nl local; + + fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + + if (fd < 0) { + return -1; + } + + memset(&local, 0, sizeof(local)); /* fill-in local address information */ + local.nl_family = AF_NETLINK; + local.nl_pid = 0; + local.nl_groups = 0; + + if (bind (fd, (struct sockaddr *) &local, sizeof(local)) < 0) { + perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support"); + close (fd); + return -1; + } + + return fd; +} + +static uint16_t _wireless_parse_family_id (struct nlmsghdr *msg_ptr) { + struct genlmsghdr *ghdr; + struct rtattr *attribute; + int len; + + uint16_t n80211_family; + + struct rtattr *nest2_attr, *nest3_attr; + int nest2_size, nest3_size; + int sub2_len, sub3_len; + + ghdr = NLMSG_DATA (msg_ptr); + len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr)); + + attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN); + + for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { + //printf ("Attribute: %d\n", attribute->rta_type); + if (attribute->rta_type == CTRL_ATTR_FAMILY_ID) { + memcpy (&n80211_family, RTA_DATA (attribute), 2); + //printf ("El id del nl80211 es: %hu\n", n80211_family); + } else if (attribute->rta_type == CTRL_ATTR_MCAST_GROUPS) { + //printf ("_____________ Descubriendo la familia nl80211. Multicast groups: \n"); + int id_multicast_group; + char multicast_group_name[512]; + + nest2_size = attribute->rta_len; + nest2_attr = RTA_DATA (attribute); + + while (nest2_size > sizeof (nest2_attr)) { + sub2_len = nest2_attr->rta_len; + if (sub2_len > nest2_size) { + break; + } + + nest3_size = nest2_attr->rta_len; + nest3_attr = RTA_DATA (nest2_attr); + + id_multicast_group = 0; + multicast_group_name[0] = 0; + + while (nest3_size > sizeof (nest3_attr)) { + sub3_len = nest3_attr->rta_len; + if (sub3_len > nest3_size) { + //printf ("Los sub atributos se acabaron prematuramente\n"); + break; + } + //printf ("sub attributo type: %i, size: %d\n", nest3_attr->rta_type, nest3_attr->rta_len); + if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_ID) { + memcpy (&id_multicast_group, RTA_DATA (nest3_attr), sizeof (id_multicast_group)); + } else if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_NAME) { + strncpy (multicast_group_name, RTA_DATA (nest3_attr), sizeof (multicast_group_name)); + } + + nest3_size -= RTA_ALIGN (sub3_len); + nest3_attr = (struct rtattr *) (((char *) nest3_attr) + RTA_ALIGN (sub3_len)); + } + + if (strcmp (multicast_group_name, "scan") == 0) { + scan_multicast_group_id = id_multicast_group; + //printf ("ID del grupo multicast SCAN: %i\n", id_multicast_group); + } + + nest2_size -= RTA_ALIGN (sub2_len); + nest2_attr = (struct rtattr *) (((char *) nest2_attr) + RTA_ALIGN (sub2_len)); + } + } + } + + return n80211_family; +} + +static void _wireless_parse_message_get_iface (struct nlmsghdr *msg_ptr, Interface *iface) { + struct genlmsghdr *ghdr; + struct rtattr *attribute; + int len; + int wiphy; + + /* Anexar la estructura wireless al objeto interfaz */ + WirelessInfo *winfo; + + winfo = (WirelessInfo *) malloc (sizeof (WirelessInfo)); + + if (winfo == NULL) { + return; + } + + memset (winfo, 0, sizeof (winfo)); + + iface->wireless = winfo; + + ghdr = NLMSG_DATA (msg_ptr); + len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr)); + + attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN); + + for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { + printf ("Wireless Attribute: %d\n", attribute->rta_type); + if (attribute->rta_type == NL80211_ATTR_WIPHY) { + memcpy (&wiphy, RTA_DATA (attribute), 4); + iface->wireless->wiphy = wiphy; + } + /*switch(attribute->rta_type) { + default: + printf ("Del interface RTA Attribute \"%hu\" no procesado\n", attribute->rta_type); + }*/ + } +} + +static void _wireless_parse_scan (NetworkInadorHandle *handle, struct nlmsghdr *msg_ptr) { + struct genlmsghdr *ghdr; + struct rtattr *attribute; + int len; + int iface = -1; + + ghdr = NLMSG_DATA (msg_ptr); + len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr)); + + + attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN); + + for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { + //printf ("Wireless scan Attribute: %d\n", attribute->rta_type); + if (attribute->rta_type == NL80211_ATTR_IFINDEX) { + memcpy (&iface, RTA_DATA (attribute), 4); + } + } + + /* Ejecutar el GET Scan */ + if (iface != -1) { + wireless_do_get_scan (handle, iface); + } +} + +static void _wireless_parse_station (struct nlmsghdr *msg_ptr, Interface *iface) { + struct genlmsghdr *ghdr; + struct rtattr *attribute; + int len; + char bss_info[1024]; + int has_bss = 0; + int bss_len; + + ghdr = NLMSG_DATA (msg_ptr); + len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr)); + + attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN); + + for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { + //printf ("Wireless scan Attribute: %d\n", attribute->rta_type); + if (attribute->rta_type == NL80211_ATTR_BSS) { + has_bss = 1; + bss_len = attribute->rta_len; + + memcpy (bss_info, RTA_DATA (attribute), bss_len); + } + } + + if (has_bss == 0) { + /* No hay BSS info */ + return; + } + + printf ("Imprimiendo BSS Attrs:\n"); + attribute = (struct rtattr *) bss_info; + for (; RTA_OK (attribute, bss_len); attribute = RTA_NEXT (attribute, len)) { + + if (attribute->rta_type == NL80211_BSS_BSSID) { + char *mac = RTA_DATA (attribute); + //printf ("MAC access point: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } else if (attribute->rta_type == NL80211_BSS_INFORMATION_ELEMENTS) { + char essid[64]; + essid[0] = 0; + int essid_len = 0; + _wireless_find_ssid (RTA_DATA (attribute), attribute->rta_len, essid, &essid_len); + essid[essid_len] = 0; + printf ("Essid: %s\n", essid); + } else if (attribute->rta_type == NL80211_BSS_STATUS) { + int status; + memcpy (&status, RTA_DATA (attribute), 4); + printf ("-> Bss estatus: %i\n", status); + } else { + printf ("BSS Scan Attribute: %d\n", attribute->rta_type); + } + } +} + +void wireless_do_get_scan (NetworkInadorHandle *handle, int ifindex) { + printf ("DO Scan for iface: %i\n", ifindex); + struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ + struct iovec io; + struct genlmsghdr *ghdr; + struct rtattr *rta; + struct sockaddr_nl kernel; + char buffer[8192]; /* a large buffer */ + int len; + Interface *iface; + + /* Localizar el iface por el índice */ + iface = interfaces_locate_by_index (handle->interfaces, ifindex); + + if (iface == NULL) { + return; + } + + /* Para la respuesta */ + struct nlmsgerr *l_err; + struct nlmsghdr *msg_ptr; /* pointer to current part */ + + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size); + + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + msg_ptr = (struct nlmsghdr *) buffer; + msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr)); + msg_ptr->nlmsg_type = nl80211_id; + msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; + msg_ptr->nlmsg_seq = global_nl_seq++; + msg_ptr->nlmsg_pid = local_nl.nl_pid; + + ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr); + ghdr->cmd = NL80211_CMD_GET_SCAN; + ghdr->version = 0; + + rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &ifindex, 4); + //rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->wiphy, 4); + + io.iov_base = buffer; + io.iov_len = msg_ptr->nlmsg_len; + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + len = sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof (kernel); + + len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0); + + if (len <= 0) { + return; + } + + msg_ptr = (struct nlmsghdr *) buffer; + printf ("Procesando mensajes de solicitud de escaneo\n"); + for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { + if (msg_ptr->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *l_err; + l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr); + printf ("DO Scan message error, num: %i\n", l_err->error); + break; + } else if (msg_ptr->nlmsg_type == NLMSG_DONE) { + printf ("DO Scan, end of DUMP\n"); + break; + } else if (msg_ptr->nlmsg_type == nl80211_id) { + ghdr = NLMSG_DATA (msg_ptr); + + //printf ("DO SCAN! Generic command: %i\n", ghdr->cmd); + if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) { + _wireless_parse_station (msg_ptr, iface); + } + } + } +} + +gboolean _wireless_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) { + NetworkInadorHandle *handle = (NetworkInadorHandle *) data; + int sock; + + sock = g_io_channel_unix_get_fd (source); + + char reply[8192]; /* a large buffer */ + struct sockaddr_nl kernel; + int len; + + struct iovec io; + /* Para la respuesta */ + struct nlmsghdr *msg_ptr; /* pointer to current part */ + struct msghdr rtnl_reply; /* generic msghdr structure */ + struct iovec io_reply; + struct genlmsghdr *ghdr; + + /* Esperar la respuesta */ + memset(&io_reply, 0, sizeof(io_reply)); + memset(&rtnl_reply, 0, sizeof(rtnl_reply)); + + io.iov_base = reply; + io.iov_len = sizeof (reply); + rtnl_reply.msg_iov = &io; + rtnl_reply.msg_iovlen = 1; + rtnl_reply.msg_name = &kernel; + rtnl_reply.msg_namelen = sizeof(kernel); + + len = recvmsg(sock, &rtnl_reply, 0); + + if (len == 0) { + printf ("Lectura de eventos regresó 0\n"); + return FALSE; + } else if (len < 0) { + perror ("Error en recvmsg\n"); + return TRUE; + } + + msg_ptr = (struct nlmsghdr *) reply; + + for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { + printf ("Msg type: %i\n", msg_ptr->nlmsg_type); + if (msg_ptr->nlmsg_type == nl80211_id) { + ghdr = NLMSG_DATA (msg_ptr); + + printf ("Generic command: %i\n", ghdr->cmd); + if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) { + _wireless_parse_scan (handle, msg_ptr); + } + } + } + + return TRUE; +} + +void wireless_init (NetworkInadorHandle *handle) { + struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ + struct iovec io; + struct genlmsghdr *ghdr; + struct rtattr *rta; + struct sockaddr_nl kernel; + char buffer[8192]; /* a large buffer */ + int len; + GIOChannel *channel; + + /* Para la respuesta */ + struct nlmsgerr *l_err; + struct nlmsghdr *msg_ptr; /* pointer to current part */ + + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Crear un netlink de la familia generica para nuestras peticiones */ + handle->netlink_sock_request_generic = _wireless_create_generic_netlink_socket (); + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size); + + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + msg_ptr = (struct nlmsghdr *) buffer; + msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr)); + msg_ptr->nlmsg_type = GENL_ID_CTRL; + msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + msg_ptr->nlmsg_seq = global_nl_seq++; + msg_ptr->nlmsg_pid = local_nl.nl_pid; + + ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr); + ghdr->cmd = CTRL_CMD_GETFAMILY; + ghdr->version = 1; + + len = strlen (NL80211_GENL_NAME) + 1; + rta_addattr_l (msg_ptr, sizeof (buffer), CTRL_ATTR_FAMILY_NAME, NL80211_GENL_NAME, len); + + io.iov_base = buffer; + io.iov_len = msg_ptr->nlmsg_len; + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof (kernel); + + /*len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0); + msg_ptr = (struct nlmsghdr *) buffer; + _wireless_parse_family_id (msg_ptr); + + len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0); + msg_ptr = (struct nlmsghdr *) buffer;*/ + while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */ + msg_ptr = (struct nlmsghdr *) buffer; + if (msg_ptr->nlmsg_type == NLMSG_DONE) break; + if (msg_ptr->nlmsg_type == NLMSG_ERROR) break; + + if (msg_ptr->nlmsg_type == GENL_ID_CTRL) { + nl80211_id = _wireless_parse_family_id (msg_ptr); + } + } + + /* Generar otro socket netlink generic para eventos */ + int sock_for_wireless_events; + int group; + + sock_for_wireless_events = _wireless_create_generic_netlink_socket (); + + group = scan_multicast_group_id; + setsockopt (sock_for_wireless_events, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof (group)); + + /* Instalar un GIOChannel */ + channel = g_io_channel_unix_new (sock_for_wireless_events); + + g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _wireless_events_handle_read, handle); +} + +//void test_wireless +void wireless_check_is_wireless_interface (NetworkInadorHandle *handle, Interface *iface) { + struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ + struct iovec io; + struct genlmsghdr *ghdr; + struct rtattr *rta; + struct sockaddr_nl kernel; + char buffer[8192]; /* a large buffer */ + int len; + + /* Para la respuesta */ + struct nlmsgerr *l_err; + struct nlmsghdr *msg_ptr; /* pointer to current part */ + + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size); + + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + msg_ptr = (struct nlmsghdr *) buffer; + msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr)); + msg_ptr->nlmsg_type = nl80211_id; + msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + msg_ptr->nlmsg_seq = global_nl_seq++; + msg_ptr->nlmsg_pid = local_nl.nl_pid; + + ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr); + ghdr->cmd = NL80211_CMD_GET_INTERFACE; + ghdr->version = 0; + + rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->index, 4); + + io.iov_base = buffer; + io.iov_len = msg_ptr->nlmsg_len; + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof (kernel); + + while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */ + msg_ptr = (struct nlmsghdr *) buffer; + if (msg_ptr->nlmsg_type == NLMSG_DONE) break; + if (msg_ptr->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *l_err; + l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr); + break; + } + + if (msg_ptr->nlmsg_type == nl80211_id) { + _wireless_parse_message_get_iface (msg_ptr, iface); + } + } +} + diff --git a/src/wireless.h b/src/wireless.h new file mode 100644 index 0000000..d1b891a --- /dev/null +++ b/src/wireless.h @@ -0,0 +1,32 @@ +/* + * wireless.h + * This file is part of Network-inador + * + * Copyright (C) 2018 - Félix Arreola Rodríguez + * + * Network-inador is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Network-inador is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Network-inador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __WIRELESS_H__ +#define __WIRELESS_H__ + +#include "network-inador.h" + +void wireless_init (NetworkInadorHandle *handle); +void wireless_check_is_wireless_interface (NetworkInadorHandle *handle, Interface *iface); +void wireless_do_get_scan (NetworkInadorHandle *handle, int ifindex); + +#endif