00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00087
00088
00089
00090
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 }