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> |
| 21 | #include <malloc.h> |
| 22 | #include <sys/time.h> |
| 23 | #include <sys/socket.h> |
| 24 | #include "netlink-types.h" |
| 25 | |
| 26 | /* Join group */ |
| 27 | int nl_socket_add_membership(struct nl_sock *sk, int group) |
| 28 | { |
| 29 | return setsockopt(sk->s_fd, SOL_NETLINK, |
| 30 | NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); |
| 31 | } |
| 32 | |
| 33 | /* Allocate new netlink socket. */ |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 34 | static struct nl_sock *_nl_socket_alloc(void) |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 35 | { |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 36 | struct nl_sock *sk; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 37 | struct timeval tv; |
| 38 | struct nl_cb *cb; |
| 39 | |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 40 | sk = (struct nl_sock *) malloc(sizeof(struct nl_sock)); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 41 | if (!sk) |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 42 | return NULL; |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 43 | memset(sk, 0, sizeof(*sk)); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 44 | |
| 45 | /* Get current time */ |
| 46 | |
| 47 | if (gettimeofday(&tv, NULL)) |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 48 | goto fail; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 49 | else |
| 50 | sk->s_seq_next = (int) tv.tv_sec; |
| 51 | |
| 52 | /* Create local socket */ |
| 53 | sk->s_local.nl_family = AF_NETLINK; |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 54 | sk->s_local.nl_pid = 0; /* Kernel fills in pid */ |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 55 | sk->s_local.nl_groups = 0; /* No groups */ |
| 56 | |
| 57 | /* Create peer socket */ |
| 58 | sk->s_peer.nl_family = AF_NETLINK; |
| 59 | sk->s_peer.nl_pid = 0; /* Kernel */ |
| 60 | sk->s_peer.nl_groups = 0; /* No groups */ |
| 61 | |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 62 | return sk; |
| 63 | fail: |
| 64 | free(sk); |
| 65 | return NULL; |
| 66 | } |
| 67 | |
| 68 | /* Allocate new netlink socket. */ |
| 69 | struct nl_sock *nl_socket_alloc(void) |
| 70 | { |
| 71 | struct nl_sock *sk = _nl_socket_alloc(); |
| 72 | struct nl_cb *cb; |
| 73 | |
| 74 | if (!sk) |
| 75 | return NULL; |
| 76 | |
| 77 | cb = nl_cb_alloc(NL_CB_DEFAULT); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 78 | if (!cb) |
| 79 | goto cb_fail; |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 80 | sk->s_cb = cb; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 81 | return sk; |
| 82 | cb_fail: |
| 83 | free(sk); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 84 | return NULL; |
| 85 | } |
| 86 | |
| 87 | /* Allocate new socket with custom callbacks. */ |
| 88 | struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) |
| 89 | { |
Dmitry Shmidt | d99fe5e | 2011-11-01 15:24:02 -0700 | [diff] [blame] | 90 | struct nl_sock *sk = _nl_socket_alloc(); |
| 91 | |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 92 | if (!sk) |
Frank Maker | c28b79a | 2011-07-06 22:03:13 -0700 | [diff] [blame] | 93 | return NULL; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 94 | |
| 95 | sk->s_cb = cb; |
| 96 | nl_cb_get(cb); |
| 97 | |
| 98 | return sk; |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | /* Free a netlink socket. */ |
| 102 | void nl_socket_free(struct nl_sock *sk) |
| 103 | { |
| 104 | nl_cb_put(sk->s_cb); |
Frank Maker | 69bc179 | 2011-08-01 19:51:49 -0700 | [diff] [blame] | 105 | close(sk->s_fd); |
Frank Maker | ed6b39c | 2011-05-23 21:14:58 -0700 | [diff] [blame] | 106 | free(sk); |
| 107 | } |
| 108 | |
| 109 | /* Sets socket buffer size of netlink socket */ |
| 110 | int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) |
| 111 | { |
| 112 | if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \ |
| 113 | &rxbuf, (socklen_t) sizeof(rxbuf))) |
| 114 | goto error; |
| 115 | |
| 116 | if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \ |
| 117 | &txbuf, (socklen_t) sizeof(txbuf))) |
| 118 | goto error; |
| 119 | |
| 120 | return 0; |
| 121 | error: |
| 122 | return -errno; |
| 123 | |
| 124 | } |
| 125 | |
| 126 | int nl_socket_get_fd(struct nl_sock *sk) |
| 127 | { |
| 128 | return sk->s_fd; |
| 129 | } |
Dmitry Shmidt | de92239 | 2012-07-10 10:47:48 -0700 | [diff] [blame] | 130 | |
| 131 | void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb) |
| 132 | { |
| 133 | nl_cb_put(sk->s_cb); |
| 134 | sk->s_cb = cb; |
| 135 | nl_cb_get(cb); |
| 136 | } |
| 137 | |
| 138 | struct nl_cb *nl_socket_get_cb(struct nl_sock *sk) |
| 139 | { |
| 140 | return nl_cb_get(sk->s_cb); |
| 141 | } |