예제 #1
0
/**
 * 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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
파일: nl.c 프로젝트: rinrinne/libnl
/**
 * 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;
}
예제 #5
0
/* 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;
}
예제 #6
0
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;
}
예제 #7
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;
}
예제 #8
0
/**
 * 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;
}
예제 #9
0
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;
}