libnl  1.1
/build/libnl-MPM8kX/libnl-1.1/lib/socket.c
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 <netlink-local.h>
00093 #include <netlink/netlink.h>
00094 #include <netlink/utils.h>
00095 #include <netlink/handlers.h>
00096 #include <netlink/msg.h>
00097 #include <netlink/attr.h>
00098 
00099 static int default_cb = NL_CB_DEFAULT;
00100 
00101 static void __init init_default_cb(void)
00102 {
00103         char *nlcb;
00104 
00105         if ((nlcb = getenv("NLCB"))) {
00106                 if (!strcasecmp(nlcb, "default"))
00107                         default_cb = NL_CB_DEFAULT;
00108                 else if (!strcasecmp(nlcb, "verbose"))
00109                         default_cb = NL_CB_VERBOSE;
00110                 else if (!strcasecmp(nlcb, "debug"))
00111                         default_cb = NL_CB_DEBUG;
00112                 else {
00113                         fprintf(stderr, "Unknown value for NLCB, valid values: "
00114                                 "{default | verbose | debug}\n");
00115                 }
00116         }
00117 }
00118 
00119 static uint32_t used_ports_map[32];
00120 
00121 static uint32_t generate_local_port(void)
00122 {
00123         int i, n;
00124         uint32_t pid = getpid() & 0x3FFFFF;
00125 
00126         for (i = 0; i < 32; i++) {
00127                 if (used_ports_map[i] == 0xFFFFFFFF)
00128                         continue;
00129 
00130                 for (n = 0; n < 32; n++) {
00131                         if (1UL & (used_ports_map[i] >> n))
00132                                 continue;
00133 
00134                         used_ports_map[i] |= (1UL << n);
00135                         n += (i * 32);
00136 
00137                         /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
00138                          * to, i.e. 1024 unique ports per application. */
00139                         return pid + (n << 22);
00140 
00141                 }
00142         }
00143 
00144         /* Out of sockets in our own PID namespace, what to do? FIXME */
00145         return UINT_MAX;
00146 }
00147 
00148 static void release_local_port(uint32_t port)
00149 {
00150         int nr;
00151 
00152         if (port == UINT_MAX)
00153                 return;
00154         
00155         nr = port >> 22;
00156         used_ports_map[nr / 32] &= ~(1 << nr % 32);
00157 }
00158 
00159 /**
00160  * @name Allocation
00161  * @{
00162  */
00163 
00164 static struct nl_handle *__alloc_handle(struct nl_cb *cb)
00165 {
00166         struct nl_handle *handle;
00167 
00168         handle = calloc(1, sizeof(*handle));
00169         if (!handle) {
00170                 nl_errno(ENOMEM);
00171                 return NULL;
00172         }
00173 
00174         handle->h_fd = -1;
00175         handle->h_cb = cb;
00176         handle->h_local.nl_family = AF_NETLINK;
00177         handle->h_peer.nl_family = AF_NETLINK;
00178         handle->h_seq_expect = handle->h_seq_next = time(0);
00179         handle->h_local.nl_pid = generate_local_port();
00180         if (handle->h_local.nl_pid == UINT_MAX) {
00181                 nl_handle_destroy(handle);
00182                 nl_error(ENOBUFS, "Out of local ports");
00183                 return NULL;
00184         }
00185 
00186         return handle;
00187 }
00188 
00189 /**
00190  * Allocate new netlink socket handle.
00191  *
00192  * @return Newly allocated netlink socket handle or NULL.
00193  */
00194 struct nl_handle *nl_handle_alloc(void)
00195 {
00196         struct nl_cb *cb;
00197         
00198         cb = nl_cb_alloc(default_cb);
00199         if (!cb) {
00200                 nl_errno(ENOMEM);
00201                 return NULL;
00202         }
00203 
00204         return __alloc_handle(cb);
00205 }
00206 
00207 /**
00208  * Allocate new socket handle with custom callbacks
00209  * @arg cb              Callback handler
00210  *
00211  * The reference to the callback handler is taken into account
00212  * automatically, it is released again upon calling nl_handle_destroy().
00213  *
00214  *@return Newly allocted socket handle or NULL.
00215  */
00216 struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb)
00217 {
00218         if (cb == NULL)
00219                 BUG();
00220 
00221         return __alloc_handle(nl_cb_get(cb));
00222 }
00223 
00224 /**
00225  * Destroy netlink handle.
00226  * @arg handle          Netlink handle.
00227  */
00228 void nl_handle_destroy(struct nl_handle *handle)
00229 {
00230         if (!handle)
00231                 return;
00232 
00233         if (handle->h_fd >= 0)
00234                 close(handle->h_fd);
00235 
00236         if (!(handle->h_flags & NL_OWN_PORT))
00237                 release_local_port(handle->h_local.nl_pid);
00238 
00239         nl_cb_put(handle->h_cb);
00240         free(handle);
00241 }
00242 
00243 /** @} */
00244 
00245 /**
00246  * @name Sequence Numbers
00247  * @{
00248  */
00249 
00250 static int noop_seq_check(struct nl_msg *msg, void *arg)
00251 {
00252         return NL_OK;
00253 }
00254 
00255 
00256 /**
00257  * Disable sequence number checking.
00258  * @arg handle          Netlink handle.
00259  *
00260  * Disables checking of sequence numbers on the netlink handle. This is
00261  * required to allow messages to be processed which were not requested by
00262  * a preceding request message, e.g. netlink events.
00263  *
00264  * @note This function modifies the NL_CB_SEQ_CHECK configuration in
00265  * the callback handle associated with the socket.
00266  */
00267 void nl_disable_sequence_check(struct nl_handle *handle)
00268 {
00269         nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK,
00270                   NL_CB_CUSTOM, noop_seq_check, NULL);
00271 }
00272 
00273 /**
00274  * Use next sequence number
00275  * @arg handle          Netlink handle
00276  *
00277  * Uses the next available sequence number and increases the counter
00278  * by one for subsequent calls.
00279  *
00280  * @return Unique serial sequence number
00281  */
00282 unsigned int nl_socket_use_seq(struct nl_handle *handle)
00283 {
00284         return handle->h_seq_next++;
00285 }
00286 
00287 /** @} */
00288 
00289 /**
00290  * @name Source Idenficiation
00291  * @{
00292  */
00293 
00294 uint32_t nl_socket_get_local_port(struct nl_handle *handle)
00295 {
00296         return handle->h_local.nl_pid;
00297 }
00298 
00299 /**
00300  * Set local port of socket
00301  * @arg handle          Netlink handle
00302  * @arg port            Local port identifier
00303  *
00304  * Assigns a local port identifier to the socket. If port is 0
00305  * a unique port identifier will be generated automatically.
00306  */
00307 void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port)
00308 {
00309         if (port == 0) {
00310                 port = generate_local_port(); 
00311                 handle->h_flags &= ~NL_OWN_PORT;
00312         } else  {
00313                 if (!(handle->h_flags & NL_OWN_PORT))
00314                         release_local_port(handle->h_local.nl_pid);
00315                 handle->h_flags |= NL_OWN_PORT;
00316         }
00317 
00318         handle->h_local.nl_pid = port;
00319 }
00320 
00321 /** @} */
00322 
00323 /**
00324  * @name Group Subscriptions
00325  * @{
00326  */
00327 
00328 /**
00329  * Join a group
00330  * @arg handle          Netlink handle
00331  * @arg group           Group identifier
00332  *
00333  * Joins the specified group using the modern socket option which
00334  * is available since kernel version 2.6.14. It allows joining an
00335  * almost arbitary number of groups without limitation.
00336  *
00337  * Make sure to use the correct group definitions as the older
00338  * bitmask definitions for nl_join_groups() are likely to still
00339  * be present for backward compatibility reasons.
00340  *
00341  * @return 0 on sucess or a negative error code.
00342  */
00343 int nl_socket_add_membership(struct nl_handle *handle, int group)
00344 {
00345         int err;
00346 
00347         if (handle->h_fd == -1)
00348                 return nl_error(EBADFD, "Socket not connected");
00349 
00350         err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
00351                          &group, sizeof(group));
00352         if (err < 0)
00353                 return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) "
00354                                        "failed");
00355 
00356         return 0;
00357 }
00358 
00359 /**
00360  * Leave a group
00361  * @arg handle          Netlink handle
00362  * @arg group           Group identifier
00363  *
00364  * Leaves the specified group using the modern socket option
00365  * which is available since kernel version 2.6.14.
00366  *
00367  * @see nl_socket_add_membership
00368  * @return 0 on success or a negative error code.
00369  */
00370 int nl_socket_drop_membership(struct nl_handle *handle, int group)
00371 {
00372         int err;
00373 
00374         if (handle->h_fd == -1)
00375                 return nl_error(EBADFD, "Socket not connected");
00376 
00377         err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
00378                          &group, sizeof(group));
00379         if (err < 0)
00380                 return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) "
00381                                        "failed");
00382 
00383         return 0;
00384 }
00385 
00386 /**
00387  * Join multicast groups (deprecated)
00388  * @arg handle          Netlink handle.
00389  * @arg groups          Bitmask of groups to join.
00390  *
00391  * This function defines the old way of joining multicast group which
00392  * has to be done prior to calling nl_connect(). It works on any kernel
00393  * version but is very limited as only 32 groups can be joined.
00394  */
00395 void nl_join_groups(struct nl_handle *handle, int groups)
00396 {
00397         handle->h_local.nl_groups |= groups;
00398 }
00399 
00400 
00401 /** @} */
00402 
00403 /**
00404  * @name Peer Identfication
00405  * @{
00406  */
00407 
00408 uint32_t nl_socket_get_peer_port(struct nl_handle *handle)
00409 {
00410         return handle->h_peer.nl_pid;
00411 }
00412 
00413 void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port)
00414 {
00415         handle->h_peer.nl_pid = port;
00416 }
00417 
00418 /** @} */
00419 
00420 /**
00421  * @name File Descriptor
00422  * @{
00423  */
00424 
00425 int nl_socket_get_fd(struct nl_handle *handle)
00426 {
00427         return handle->h_fd;
00428 }
00429 
00430 /**
00431  * Set file descriptor of socket handle to non-blocking state
00432  * @arg handle          Netlink socket
00433  *
00434  * @return 0 on success or a negative error code.
00435  */
00436 int nl_socket_set_nonblocking(struct nl_handle *handle)
00437 {
00438         if (handle->h_fd == -1)
00439                 return nl_error(EBADFD, "Socket not connected");
00440 
00441         if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
00442                 return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
00443 
00444         return 0;
00445 }
00446 
00447 /**
00448  * Enable use of MSG_PEEK when reading from socket
00449  * @arg handle          Netlink socket
00450  */
00451 void nl_socket_enable_msg_peek(struct nl_handle *handle)
00452 {
00453         handle->h_flags |= NL_MSG_PEEK;
00454 }
00455 
00456 /**
00457  * Disable use of MSG_PEEK when reading from socket
00458  * @arg handle          Netlink socket
00459  */
00460 void nl_socket_disable_msg_peek(struct nl_handle *handle)
00461 {
00462         handle->h_flags &= ~NL_MSG_PEEK;
00463 }
00464 
00465 /** @} */
00466 
00467 /**
00468  * @name Callback Handler
00469  * @{
00470  */
00471 
00472 struct nl_cb *nl_socket_get_cb(struct nl_handle *handle)
00473 {
00474         return nl_cb_get(handle->h_cb);
00475 }
00476 
00477 void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb)
00478 {
00479         nl_cb_put(handle->h_cb);
00480         handle->h_cb = nl_cb_get(cb);
00481 }
00482 
00483 /**
00484  * Modify the callback handler associated to the socket
00485  * @arg handle          netlink handle
00486  * @arg type            which type callback to set
00487  * @arg kind            kind of callback
00488  * @arg func            callback function
00489  * @arg arg             argument to be passwd to callback function
00490  *
00491  * @see nl_cb_set
00492  */
00493 int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type,
00494                         enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
00495                         void *arg)
00496 {
00497         return nl_cb_set(handle->h_cb, type, kind, func, arg);
00498 }
00499 
00500 /** @} */
00501 
00502 /**
00503  * @name Utilities
00504  * @{
00505  */
00506 
00507 /**
00508  * Set socket buffer size of netlink handle.
00509  * @arg handle          Netlink handle.
00510  * @arg rxbuf           New receive socket buffer size in bytes.
00511  * @arg txbuf           New transmit socket buffer size in bytes.
00512  *
00513  * Sets the socket buffer size of a netlink handle to the specified
00514  * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
00515  * good default value.
00516  *
00517  * @note It is not required to call this function prior to nl_connect().
00518  * @return 0 on sucess or a negative error code.
00519  */
00520 int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf)
00521 {
00522         int err;
00523 
00524         if (rxbuf <= 0)
00525                 rxbuf = 32768;
00526 
00527         if (txbuf <= 0)
00528                 txbuf = 32768;
00529 
00530         if (handle->h_fd == -1)
00531                 return nl_error(EBADFD, "Socket not connected");
00532         
00533         err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
00534                          &txbuf, sizeof(txbuf));
00535         if (err < 0)
00536                 return nl_error(errno, "setsockopt(SO_SNDBUF) failed");
00537 
00538         err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
00539                          &rxbuf, sizeof(rxbuf));
00540         if (err < 0)
00541                 return nl_error(errno, "setsockopt(SO_RCVBUF) failed");
00542 
00543         handle->h_flags |= NL_SOCK_BUFSIZE_SET;
00544 
00545         return 0;
00546 }
00547 
00548 /**
00549  * Enable/disable credential passing on netlink handle.
00550  * @arg handle          Netlink handle
00551  * @arg state           New state (0 - disabled, 1 - enabled)
00552  *
00553  * @return 0 on success or a negative error code
00554  */
00555 int nl_set_passcred(struct nl_handle *handle, int state)
00556 {
00557         int err;
00558 
00559         if (handle->h_fd == -1)
00560                 return nl_error(EBADFD, "Socket not connected");
00561 
00562         err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
00563                          &state, sizeof(state));
00564         if (err < 0)
00565                 return nl_error(errno, "setsockopt(SO_PASSCRED) failed");
00566 
00567         if (state)
00568                 handle->h_flags |= NL_SOCK_PASSCRED;
00569         else
00570                 handle->h_flags &= ~NL_SOCK_PASSCRED;
00571 
00572         return 0;
00573 }
00574 
00575 /**
00576  * Enable/disable receival of additional packet information
00577  * @arg handle          Netlink handle
00578  * @arg state           New state (0 - disabled, 1 - enabled)
00579  *
00580  * @return 0 on success or a negative error code
00581  */
00582 int nl_socket_recv_pktinfo(struct nl_handle *handle, int state)
00583 {
00584         int err;
00585 
00586         if (handle->h_fd == -1)
00587                 return nl_error(EBADFD, "Socket not connected");
00588 
00589         err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
00590                          &state, sizeof(state));
00591         if (err < 0)
00592                 return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed");
00593 
00594         return 0;
00595 }
00596 
00597 /** @} */
00598 
00599 /** @} */