socket.c

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