/** * Create file descriptor and bind socket. * @arg sk Netlink socket (required) * @arg protocol Netlink protocol to use (required) * * Creates a new Netlink socket using `socket()` and binds the socket to the * protocol and local port specified in the `sk` socket object. Fails if * the socket is already connected. * * @note If available, the `close-on-exec` (`SOCK_CLOEXEC`) feature is enabled * automatically on the new file descriptor. This causes the socket to * be closed automatically if any of the `exec` family functions succeed. * This is essential for multi threaded programs. * * @see nl_socket_alloc() * @see nl_close() * * @return 0 on success or a negative error code. * * @retval -NLE_BAD_SOCK Socket is already connected */ int nl_connect(struct nl_sock *sk, int protocol) { int err, flags = 0; socklen_t addrlen; #ifdef SOCK_CLOEXEC flags |= SOCK_CLOEXEC; #endif if (sk->s_fd != -1) return -NLE_BAD_SOCK; sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol); if (sk->s_fd < 0) { err = -nl_syserr2nlerr(errno); goto errout; } if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) { err = nl_socket_set_buffer_size(sk, 0, 0); if (err < 0) goto errout; } err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof(sk->s_local)); if (err < 0) { err = -nl_syserr2nlerr(errno); goto errout; } addrlen = sizeof(sk->s_local); err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, &addrlen); if (err < 0) { err = -nl_syserr2nlerr(errno); goto errout; } if (addrlen != sizeof(sk->s_local)) { err = -NLE_NOADDR; goto errout; } if (sk->s_local.nl_family != AF_NETLINK) { err = -NLE_AF_NOSUPPORT; goto errout; } sk->s_proto = protocol; return 0; errout: if (sk->s_fd != -1) { close(sk->s_fd); sk->s_fd = -1; } return err; }
static int nl80211_init(struct nl80211_state *state) { int err; state->nl_sock = nl_socket_alloc(); if (!state->nl_sock) { fprintf(stderr, "Failed to allocate netlink socket.\n"); return -ENOMEM; } nl_socket_set_buffer_size(state->nl_sock, 8192, 8192); if (genl_connect(state->nl_sock)) { fprintf(stderr, "Failed to connect to generic netlink.\n"); err = -ENOLINK; goto out_handle_destroy; } state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211"); if (state->nl80211_id < 0) { fprintf(stderr, "nl80211 not found.\n"); err = -ENOENT; goto out_handle_destroy; } return 0; out_handle_destroy: nl_socket_free(state->nl_sock); return err; }
static wifi_error wifi_init_user_sock(hal_info *info) { struct nl_sock *user_sock = wifi_create_nl_socket(WIFI_HAL_USER_SOCK_PORT, NETLINK_USERSOCK); if (user_sock == NULL) { ALOGE("Could not create diag sock"); return WIFI_ERROR_UNKNOWN; } /* Set the socket buffer size */ if (nl_socket_set_buffer_size(user_sock, (256*1024), 0) < 0) { ALOGE("Could not set size for user_sock: %s", strerror(errno)); /* continue anyway with the default (smaller) buffer */ } else { ALOGV("nl_socket_set_buffer_size successful for user_sock"); } struct nl_cb *cb = nl_socket_get_cb(user_sock); if (cb == NULL) { ALOGE("Could not get cb"); return WIFI_ERROR_UNKNOWN; } info->user_sock_arg = 1; nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->user_sock_arg); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->user_sock_arg); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->user_sock_arg); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, user_sock_message_handler, info); nl_cb_put(cb); int ret = nl_socket_add_membership(user_sock, 1); if (ret < 0) { ALOGE("Could not add membership"); return WIFI_ERROR_UNKNOWN; } info->user_sock = user_sock; ALOGV("Initiialized diag sock successfully"); return WIFI_SUCCESS; }
/** * Create file descriptor and bind socket. * @arg sk Netlink socket (required) * @arg protocol Netlink protocol to use (required) * * Creates a new Netlink socket using `socket()` and binds the socket to the * protocol and local port specified in the `sk` socket object. Fails if * the socket is already connected. * * @note If available, the `close-on-exec` (`SOCK_CLOEXEC`) feature is enabled * automatically on the new file descriptor. This causes the socket to * be closed automatically if any of the `exec` family functions succeed. * This is essential for multi threaded programs. * * @note The local port (`nl_socket_get_local_port()`) is unspecified after * creating a new socket. It only gets determined when accessing the * port the first time or during `nl_connect()`. When nl_connect() * fails during `bind()` due to `ADDRINUSE`, it will retry with * different ports if the port is unspecified. Unless you want to enforce * the use of a specific local port, don't access the local port (or * reset it to `unspecified` by calling `nl_socket_set_local_port(sk, 0)`). * This capability is indicated by * `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`. * * @note nl_connect() creates and sets the file descriptor. You can setup the file * descriptor yourself by creating and binding it, and then calling * nl_socket_set_fd(). The result will be the same. * * @see nl_socket_alloc() * @see nl_close() * @see nl_socket_set_fd() * * @return 0 on success or a negative error code. * * @retval -NLE_BAD_SOCK Socket is already connected */ int nl_connect(struct nl_sock *sk, int protocol) { int err, flags = 0; int errsv; socklen_t addrlen; struct sockaddr_nl local = { 0 }; char buf[64]; #ifdef SOCK_CLOEXEC flags |= SOCK_CLOEXEC; #endif if (sk->s_fd != -1) return -NLE_BAD_SOCK; sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol); if (sk->s_fd < 0) { errsv = errno; NL_DBG(4, "nl_connect(%p): socket() failed with %d (%s)\n", sk, errsv, strerror_r(errsv, buf, sizeof(buf))); err = -nl_syserr2nlerr(errsv); goto errout; } err = nl_socket_set_buffer_size(sk, 0, 0); if (err < 0) goto errout; if (_nl_socket_is_local_port_unspecified (sk)) { uint32_t port; uint32_t used_ports[32] = { 0 }; while (1) { port = _nl_socket_generate_local_port_no_release(sk); if (port == UINT32_MAX) { NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk); _nl_socket_used_ports_release_all(used_ports); err = -NLE_EXIST; goto errout; } err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof(sk->s_local)); if (err == 0) break; errsv = errno; if (errsv == EADDRINUSE) { NL_DBG(4, "nl_connect(%p): local port %u already in use. Retry.\n", sk, (unsigned) port); _nl_socket_used_ports_set(used_ports, port); } else { NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d (%s)\n", sk, (unsigned) port, errsv, strerror_r(errsv, buf, sizeof(buf))); _nl_socket_used_ports_release_all(used_ports); err = -nl_syserr2nlerr(errsv); goto errout; } } _nl_socket_used_ports_release_all(used_ports); } else { err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof(sk->s_local)); if (err != 0) { errsv = errno; NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n", sk, errsv, strerror_r(errsv, buf, sizeof(buf))); err = -nl_syserr2nlerr(errsv); goto errout; } } addrlen = sizeof(local); err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen); if (err < 0) { NL_DBG(4, "nl_connect(%p): getsockname() failed with %d (%s)\n", sk, errno, strerror_r(errno, buf, sizeof(buf))); err = -nl_syserr2nlerr(errno); goto errout; } if (addrlen != sizeof(local)) { err = -NLE_NOADDR; goto errout; } if (local.nl_family != AF_NETLINK) { err = -NLE_AF_NOSUPPORT; goto errout; } if (sk->s_local.nl_pid != local.nl_pid) { /* strange, the port id is not as expected. Set the local * port id to release a possibly generated port and un-own * it. */ nl_socket_set_local_port (sk, local.nl_pid); } sk->s_local = local; sk->s_proto = protocol; return 0; errout: if (sk->s_fd != -1) { close(sk->s_fd); sk->s_fd = -1; } return err; }
/* Create a socket to netlink interface_t */ static int netlink_socket(nl_handle_t *nl, int flags, int group, ...) { int ret; va_list gp; memset(nl, 0, sizeof (*nl)); #ifdef _HAVE_LIBNL3_ /* We need to keep libnl3 in step with our netlink socket creation. */ nl->sk = nl_socket_alloc(); if ( nl->sk == NULL ) { log_message(LOG_INFO, "Netlink: Cannot allocate netlink socket" ); return -1; } ret = nl_connect(nl->sk, NETLINK_ROUTE); if (ret != 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%d)", ret); return -1; } /* Unfortunately we can't call nl_socket_add_memberships() with variadic arguments * from a variadic argument list passed to us */ va_start(gp, group); while (group != 0) { if (group < 0) { va_end(gp); return -1; } if ((ret = nl_socket_add_membership(nl->sk, group))) { log_message(LOG_INFO, "Netlink: Cannot add socket membership 0x%x : (%d)", group, ret); return -1; } group = va_arg(gp,int); } va_end(gp); if (flags & SOCK_NONBLOCK) { if ((ret = nl_socket_set_nonblocking(nl->sk))) { log_message(LOG_INFO, "Netlink: Cannot set netlink socket non-blocking : (%d)", ret); return -1; } } if ((ret = nl_socket_set_buffer_size(nl->sk, IF_DEFAULT_BUFSIZE, 0))) { log_message(LOG_INFO, "Netlink: Cannot set netlink buffer size : (%d)", ret); return -1; } nl->nl_pid = nl_socket_get_local_port(nl->sk); nl->fd = nl_socket_get_fd(nl->sk); /* Set CLOEXEC */ fcntl(nl->fd, F_SETFD, fcntl(nl->fd, F_GETFD) | FD_CLOEXEC); #else socklen_t addr_len; struct sockaddr_nl snl; #if !HAVE_DECL_SOCK_NONBLOCK int sock_flags = flags; flags &= ~SOCK_NONBLOCK; #endif nl->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | flags, NETLINK_ROUTE); if (nl->fd < 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%s)", strerror(errno)); return -1; } #if !HAVE_DECL_SOCK_NONBLOCK if ((sock_flags & SOCK_NONBLOCK) && set_sock_flags(nl->fd, F_SETFL, O_NONBLOCK)) return -1; #endif memset(&snl, 0, sizeof (snl)); snl.nl_family = AF_NETLINK; ret = bind(nl->fd, (struct sockaddr *) &snl, sizeof (snl)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot bind netlink socket : (%s)", strerror(errno)); close(nl->fd); return -1; } /* Join the requested groups */ va_start(gp, group); while (group != 0) { if (group < 0) { va_end(gp); return -1; } ret = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot add membership on netlink socket : (%s)", strerror(errno)); va_end(gp); return -1; } group = va_arg(gp,int); } va_end(gp); addr_len = sizeof (snl); ret = getsockname(nl->fd, (struct sockaddr *) &snl, &addr_len); if (ret < 0 || addr_len != sizeof (snl)) { log_message(LOG_INFO, "Netlink: Cannot getsockname : (%s)", strerror(errno)); close(nl->fd); return -1; } if (snl.nl_family != AF_NETLINK) { log_message(LOG_INFO, "Netlink: Wrong address family %d", snl.nl_family); close(nl->fd); return -1; } /* Save the port id for checking message source later */ nl->nl_pid = snl.nl_pid; /* Set default rcvbuf size */ if_setsockopt_rcvbuf(&nl->fd, IF_DEFAULT_BUFSIZE); #endif nl->seq = (uint32_t)time(NULL); if (nl->fd < 0) return -1; return ret; }
static void obj_input(struct nl_object *obj, void *arg) { struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj; struct nl_dump_params dp = { .dp_type = NL_DUMP_STATS, .dp_fd = stdout, .dp_dump_msgtype = 1, }; nfnl_queue_msg_set_verdict(msg, NF_ACCEPT); nl_object_dump(obj, &dp); nfnl_queue_msg_send_verdict(nf_sock, msg); } static int event_input(struct nl_msg *msg, void *arg) { if (nl_msg_parse(msg, &obj_input, NULL) < 0) fprintf(stderr, "<<EVENT>> Unknown message type\n"); /* Exit nl_recvmsgs_def() and return to the main select() */ return NL_STOP; } int main(int argc, char *argv[]) { struct nl_sock *rt_sock; struct nl_cache *link_cache; struct nfnl_queue *queue; enum nfnl_queue_copy_mode copy_mode; uint32_t copy_range; int err = 1; int family; nf_sock = nfnl_queue_socket_alloc(); if (nf_sock == NULL) nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket"); nl_socket_disable_seq_check(nf_sock); nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) { printf("Usage: nf-queue family group [ copy_mode ] " "[ copy_range ]\n"); printf("family: [ inet | inet6 | ... ] \n"); printf("group: the --queue-num arg that you gave to iptables\n"); printf("copy_mode: [ none | meta | packet ] \n"); return 2; } nl_cli_connect(nf_sock, NETLINK_NETFILTER); if ((family = nl_str2af(argv[1])) == AF_UNSPEC) nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\"", argv[1]); nfnl_queue_pf_unbind(nf_sock, family); if ((err = nfnl_queue_pf_bind(nf_sock, family)) < 0) nl_cli_fatal(err, "Unable to bind logger: %s", nl_geterror(err)); queue = alloc_queue(); nfnl_queue_set_group(queue, atoi(argv[2])); copy_mode = NFNL_QUEUE_COPY_PACKET; if (argc > 3) { copy_mode = nfnl_queue_str2copy_mode(argv[3]); if (copy_mode < 0) nl_cli_fatal(copy_mode, "Unable to parse copy mode \"%s\": %s", argv[3], nl_geterror(copy_mode)); } nfnl_queue_set_copy_mode(queue, copy_mode); copy_range = 0xFFFF; if (argc > 4) copy_range = atoi(argv[4]); nfnl_queue_set_copy_range(queue, copy_range); if ((err = nfnl_queue_create(nf_sock, queue)) < 0) nl_cli_fatal(err, "Unable to bind queue: %s", nl_geterror(err)); rt_sock = nl_cli_alloc_socket(); nl_cli_connect(rt_sock, NETLINK_ROUTE); link_cache = nl_cli_link_alloc_cache(rt_sock); nl_socket_set_buffer_size(nf_sock, 1024*127, 1024*127); while (1) { fd_set rfds; int nffd, rtfd, maxfd, retval; FD_ZERO(&rfds); maxfd = nffd = nl_socket_get_fd(nf_sock); FD_SET(nffd, &rfds); rtfd = nl_socket_get_fd(rt_sock); FD_SET(rtfd, &rfds); if (maxfd < rtfd) maxfd = rtfd; /* wait for an incoming message on the netlink socket */ retval = select(maxfd+1, &rfds, NULL, NULL, NULL); if (retval) { if (FD_ISSET(nffd, &rfds)) nl_recvmsgs_default(nf_sock); if (FD_ISSET(rtfd, &rfds)) nl_recvmsgs_default(rt_sock); } } return 0; }
wifi_error wifi_initialize(wifi_handle *handle) { int err = 0; wifi_error ret = WIFI_SUCCESS; wifi_interface_handle iface_handle; struct nl_sock *cmd_sock = NULL; struct nl_sock *event_sock = NULL; struct nl_cb *cb = NULL; int status = 0; ALOGI("Initializing wifi"); hal_info *info = (hal_info *)malloc(sizeof(hal_info)); if (info == NULL) { ALOGE("Could not allocate hal_info"); return WIFI_ERROR_OUT_OF_MEMORY; } memset(info, 0, sizeof(*info)); cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT, NETLINK_GENERIC); if (cmd_sock == NULL) { ALOGE("Failed to create command socket port"); ret = WIFI_ERROR_UNKNOWN; goto unload; } /* Set the socket buffer size */ if (nl_socket_set_buffer_size(cmd_sock, (256*1024), 0) < 0) { ALOGE("Could not set nl_socket RX buffer size for cmd_sock: %s", strerror(errno)); /* continue anyway with the default (smaller) buffer */ } event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT, NETLINK_GENERIC); if (event_sock == NULL) { ALOGE("Failed to create event socket port"); ret = WIFI_ERROR_UNKNOWN; goto unload; } /* Set the socket buffer size */ if (nl_socket_set_buffer_size(event_sock, (256*1024), 0) < 0) { ALOGE("Could not set nl_socket RX buffer size for event_sock: %s", strerror(errno)); /* continue anyway with the default (smaller) buffer */ } cb = nl_socket_get_cb(event_sock); if (cb == NULL) { ALOGE("Failed to get NL control block for event socket port"); ret = WIFI_ERROR_UNKNOWN; goto unload; } err = 1; nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info); nl_cb_put(cb); info->cmd_sock = cmd_sock; info->event_sock = event_sock; info->clean_up = false; info->in_event_loop = false; info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE); if (info->event_cb == NULL) { ALOGE("Could not allocate event_cb"); ret = WIFI_ERROR_OUT_OF_MEMORY; goto unload; } info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE; info->num_event_cb = 0; info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE); if (info->cmd == NULL) { ALOGE("Could not allocate cmd info"); ret = WIFI_ERROR_OUT_OF_MEMORY; goto unload; } info->alloc_cmd = DEFAULT_CMD_SIZE; info->num_cmd = 0; info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211"); if (info->nl80211_family_id < 0) { ALOGE("Could not resolve nl80211 familty id"); ret = WIFI_ERROR_UNKNOWN; goto unload; } pthread_mutex_init(&info->cb_lock, NULL); pthread_mutex_init(&info->pkt_fate_stats_lock, NULL); *handle = (wifi_handle) info; wifi_add_membership(*handle, "scan"); wifi_add_membership(*handle, "mlme"); wifi_add_membership(*handle, "regulatory"); wifi_add_membership(*handle, "vendor"); info->cldctx = cld80211_init(); if (info->cldctx != NULL) { info->user_sock = info->cldctx->sock; ret = wifi_init_cld80211_sock_cb(info); if (ret != WIFI_SUCCESS) { ALOGE("Could not set cb for CLD80211 family"); goto cld80211_cleanup; } status = cld80211_add_mcast_group(info->cldctx, "host_logs"); if (status) { ALOGE("Failed to add mcast group host_logs :%d", status); goto cld80211_cleanup; } status = cld80211_add_mcast_group(info->cldctx, "fw_logs"); if (status) { ALOGE("Failed to add mcast group fw_logs :%d", status); goto cld80211_cleanup; } status = cld80211_add_mcast_group(info->cldctx, "per_pkt_stats"); if (status) { ALOGE("Failed to add mcast group per_pkt_stats :%d", status); goto cld80211_cleanup; } status = cld80211_add_mcast_group(info->cldctx, "diag_events"); if (status) { ALOGE("Failed to add mcast group diag_events :%d", status); goto cld80211_cleanup; } status = cld80211_add_mcast_group(info->cldctx, "fatal_events"); if (status) { ALOGE("Failed to add mcast group fatal_events :%d", status); goto cld80211_cleanup; } } else { ret = wifi_init_user_sock(info); if (ret != WIFI_SUCCESS) { ALOGE("Failed to alloc user socket"); goto unload; } } ret = wifi_init_interfaces(*handle); if (ret != WIFI_SUCCESS) { ALOGE("Failed to init interfaces"); goto unload; } if (info->num_interfaces == 0) { ALOGE("No interfaces found"); ret = WIFI_ERROR_UNINITIALIZED; goto unload; } iface_handle = wifi_get_iface_handle((info->interfaces[0])->handle, (info->interfaces[0])->name); if (iface_handle == NULL) { int i; for (i = 0; i < info->num_interfaces; i++) { free(info->interfaces[i]); } ALOGE("%s no iface with %s\n", __func__, info->interfaces[0]->name); goto unload; } ret = acquire_supported_features(iface_handle, &info->supported_feature_set); if (ret != WIFI_SUCCESS) { ALOGI("Failed to get supported feature set : %d", ret); //acquire_supported_features failure is acceptable condition as legacy //drivers might not support the required vendor command. So, do not //consider it as failure of wifi_initialize ret = WIFI_SUCCESS; } ret = get_firmware_bus_max_size_supported(iface_handle); if (ret != WIFI_SUCCESS) { ALOGE("Failed to get supported bus size, error : %d", ret); info->firmware_bus_max_size = 1520; } ret = wifi_logger_ring_buffers_init(info); if (ret != WIFI_SUCCESS) { ALOGE("Wifi Logger Ring Initialization Failed"); goto unload; } ret = wifi_get_capabilities(iface_handle); if (ret != WIFI_SUCCESS) ALOGE("Failed to get wifi Capabilities, error: %d", ret); info->pkt_stats = (struct pkt_stats_s *)malloc(sizeof(struct pkt_stats_s)); if (!info->pkt_stats) { ALOGE("%s: malloc Failed for size: %zu", __FUNCTION__, sizeof(struct pkt_stats_s)); ret = WIFI_ERROR_OUT_OF_MEMORY; goto unload; } info->rx_buf_size_allocated = MAX_RXMPDUS_PER_AMPDU * MAX_MSDUS_PER_MPDU * PKT_STATS_BUF_SIZE; info->rx_aggr_pkts = (wifi_ring_buffer_entry *)malloc(info->rx_buf_size_allocated); if (!info->rx_aggr_pkts) { ALOGE("%s: malloc Failed for size: %d", __FUNCTION__, info->rx_buf_size_allocated); ret = WIFI_ERROR_OUT_OF_MEMORY; info->rx_buf_size_allocated = 0; goto unload; } memset(info->rx_aggr_pkts, 0, info->rx_buf_size_allocated); info->exit_sockets[0] = -1; info->exit_sockets[1] = -1; if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->exit_sockets) == -1) { ALOGE("Failed to create exit socket pair"); ret = WIFI_ERROR_UNKNOWN; goto unload; } ALOGV("Initializing Gscan Event Handlers"); ret = initializeGscanHandlers(info); if (ret != WIFI_SUCCESS) { ALOGE("Initializing Gscan Event Handlers Failed"); goto unload; } ret = initializeRSSIMonitorHandler(info); if (ret != WIFI_SUCCESS) { ALOGE("Initializing RSSI Event Handler Failed"); goto unload; } ALOGV("Initialized Wifi HAL Successfully; vendor cmd = %d Supported" " features : %x", NL80211_CMD_VENDOR, info->supported_feature_set); cld80211_cleanup: if (status != 0 || ret != WIFI_SUCCESS) { ret = WIFI_ERROR_UNKNOWN; cld80211lib_cleanup(info); } unload: if (ret != WIFI_SUCCESS) { if (cmd_sock) nl_socket_free(cmd_sock); if (event_sock) nl_socket_free(event_sock); if (info) { if (info->cmd) free(info->cmd); if (info->event_cb) free(info->event_cb); if (info->cldctx) { cld80211lib_cleanup(info); } else if (info->user_sock) { nl_socket_free(info->user_sock); } if (info->pkt_stats) free(info->pkt_stats); if (info->rx_aggr_pkts) free(info->rx_aggr_pkts); cleanupGscanHandlers(info); cleanupRSSIMonitorHandler(info); free(info); } } return ret; }
/** * Setups generic netlink connection with the kernel module and retrieves assocaited family id * * @return 0 on success */ static int initialize_netlink_family(void) { struct nl_sock *sk; struct nl_msg* msg = NULL; struct nl_msg *ans_msg = NULL; struct nlmsghdr *nl_hdr; struct genlmsghdr* genl_hdr; struct nlattr *nla; int ret_val = 0; sk = nl_socket_alloc(); nl_socket_set_buffer_size(sk, 15000000, 15000000); //nl_handle_set_peer_pid(hndl, 0); //nl_set_passcred(hndl, 1); nl_socket_disable_seq_check(sk); if ( (ret_val=nl_connect(sk, NETLINK_GENERIC)) ) goto init_return; if ( (ret_val=prepare_request_message(sk, CTRL_CMD_GETFAMILY, GENL_ID_CTRL, &msg) ) != 0 ) { goto init_return; } ret_val = nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, "DIRECTORCHNL"); if (ret_val != 0) goto init_return; if ( (ret_val = send_request_message(sk, msg, 0) ) != 0 ) goto init_return; if ( (ret_val = read_message(sk, &ans_msg) ) != 0 ) goto init_return; genl_hdr = nl_msg_genlhdr(ans_msg); if (genl_hdr == NULL || genl_hdr->cmd != CTRL_CMD_NEWFAMILY) { ret_val = -EBADMSG; goto init_return; } nla = nlmsg_find_attr(nlmsg_hdr(ans_msg), sizeof(struct genlmsghdr), CTRL_ATTR_FAMILY_ID); if (nla == NULL) { ret_val = -EBADMSG; goto init_return; } state.gnl_fid = nla_get_u16(nla); if (state.gnl_fid == 0) { ret_val = -EBADMSG; goto init_return; } printf("Initialization netlink family OK\n"); state.sk = sk; return 0; init_return: nlmsg_free(ans_msg); if ( state.sk == NULL ) { nl_close(sk); nl_socket_free(sk); } return -EINVAL; }
static gboolean event_connection_setup (NMNetlinkMonitor *self, GError **error) { NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); GError *channel_error = NULL; GIOFlags channel_flags; int fd; int nle; g_return_val_if_fail (priv->io_channel == NULL, FALSE); /* Set up the event listener connection */ priv->nlh_event = nl_socket_alloc (); if (!priv->nlh_event) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE, _("unable to allocate netlink handle for monitoring link status: %s"), nl_geterror (ENOMEM)); goto error; } if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error)) goto error; nl_socket_disable_seq_check (priv->nlh_event); /* The default buffer size wasn't enough for the testsuites. It might just * as well happen with NetworkManager itself. For now let's hope 128KB is * good enough. */ nle = nl_socket_set_buffer_size (priv->nlh_event, 131072, 0); g_assert (!nle); /* Subscribe to the LINK group for internal carrier signals */ if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error)) goto error; fd = nl_socket_get_fd (priv->nlh_event); priv->io_channel = g_io_channel_unix_new (fd); g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error); /* Encoding is NULL, so no conversion error can possibly occur */ g_assert (channel_error == NULL); g_io_channel_set_close_on_unref (priv->io_channel, TRUE); channel_flags = g_io_channel_get_flags (priv->io_channel); channel_error = NULL; g_io_channel_set_flags (priv->io_channel, channel_flags | G_IO_FLAG_NONBLOCK, &channel_error); if (channel_error != NULL) { g_propagate_error (error, channel_error); goto error; } return TRUE; error: if (priv->io_channel) close_connection (self); if (priv->nlh_event) { nl_socket_free (priv->nlh_event); priv->nlh_event = NULL; } return FALSE; }