libnl 1.1
|
00001 /* 00002 * lib/socket.c Netlink Socket Handle 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup nl 00014 * @defgroup socket Socket 00015 * @brief Handle representing a netlink socket. 00016 * 00017 * The socket is represented in a structure called the netlink handle, 00018 * besides the socket, it stores various settings and values related 00019 * to the socket. Every socket handle has a mandatory association with 00020 * a set of callbacks which can be used to modify the behaviour when 00021 * sending/receiving data from the socket. 00022 * 00023 * @par Socket Attributes 00024 * - \b Local \b Port: The local port is a netlink port identifying the 00025 * local endpoint. It is used as source address for outgoing messages 00026 * and will be addressed in replies. It must therefore be unique among 00027 * all userspace applications. When the socket handle is allocated, a 00028 * unique port number is generated automatically in the form of 22 bits 00029 * Process Identifier + 10 bits Arbitary Number. Therefore the library 00030 * is capable of generating 1024 unique local port numbers for every 00031 * process. If more sockets are required, the application has to manage 00032 * port numbers itself using nl_socket_set_local_port(). 00033 * - \b Group \b Subscriptions: A socket can subscribe to any number of 00034 * multicast groups. It will then receive a copy of all messages sent 00035 * to one of the groups. This method is mainly used for event notification. 00036 * Prior to kernel 2.6.14, the group subscription was done via bitmask 00037 * which limited to a total number of groups of 32. With 2.6.14 a new 00038 * method was added based on continous identifiers which supports an 00039 * arbitary number of groups. Both methods are supported, see 00040 * nl_join_groups() respectively nl_socket_add_membership() and 00041 * nl_socket_drop_membership(). 00042 * - \b Peer \b Port: The peer port is a netlink port identifying the 00043 * peer's endpoint. If no peer port is specified, the kernel will try to 00044 * autobind to a socket of the specified netlink family automatically. 00045 * This is very common as typically only one listening socket exists 00046 * on the kernel side. The peer port can be modified using 00047 * nl_socket_set_peer_port(). 00048 * - \b Peer \b Groups: 00049 * - \b File \b Descriptor: The file descriptor of the socket, it can be 00050 * accessed via nl_socket_get_fd() to change socket options or monitor 00051 * activity using poll()/select(). 00052 * - \b Protocol: Once connected, the socket is bound to stick to one 00053 * netlink family. This field is invisible, it is maintained automatically. 00054 * (See nl_connect()) 00055 * - \b Next \b Sequence \b Number: Next available sequence number to be used 00056 * for the next message being sent out. (Initial value: UNIX time when the 00057 * socket was allocated.) Sequence numbers can be used via 00058 * nl_socket_use_seq(). 00059 * - \b Expected \b Sequence \b Number: Expected sequence number in the next 00060 * message received from the socket. (Initial value: Equal to next sequence 00061 * number.) 00062 * - \b Callbacks \b Configuration: 00063 * 00064 * @par 1) Creating the netlink handle 00065 * @code 00066 * struct nl_handle *handle; 00067 * 00068 * // Allocate and initialize a new netlink handle 00069 * handle = nl_handle_alloc(); 00070 * 00071 * // Use nl_socket_get_fd() to fetch the file description, for example to 00072 * // put a socket into non-blocking i/o mode. 00073 * fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); 00074 * @endcode 00075 * 00076 * @par 2) Group Subscriptions 00077 * @code 00078 * // Event notifications are typically sent to multicast addresses which 00079 * // represented by groups. Join a group to f.e. receive link notifications. 00080 * nl_socket_add_membership(handle, RTNLGRP_LINK); 00081 * @endcode 00082 * 00083 * @par 6) Cleaning up 00084 * @code 00085 * // Finally destroy the netlink handle 00086 * nl_handle_destroy(handle); 00087 * @endcode 00088 * 00089 * @{ 00090 */ 00091 00092 #include <pthread.h> 00093 00094 #include <netlink-local.h> 00095 #include <netlink/netlink.h> 00096 #include <netlink/utils.h> 00097 #include <netlink/handlers.h> 00098 #include <netlink/msg.h> 00099 #include <netlink/attr.h> 00100 00101 static int default_cb = NL_CB_DEFAULT; 00102 00103 static void __init init_default_cb(void) 00104 { 00105 char *nlcb; 00106 00107 if ((nlcb = getenv("NLCB"))) { 00108 if (!strcasecmp(nlcb, "default")) 00109 default_cb = NL_CB_DEFAULT; 00110 else if (!strcasecmp(nlcb, "verbose")) 00111 default_cb = NL_CB_VERBOSE; 00112 else if (!strcasecmp(nlcb, "debug")) 00113 default_cb = NL_CB_DEBUG; 00114 else { 00115 fprintf(stderr, "Unknown value for NLCB, valid values: " 00116 "{default | verbose | debug}\n"); 00117 } 00118 } 00119 } 00120 00121 static uint32_t used_ports_map[32]; 00122 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER; 00123 00124 static uint32_t generate_local_port(void) 00125 { 00126 int i, n; 00127 uint32_t pid = getpid() & 0x3FFFFF; 00128 00129 pthread_mutex_lock(&port_map_mutex); 00130 00131 for (i = 0; i < 32; i++) { 00132 if (used_ports_map[i] == 0xFFFFFFFF) 00133 continue; 00134 00135 for (n = 0; n < 32; n++) { 00136 if (1UL & (used_ports_map[i] >> n)) 00137 continue; 00138 00139 used_ports_map[i] |= (1UL << n); 00140 n += (i * 32); 00141 00142 /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit 00143 * to, i.e. 1024 unique ports per application. */ 00144 00145 pthread_mutex_unlock(&port_map_mutex); 00146 00147 return pid + (n << 22); 00148 } 00149 } 00150 00151 pthread_mutex_unlock(&port_map_mutex); 00152 00153 /* Out of sockets in our own PID namespace, what to do? FIXME */ 00154 return UINT_MAX; 00155 } 00156 00157 static void release_local_port(uint32_t port) 00158 { 00159 int nr; 00160 00161 if (port == UINT_MAX) 00162 return; 00163 00164 nr = port >> 22; 00165 00166 pthread_mutex_lock(&port_map_mutex); 00167 used_ports_map[nr / 32] &= ~(1 << (nr % 32)); 00168 pthread_mutex_unlock(&port_map_mutex); 00169 } 00170 00171 /** 00172 * @name Allocation 00173 * @{ 00174 */ 00175 00176 static struct nl_handle *__alloc_handle(struct nl_cb *cb) 00177 { 00178 struct nl_handle *handle; 00179 00180 handle = calloc(1, sizeof(*handle)); 00181 if (!handle) { 00182 nl_errno(ENOMEM); 00183 return NULL; 00184 } 00185 00186 handle->h_fd = -1; 00187 handle->h_cb = cb; 00188 handle->h_local.nl_family = AF_NETLINK; 00189 handle->h_peer.nl_family = AF_NETLINK; 00190 handle->h_seq_expect = handle->h_seq_next = time(0); 00191 handle->h_local.nl_pid = generate_local_port(); 00192 if (handle->h_local.nl_pid == UINT_MAX) { 00193 nl_handle_destroy(handle); 00194 nl_error(ENOBUFS, "Out of local ports"); 00195 return NULL; 00196 } 00197 00198 return handle; 00199 } 00200 00201 /** 00202 * Allocate new netlink socket handle. 00203 * 00204 * @return Newly allocated netlink socket handle or NULL. 00205 */ 00206 struct nl_handle *nl_handle_alloc(void) 00207 { 00208 struct nl_cb *cb; 00209 00210 cb = nl_cb_alloc(default_cb); 00211 if (!cb) { 00212 nl_errno(ENOMEM); 00213 return NULL; 00214 } 00215 00216 return __alloc_handle(cb); 00217 } 00218 00219 /** 00220 * Allocate new socket handle with custom callbacks 00221 * @arg cb Callback handler 00222 * 00223 * The reference to the callback handler is taken into account 00224 * automatically, it is released again upon calling nl_handle_destroy(). 00225 * 00226 *@return Newly allocted socket handle or NULL. 00227 */ 00228 struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb) 00229 { 00230 if (cb == NULL) 00231 BUG(); 00232 00233 return __alloc_handle(nl_cb_get(cb)); 00234 } 00235 00236 /** 00237 * Destroy netlink handle. 00238 * @arg handle Netlink handle. 00239 */ 00240 void nl_handle_destroy(struct nl_handle *handle) 00241 { 00242 if (!handle) 00243 return; 00244 00245 if (handle->h_fd >= 0) 00246 close(handle->h_fd); 00247 00248 if (!(handle->h_flags & NL_OWN_PORT)) 00249 release_local_port(handle->h_local.nl_pid); 00250 00251 nl_cb_put(handle->h_cb); 00252 free(handle); 00253 } 00254 00255 /** @} */ 00256 00257 /** 00258 * @name Sequence Numbers 00259 * @{ 00260 */ 00261 00262 static int noop_seq_check(struct nl_msg *msg, void *arg) 00263 { 00264 return NL_OK; 00265 } 00266 00267 00268 /** 00269 * Disable sequence number checking. 00270 * @arg handle Netlink handle. 00271 * 00272 * Disables checking of sequence numbers on the netlink handle. This is 00273 * required to allow messages to be processed which were not requested by 00274 * a preceding request message, e.g. netlink events. 00275 * 00276 * @note This function modifies the NL_CB_SEQ_CHECK configuration in 00277 * the callback handle associated with the socket. 00278 */ 00279 void nl_disable_sequence_check(struct nl_handle *handle) 00280 { 00281 nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK, 00282 NL_CB_CUSTOM, noop_seq_check, NULL); 00283 } 00284 00285 /** 00286 * Use next sequence number 00287 * @arg handle Netlink handle 00288 * 00289 * Uses the next available sequence number and increases the counter 00290 * by one for subsequent calls. 00291 * 00292 * @return Unique serial sequence number 00293 */ 00294 unsigned int nl_socket_use_seq(struct nl_handle *handle) 00295 { 00296 return handle->h_seq_next++; 00297 } 00298 00299 /** @} */ 00300 00301 /** 00302 * @name Source Idenficiation 00303 * @{ 00304 */ 00305 00306 uint32_t nl_socket_get_local_port(struct nl_handle *handle) 00307 { 00308 return handle->h_local.nl_pid; 00309 } 00310 00311 /** 00312 * Set local port of socket 00313 * @arg handle Netlink handle 00314 * @arg port Local port identifier 00315 * 00316 * Assigns a local port identifier to the socket. If port is 0 00317 * a unique port identifier will be generated automatically. 00318 */ 00319 void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port) 00320 { 00321 if (port == 0) { 00322 port = generate_local_port(); 00323 handle->h_flags &= ~NL_OWN_PORT; 00324 } else { 00325 if (!(handle->h_flags & NL_OWN_PORT)) 00326 release_local_port(handle->h_local.nl_pid); 00327 handle->h_flags |= NL_OWN_PORT; 00328 } 00329 00330 handle->h_local.nl_pid = port; 00331 } 00332 00333 /** @} */ 00334 00335 /** 00336 * @name Group Subscriptions 00337 * @{ 00338 */ 00339 00340 /** 00341 * Join a group 00342 * @arg handle Netlink handle 00343 * @arg group Group identifier 00344 * 00345 * Joins the specified group using the modern socket option which 00346 * is available since kernel version 2.6.14. It allows joining an 00347 * almost arbitary number of groups without limitation. 00348 * 00349 * Make sure to use the correct group definitions as the older 00350 * bitmask definitions for nl_join_groups() are likely to still 00351 * be present for backward compatibility reasons. 00352 * 00353 * @return 0 on sucess or a negative error code. 00354 */ 00355 int nl_socket_add_membership(struct nl_handle *handle, int group) 00356 { 00357 int err; 00358 00359 if (handle->h_fd == -1) 00360 return nl_error(EBADFD, "Socket not connected"); 00361 00362 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, 00363 &group, sizeof(group)); 00364 if (err < 0) 00365 return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) " 00366 "failed"); 00367 00368 return 0; 00369 } 00370 00371 /** 00372 * Leave a group 00373 * @arg handle Netlink handle 00374 * @arg group Group identifier 00375 * 00376 * Leaves the specified group using the modern socket option 00377 * which is available since kernel version 2.6.14. 00378 * 00379 * @see nl_socket_add_membership 00380 * @return 0 on success or a negative error code. 00381 */ 00382 int nl_socket_drop_membership(struct nl_handle *handle, int group) 00383 { 00384 int err; 00385 00386 if (handle->h_fd == -1) 00387 return nl_error(EBADFD, "Socket not connected"); 00388 00389 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, 00390 &group, sizeof(group)); 00391 if (err < 0) 00392 return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) " 00393 "failed"); 00394 00395 return 0; 00396 } 00397 00398 /** 00399 * Join multicast groups (deprecated) 00400 * @arg handle Netlink handle. 00401 * @arg groups Bitmask of groups to join. 00402 * 00403 * This function defines the old way of joining multicast group which 00404 * has to be done prior to calling nl_connect(). It works on any kernel 00405 * version but is very limited as only 32 groups can be joined. 00406 */ 00407 void nl_join_groups(struct nl_handle *handle, int groups) 00408 { 00409 handle->h_local.nl_groups |= groups; 00410 } 00411 00412 00413 /** @} */ 00414 00415 /** 00416 * @name Peer Identfication 00417 * @{ 00418 */ 00419 00420 uint32_t nl_socket_get_peer_port(struct nl_handle *handle) 00421 { 00422 return handle->h_peer.nl_pid; 00423 } 00424 00425 void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port) 00426 { 00427 handle->h_peer.nl_pid = port; 00428 } 00429 00430 /** @} */ 00431 00432 /** 00433 * @name File Descriptor 00434 * @{ 00435 */ 00436 00437 int nl_socket_get_fd(struct nl_handle *handle) 00438 { 00439 return handle->h_fd; 00440 } 00441 00442 /** 00443 * Set file descriptor of socket handle to non-blocking state 00444 * @arg handle Netlink socket 00445 * 00446 * @return 0 on success or a negative error code. 00447 */ 00448 int nl_socket_set_nonblocking(struct nl_handle *handle) 00449 { 00450 if (handle->h_fd == -1) 00451 return nl_error(EBADFD, "Socket not connected"); 00452 00453 if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0) 00454 return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed"); 00455 00456 return 0; 00457 } 00458 00459 /** 00460 * Enable use of MSG_PEEK when reading from socket 00461 * @arg handle Netlink socket 00462 */ 00463 void nl_socket_enable_msg_peek(struct nl_handle *handle) 00464 { 00465 handle->h_flags |= NL_MSG_PEEK; 00466 } 00467 00468 /** 00469 * Disable use of MSG_PEEK when reading from socket 00470 * @arg handle Netlink socket 00471 */ 00472 void nl_socket_disable_msg_peek(struct nl_handle *handle) 00473 { 00474 handle->h_flags &= ~NL_MSG_PEEK; 00475 } 00476 00477 /** @} */ 00478 00479 /** 00480 * @name Callback Handler 00481 * @{ 00482 */ 00483 00484 struct nl_cb *nl_socket_get_cb(struct nl_handle *handle) 00485 { 00486 return nl_cb_get(handle->h_cb); 00487 } 00488 00489 void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb) 00490 { 00491 nl_cb_put(handle->h_cb); 00492 handle->h_cb = nl_cb_get(cb); 00493 } 00494 00495 /** 00496 * Modify the callback handler associated to the socket 00497 * @arg handle netlink handle 00498 * @arg type which type callback to set 00499 * @arg kind kind of callback 00500 * @arg func callback function 00501 * @arg arg argument to be passwd to callback function 00502 * 00503 * @see nl_cb_set 00504 */ 00505 int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type, 00506 enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, 00507 void *arg) 00508 { 00509 return nl_cb_set(handle->h_cb, type, kind, func, arg); 00510 } 00511 00512 /** @} */ 00513 00514 /** 00515 * @name Utilities 00516 * @{ 00517 */ 00518 00519 /** 00520 * Set socket buffer size of netlink handle. 00521 * @arg handle Netlink handle. 00522 * @arg rxbuf New receive socket buffer size in bytes. 00523 * @arg txbuf New transmit socket buffer size in bytes. 00524 * 00525 * Sets the socket buffer size of a netlink handle to the specified 00526 * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a 00527 * good default value. 00528 * 00529 * @note It is not required to call this function prior to nl_connect(). 00530 * @return 0 on sucess or a negative error code. 00531 */ 00532 int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf) 00533 { 00534 int err; 00535 00536 if (rxbuf <= 0) 00537 rxbuf = 32768; 00538 00539 if (txbuf <= 0) 00540 txbuf = 32768; 00541 00542 if (handle->h_fd == -1) 00543 return nl_error(EBADFD, "Socket not connected"); 00544 00545 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF, 00546 &txbuf, sizeof(txbuf)); 00547 if (err < 0) 00548 return nl_error(errno, "setsockopt(SO_SNDBUF) failed"); 00549 00550 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF, 00551 &rxbuf, sizeof(rxbuf)); 00552 if (err < 0) 00553 return nl_error(errno, "setsockopt(SO_RCVBUF) failed"); 00554 00555 handle->h_flags |= NL_SOCK_BUFSIZE_SET; 00556 00557 return 0; 00558 } 00559 00560 /** 00561 * Enable/disable credential passing on netlink handle. 00562 * @arg handle Netlink handle 00563 * @arg state New state (0 - disabled, 1 - enabled) 00564 * 00565 * @return 0 on success or a negative error code 00566 */ 00567 int nl_set_passcred(struct nl_handle *handle, int state) 00568 { 00569 int err; 00570 00571 if (handle->h_fd == -1) 00572 return nl_error(EBADFD, "Socket not connected"); 00573 00574 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED, 00575 &state, sizeof(state)); 00576 if (err < 0) 00577 return nl_error(errno, "setsockopt(SO_PASSCRED) failed"); 00578 00579 if (state) 00580 handle->h_flags |= NL_SOCK_PASSCRED; 00581 else 00582 handle->h_flags &= ~NL_SOCK_PASSCRED; 00583 00584 return 0; 00585 } 00586 00587 /** 00588 * Enable/disable receival of additional packet information 00589 * @arg handle Netlink handle 00590 * @arg state New state (0 - disabled, 1 - enabled) 00591 * 00592 * @return 0 on success or a negative error code 00593 */ 00594 int nl_socket_recv_pktinfo(struct nl_handle *handle, int state) 00595 { 00596 int err; 00597 00598 if (handle->h_fd == -1) 00599 return nl_error(EBADFD, "Socket not connected"); 00600 00601 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO, 00602 &state, sizeof(state)); 00603 if (err < 0) 00604 return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed"); 00605 00606 return 0; 00607 } 00608 00609 /** @} */ 00610 00611 /** @} */