Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /* NOTICE: This is a clean room re-implementation of libnl */ |
| 18 | |
| 19 | #include <errno.h> |
| 20 | #include <unistd.h> |
Dmitry Shmidt | e2f32d0 | 2013-10-28 17:55:16 -0700 | [diff] [blame] | 21 | #include <fcntl.h> |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 22 | #include <malloc.h> |
| 23 | #include <sys/time.h> |
| 24 | #include <sys/socket.h> |
| 25 | #include "netlink-types.h" |
| 26 | |
| 27 | /* Join group */ |
| 28 | int nl_socket_add_membership(struct nl_sock *sk, int group) |
| 29 | { |
| 30 | return setsockopt(sk->s_fd, SOL_NETLINK, |
| 31 | NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); |
| 32 | } |
| 33 | |
| 34 | /* Allocate new netlink socket. */ |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 35 | static struct nl_sock *_nl_socket_alloc(void) |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 36 | { |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 37 | struct nl_sock *sk; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 38 | struct timeval tv; |
| 39 | struct nl_cb *cb; |
| 40 | |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 41 | sk = (struct nl_sock *) malloc(sizeof(struct nl_sock)); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 42 | if (!sk) |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 43 | return NULL; |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 44 | memset(sk, 0, sizeof(*sk)); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 45 | |
| 46 | /* Get current time */ |
| 47 | |
| 48 | if (gettimeofday(&tv, NULL)) |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 49 | goto fail; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 50 | else |
| 51 | sk->s_seq_next = (int) tv.tv_sec; |
| 52 | |
| 53 | /* Create local socket */ |
| 54 | sk->s_local.nl_family = AF_NETLINK; |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 55 | sk->s_local.nl_pid = 0; /* Kernel fills in pid */ |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 56 | sk->s_local.nl_groups = 0; /* No groups */ |
| 57 | |
| 58 | /* Create peer socket */ |
| 59 | sk->s_peer.nl_family = AF_NETLINK; |
| 60 | sk->s_peer.nl_pid = 0; /* Kernel */ |
| 61 | sk->s_peer.nl_groups = 0; /* No groups */ |
| 62 | |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 63 | return sk; |
| 64 | fail: |
| 65 | free(sk); |
| 66 | return NULL; |
| 67 | } |
| 68 | |
| 69 | /* Allocate new netlink socket. */ |
| 70 | struct nl_sock *nl_socket_alloc(void) |
| 71 | { |
| 72 | struct nl_sock *sk = _nl_socket_alloc(); |
| 73 | struct nl_cb *cb; |
| 74 | |
| 75 | if (!sk) |
| 76 | return NULL; |
| 77 | |
| 78 | cb = nl_cb_alloc(NL_CB_DEFAULT); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 79 | if (!cb) |
| 80 | goto cb_fail; |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 81 | sk->s_cb = cb; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 82 | return sk; |
| 83 | cb_fail: |
| 84 | free(sk); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 85 | return NULL; |
| 86 | } |
| 87 | |
| 88 | /* Allocate new socket with custom callbacks. */ |
| 89 | struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) |
| 90 | { |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 91 | struct nl_sock *sk = _nl_socket_alloc(); |
| 92 | |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 93 | if (!sk) |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 94 | return NULL; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 95 | |
| 96 | sk->s_cb = cb; |
| 97 | nl_cb_get(cb); |
| 98 | |
| 99 | return sk; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | /* Free a netlink socket. */ |
| 103 | void nl_socket_free(struct nl_sock *sk) |
| 104 | { |
| 105 | nl_cb_put(sk->s_cb); |
Frank Maker | 69bc179 | 2011-08-01 19:51:49 -0700 | [diff] [blame] | 106 | close(sk->s_fd); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 107 | free(sk); |
| 108 | } |
| 109 | |
| 110 | /* Sets socket buffer size of netlink socket */ |
| 111 | int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) |
| 112 | { |
| 113 | if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \ |
| 114 | &rxbuf, (socklen_t) sizeof(rxbuf))) |
| 115 | goto error; |
| 116 | |
| 117 | if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \ |
| 118 | &txbuf, (socklen_t) sizeof(txbuf))) |
| 119 | goto error; |
| 120 | |
| 121 | return 0; |
| 122 | error: |
| 123 | return -errno; |
| 124 | |
| 125 | } |
| 126 | |
| 127 | int nl_socket_get_fd(struct nl_sock *sk) |
| 128 | { |
| 129 | return sk->s_fd; |
| 130 | } |
Dmitry Shmidt | de92239 | 2012-07-10 10:47:48 -0700 | [diff] [blame] | 131 | |
| 132 | void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb) |
| 133 | { |
| 134 | nl_cb_put(sk->s_cb); |
| 135 | sk->s_cb = cb; |
| 136 | nl_cb_get(cb); |
| 137 | } |
| 138 | |
| 139 | struct nl_cb *nl_socket_get_cb(struct nl_sock *sk) |
| 140 | { |
| 141 | return nl_cb_get(sk->s_cb); |
| 142 | } |
Dmitry Shmidt | e2f32d0 | 2013-10-28 17:55:16 -0700 | [diff] [blame] | 143 | |
| 144 | int nl_socket_set_nonblocking(struct nl_sock *sk) |
| 145 | { |
| 146 | if (sk->s_fd == -1) |
| 147 | return -NLE_BAD_SOCK; |
| 148 | |
| 149 | if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) |
| 150 | return -errno; |
| 151 | |
| 152 | return 0; |
| 153 | } |