netlink.c
Go to the documentation of this file.
00001 /*
00002  * Netlink helper functions for driver wrappers
00003  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "eloop.h"
00019 #include "priv_netlink.h"
00020 #include "netlink.h"
00021 
00022 
00023 struct netlink_data {
00024         struct netlink_config *cfg;
00025         int sock;
00026 };
00027 
00028 
00029 static void netlink_receive_link(struct netlink_data *netlink,
00030                                  void (*cb)(void *ctx, struct ifinfomsg *ifi,
00031                                             u8 *buf, size_t len),
00032                                  struct nlmsghdr *h)
00033 {
00034         if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
00035                 return;
00036         cb(netlink->cfg->ctx, NLMSG_DATA(h),
00037            NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
00038            NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
00039 }
00040 
00041 
00042 static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
00043 {
00044         struct netlink_data *netlink = eloop_ctx;
00045         char buf[8192];
00046         int left;
00047         struct sockaddr_nl from;
00048         socklen_t fromlen;
00049         struct nlmsghdr *h;
00050         int max_events = 10;
00051 
00052 try_again:
00053         fromlen = sizeof(from);
00054         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
00055                         (struct sockaddr *) &from, &fromlen);
00056         if (left < 0) {
00057                 if (errno != EINTR && errno != EAGAIN)
00058                         wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
00059                                    strerror(errno));
00060                 return;
00061         }
00062 
00063         h = (struct nlmsghdr *) buf;
00064         while (NLMSG_OK(h, left)) {
00065                 switch (h->nlmsg_type) {
00066                 case RTM_NEWLINK:
00067                         netlink_receive_link(netlink, netlink->cfg->newlink_cb,
00068                                              h);
00069                         break;
00070                 case RTM_DELLINK:
00071                         netlink_receive_link(netlink, netlink->cfg->dellink_cb,
00072                                              h);
00073                         break;
00074                 }
00075 
00076                 h = NLMSG_NEXT(h, left);
00077         }
00078 
00079         if (left > 0) {
00080                 wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
00081                            "netlink message", left);
00082         }
00083 
00084         if (--max_events > 0) {
00085                 /*
00086                  * Try to receive all events in one eloop call in order to
00087                  * limit race condition on cases where AssocInfo event, Assoc
00088                  * event, and EAPOL frames are received more or less at the
00089                  * same time. We want to process the event messages first
00090                  * before starting EAPOL processing.
00091                  */
00092                 goto try_again;
00093         }
00094 }
00095 
00096 
00097 struct netlink_data * netlink_init(struct netlink_config *cfg)
00098 {
00099         struct netlink_data *netlink;
00100         struct sockaddr_nl local;
00101 
00102         netlink = os_zalloc(sizeof(*netlink));
00103         if (netlink == NULL)
00104                 return NULL;
00105 
00106         netlink->cfg = cfg;
00107 
00108         netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00109         if (netlink->sock < 0) {
00110                 wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
00111                            "socket: %s", strerror(errno));
00112                 netlink_deinit(netlink);
00113                 return NULL;
00114         }
00115 
00116         os_memset(&local, 0, sizeof(local));
00117         local.nl_family = AF_NETLINK;
00118         local.nl_groups = RTMGRP_LINK;
00119         if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
00120         {
00121                 wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
00122                            "socket: %s", strerror(errno));
00123                 netlink_deinit(netlink);
00124                 return NULL;
00125         }
00126 
00127         eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
00128                                  NULL);
00129 
00130         return netlink;
00131 }
00132 
00133 
00134 void netlink_deinit(struct netlink_data *netlink)
00135 {
00136         if (netlink == NULL)
00137                 return;
00138         if (netlink->sock >= 0) {
00139                 eloop_unregister_read_sock(netlink->sock);
00140                 close(netlink->sock);
00141         }
00142         os_free(netlink->cfg);
00143         os_free(netlink);
00144 }
00145 
00146 int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
00147                            int linkmode, int operstate)
00148 {
00149         struct {
00150                 struct nlmsghdr hdr;
00151                 struct ifinfomsg ifinfo;
00152                 char opts[16];
00153         } req;
00154         struct rtattr *rta;
00155         static int nl_seq;
00156         ssize_t ret;
00157 
00158         os_memset(&req, 0, sizeof(req));
00159 
00160         req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
00161         req.hdr.nlmsg_type = RTM_SETLINK;
00162         req.hdr.nlmsg_flags = NLM_F_REQUEST;
00163         req.hdr.nlmsg_seq = ++nl_seq;
00164         req.hdr.nlmsg_pid = 0;
00165 
00166         req.ifinfo.ifi_family = AF_UNSPEC;
00167         req.ifinfo.ifi_type = 0;
00168         req.ifinfo.ifi_index = ifindex;
00169         req.ifinfo.ifi_flags = 0;
00170         req.ifinfo.ifi_change = 0;
00171 
00172         if (linkmode != -1) {
00173                 rta = aliasing_hide_typecast(
00174                         ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
00175                         struct rtattr);
00176                 rta->rta_type = IFLA_LINKMODE;
00177                 rta->rta_len = RTA_LENGTH(sizeof(char));
00178                 *((char *) RTA_DATA(rta)) = linkmode;
00179                 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
00180                         RTA_LENGTH(sizeof(char));
00181         }
00182         if (operstate != -1) {
00183                 rta = aliasing_hide_typecast(
00184                         ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
00185                         struct rtattr);
00186                 rta->rta_type = IFLA_OPERSTATE;
00187                 rta->rta_len = RTA_LENGTH(sizeof(char));
00188                 *((char *) RTA_DATA(rta)) = operstate;
00189                 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
00190                         RTA_LENGTH(sizeof(char));
00191         }
00192 
00193         wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
00194                    linkmode, operstate);
00195 
00196         ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
00197         if (ret < 0) {
00198                 wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
00199                            "failed: %s (assume operstate is not supported)",
00200                            strerror(errno));
00201         }
00202 
00203         return ret < 0 ? -1 : 0;
00204 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:38