| /* |
| * 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); |
| } |