142 lines
2.9 KiB
C
142 lines
2.9 KiB
C
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* NOTICE: This is a clean room re-implementation of libnl */
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <malloc.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include "netlink-types.h"
|
|
|
|
/* Join group */
|
|
int nl_socket_add_membership(struct nl_sock *sk, int group)
|
|
{
|
|
return setsockopt(sk->s_fd, SOL_NETLINK,
|
|
NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
|
|
}
|
|
|
|
/* Allocate new netlink socket. */
|
|
static struct nl_sock *_nl_socket_alloc(void)
|
|
{
|
|
struct nl_sock *sk;
|
|
struct timeval tv;
|
|
struct nl_cb *cb;
|
|
|
|
sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
|
|
if (!sk)
|
|
return NULL;
|
|
memset(sk, 0, sizeof(*sk));
|
|
|
|
/* Get current time */
|
|
|
|
if (gettimeofday(&tv, NULL))
|
|
goto fail;
|
|
else
|
|
sk->s_seq_next = (int) tv.tv_sec;
|
|
|
|
/* Create local socket */
|
|
sk->s_local.nl_family = AF_NETLINK;
|
|
sk->s_local.nl_pid = 0; /* Kernel fills in pid */
|
|
sk->s_local.nl_groups = 0; /* No groups */
|
|
|
|
/* Create peer socket */
|
|
sk->s_peer.nl_family = AF_NETLINK;
|
|
sk->s_peer.nl_pid = 0; /* Kernel */
|
|
sk->s_peer.nl_groups = 0; /* No groups */
|
|
|
|
return sk;
|
|
fail:
|
|
free(sk);
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate new netlink socket. */
|
|
struct nl_sock *nl_socket_alloc(void)
|
|
{
|
|
struct nl_sock *sk = _nl_socket_alloc();
|
|
struct nl_cb *cb;
|
|
|
|
if (!sk)
|
|
return NULL;
|
|
|
|
cb = nl_cb_alloc(NL_CB_DEFAULT);
|
|
if (!cb)
|
|
goto cb_fail;
|
|
sk->s_cb = cb;
|
|
return sk;
|
|
cb_fail:
|
|
free(sk);
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate new socket with custom callbacks. */
|
|
struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
|
|
{
|
|
struct nl_sock *sk = _nl_socket_alloc();
|
|
|
|
if (!sk)
|
|
return NULL;
|
|
|
|
sk->s_cb = cb;
|
|
nl_cb_get(cb);
|
|
|
|
return sk;
|
|
}
|
|
|
|
/* Free a netlink socket. */
|
|
void nl_socket_free(struct nl_sock *sk)
|
|
{
|
|
nl_cb_put(sk->s_cb);
|
|
close(sk->s_fd);
|
|
free(sk);
|
|
}
|
|
|
|
/* Sets socket buffer size of netlink socket */
|
|
int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
|
|
{
|
|
if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
|
|
&rxbuf, (socklen_t) sizeof(rxbuf)))
|
|
goto error;
|
|
|
|
if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
|
|
&txbuf, (socklen_t) sizeof(txbuf)))
|
|
goto error;
|
|
|
|
return 0;
|
|
error:
|
|
return -errno;
|
|
|
|
}
|
|
|
|
int nl_socket_get_fd(struct nl_sock *sk)
|
|
{
|
|
return sk->s_fd;
|
|
}
|
|
|
|
void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
|
|
{
|
|
nl_cb_put(sk->s_cb);
|
|
sk->s_cb = cb;
|
|
nl_cb_get(cb);
|
|
}
|
|
|
|
struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
|
|
{
|
|
return nl_cb_get(sk->s_cb);
|
|
}
|