1 /* 2 * lib/socket.c Netlink Socket 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12 /** 13 * @ingroup core 14 * @defgroup socket Socket 15 * @{ 16 */ 17 18 #include <netlink-local.h> 19 #include <netlink/netlink.h> 20 #include <netlink/utils.h> 21 #include <netlink/handlers.h> 22 #include <netlink/msg.h> 23 #include <netlink/attr.h> 24 25 static uint32_t used_ports_map[32]; 26 27 static uint32_t generate_local_port(void) 28 { 29 int i, n; 30 uint32_t pid = getpid() & 0x3FFFFF; 31 32 for (i = 0; i < 32; i++) { 33 if (used_ports_map[i] == 0xFFFFFFFF) 34 continue; 35 36 for (n = 0; n < 32; n++) { 37 if (1UL & (used_ports_map[i] >> n)) 38 continue; 39 40 used_ports_map[i] |= (1UL << n); 41 n += (i * 32); 42 43 /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit 44 * to, i.e. 1024 unique ports per application. */ 45 return pid + (n << 22); 46 47 } 48 } 49 50 /* Out of sockets in our own PID namespace, what to do? FIXME */ 51 return UINT_MAX; 52 } 53 54 static void release_local_port(uint32_t port) 55 { 56 int nr; 57 58 if (port == UINT_MAX) 59 return; 60 61 nr = port >> 22; 62 used_ports_map[nr / 32] &= ~(1 << nr % 32); 63 } 64 65 /** 66 * @name Allocation 67 * @{ 68 */ 69 70 static struct nl_sock *__alloc_socket(struct nl_cb *cb) 71 { 72 struct nl_sock *sk; 73 74 sk = calloc(1, sizeof(*sk)); 75 if (!sk) 76 return NULL; 77 78 sk->s_fd = -1; 79 sk->s_cb = cb; 80 sk->s_local.nl_family = AF_NETLINK; 81 sk->s_peer.nl_family = AF_NETLINK; 82 sk->s_seq_expect = sk->s_seq_next = time(0); 83 sk->s_local.nl_pid = generate_local_port(); 84 if (sk->s_local.nl_pid == UINT_MAX) { 85 nl_socket_free(sk); 86 return NULL; 87 } 88 89 return sk; 90 } 91 92 /** 93 * Allocate new netlink socket 94 * 95 * @return Newly allocated netlink socket or NULL. 96 */ 97 struct nl_sock *nl_socket_alloc(void) 98 { 99 struct nl_cb *cb; 100 101 cb = nl_cb_alloc(NL_CB_DEFAULT); 102 if (!cb) 103 return NULL; 104 105 return __alloc_socket(cb); 106 } 107 108 /** 109 * Allocate new socket with custom callbacks 110 * @arg cb Callback handler 111 * 112 * The reference to the callback handler is taken into account 113 * automatically, it is released again upon calling nl_socket_free(). 114 * 115 *@return Newly allocted socket handle or NULL. 116 */ 117 struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) 118 { 119 if (cb == NULL) 120 BUG(); 121 122 return __alloc_socket(nl_cb_get(cb)); 123 } 124 125 /** 126 * Free a netlink socket. 127 * @arg sk Netlink socket. 128 */ 129 void nl_socket_free(struct nl_sock *sk) 130 { 131 if (!sk) 132 return; 133 134 if (sk->s_fd >= 0) 135 close(sk->s_fd); 136 137 if (!(sk->s_flags & NL_OWN_PORT)) 138 release_local_port(sk->s_local.nl_pid); 139 140 nl_cb_put(sk->s_cb); 141 free(sk); 142 } 143 144 /** @} */ 145 146 /** 147 * @name Sequence Numbers 148 * @{ 149 */ 150 151 static int noop_seq_check(struct nl_msg *msg, void *arg) 152 { 153 return NL_OK; 154 } 155 156 157 /** 158 * Disable sequence number checking. 159 * @arg sk Netlink socket. 160 * 161 * Disables checking of sequence numbers on the netlink socket This is 162 * required to allow messages to be processed which were not requested by 163 * a preceding request message, e.g. netlink events. 164 * 165 * @note This function modifies the NL_CB_SEQ_CHECK configuration in 166 * the callback handle associated with the socket. 167 */ 168 void nl_socket_disable_seq_check(struct nl_sock *sk) 169 { 170 nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK, 171 NL_CB_CUSTOM, noop_seq_check, NULL); 172 } 173 174 /** @} */ 175 176 /** 177 * Set local port of socket 178 * @arg sk Netlink socket. 179 * @arg port Local port identifier 180 * 181 * Assigns a local port identifier to the socket. If port is 0 182 * a unique port identifier will be generated automatically. 183 */ 184 void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port) 185 { 186 if (port == 0) { 187 port = generate_local_port(); 188 sk->s_flags &= ~NL_OWN_PORT; 189 } else { 190 if (!(sk->s_flags & NL_OWN_PORT)) 191 release_local_port(sk->s_local.nl_pid); 192 sk->s_flags |= NL_OWN_PORT; 193 } 194 195 sk->s_local.nl_pid = port; 196 } 197 198 /** @} */ 199 200 /** 201 * @name Group Subscriptions 202 * @{ 203 */ 204 205 /** 206 * Join groups 207 * @arg sk Netlink socket 208 * @arg group Group identifier 209 * 210 * Joins the specified groups using the modern socket option which 211 * is available since kernel version 2.6.14. It allows joining an 212 * almost arbitary number of groups without limitation. The list 213 * of groups has to be terminated by 0 (%NFNLGRP_NONE). 214 * 215 * Make sure to use the correct group definitions as the older 216 * bitmask definitions for nl_join_groups() are likely to still 217 * be present for backward compatibility reasons. 218 * 219 * @return 0 on sucess or a negative error code. 220 */ 221 int nl_socket_add_memberships(struct nl_sock *sk, int group, ...) 222 { 223 int err; 224 va_list ap; 225 226 if (sk->s_fd == -1) 227 return -NLE_BAD_SOCK; 228 229 va_start(ap, group); 230 231 while (group != 0) { 232 if (group < 0) 233 return -NLE_INVAL; 234 235 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, 236 &group, sizeof(group)); 237 if (err < 0) 238 return -nl_syserr2nlerr(errno); 239 240 group = va_arg(ap, int); 241 } 242 243 va_end(ap); 244 245 return 0; 246 } 247 248 /** 249 * Leave groups 250 * @arg sk Netlink socket 251 * @arg group Group identifier 252 * 253 * Leaves the specified groups using the modern socket option 254 * which is available since kernel version 2.6.14. The list of groups 255 * has to terminated by 0 (%NFNLGRP_NONE). 256 * 257 * @see nl_socket_add_membership 258 * @return 0 on success or a negative error code. 259 */ 260 int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...) 261 { 262 int err; 263 va_list ap; 264 265 if (sk->s_fd == -1) 266 return -NLE_BAD_SOCK; 267 268 va_start(ap, group); 269 270 while (group != 0) { 271 if (group < 0) 272 return -NLE_INVAL; 273 274 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, 275 &group, sizeof(group)); 276 if (err < 0) 277 return -nl_syserr2nlerr(errno); 278 279 group = va_arg(ap, int); 280 } 281 282 va_end(ap); 283 284 return 0; 285 } 286 287 288 /** @} */ 289 290 /** 291 * Set file descriptor of socket to non-blocking state 292 * @arg sk Netlink socket. 293 * 294 * @return 0 on success or a negative error code. 295 */ 296 int nl_socket_set_nonblocking(struct nl_sock *sk) 297 { 298 if (sk->s_fd == -1) 299 return -NLE_BAD_SOCK; 300 301 if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) 302 return -nl_syserr2nlerr(errno); 303 304 return 0; 305 } 306 307 /** @} */ 308 309 /** 310 * @name Utilities 311 * @{ 312 */ 313 314 /** 315 * Set socket buffer size of netlink socket. 316 * @arg sk Netlink socket. 317 * @arg rxbuf New receive socket buffer size in bytes. 318 * @arg txbuf New transmit socket buffer size in bytes. 319 * 320 * Sets the socket buffer size of a netlink socket to the specified 321 * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a 322 * good default value. 323 * 324 * @note It is not required to call this function prior to nl_connect(). 325 * @return 0 on sucess or a negative error code. 326 */ 327 int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) 328 { 329 int err; 330 331 if (rxbuf <= 0) 332 rxbuf = 32768; 333 334 if (txbuf <= 0) 335 txbuf = 32768; 336 337 if (sk->s_fd == -1) 338 return -NLE_BAD_SOCK; 339 340 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, 341 &txbuf, sizeof(txbuf)); 342 if (err < 0) 343 return -nl_syserr2nlerr(errno); 344 345 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, 346 &rxbuf, sizeof(rxbuf)); 347 if (err < 0) 348 return -nl_syserr2nlerr(errno); 349 350 sk->s_flags |= NL_SOCK_BUFSIZE_SET; 351 352 return 0; 353 } 354 355 /** 356 * Enable/disable credential passing on netlink socket. 357 * @arg sk Netlink socket. 358 * @arg state New state (0 - disabled, 1 - enabled) 359 * 360 * @return 0 on success or a negative error code 361 */ 362 int nl_socket_set_passcred(struct nl_sock *sk, int state) 363 { 364 int err; 365 366 if (sk->s_fd == -1) 367 return -NLE_BAD_SOCK; 368 369 err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, 370 &state, sizeof(state)); 371 if (err < 0) 372 return -nl_syserr2nlerr(errno); 373 374 if (state) 375 sk->s_flags |= NL_SOCK_PASSCRED; 376 else 377 sk->s_flags &= ~NL_SOCK_PASSCRED; 378 379 return 0; 380 } 381 382 /** 383 * Enable/disable receival of additional packet information 384 * @arg sk Netlink socket. 385 * @arg state New state (0 - disabled, 1 - enabled) 386 * 387 * @return 0 on success or a negative error code 388 */ 389 int nl_socket_recv_pktinfo(struct nl_sock *sk, int state) 390 { 391 int err; 392 393 if (sk->s_fd == -1) 394 return -NLE_BAD_SOCK; 395 396 err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO, 397 &state, sizeof(state)); 398 if (err < 0) 399 return -nl_syserr2nlerr(errno); 400 401 return 0; 402 } 403 404 /** @} */ 405 406 /** @} */ 407
This page was automatically generated by LXR 0.3.1. • OpenWrt