Line data Source code
1 : /*
2 : * Netlink helper functions for driver wrappers
3 : * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 : #include "eloop.h"
13 : #include "priv_netlink.h"
14 : #include "netlink.h"
15 :
16 :
17 : struct netlink_data {
18 : struct netlink_config *cfg;
19 : int sock;
20 : };
21 :
22 :
23 29498 : static void netlink_receive_link(struct netlink_data *netlink,
24 : void (*cb)(void *ctx, struct ifinfomsg *ifi,
25 : u8 *buf, size_t len),
26 : struct nlmsghdr *h)
27 : {
28 29498 : if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
29 29498 : return;
30 29498 : cb(netlink->cfg->ctx, NLMSG_DATA(h),
31 : (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
32 29498 : NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
33 : }
34 :
35 :
36 26016 : static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
37 : {
38 26016 : struct netlink_data *netlink = eloop_ctx;
39 : char buf[8192];
40 : int left;
41 : struct sockaddr_nl from;
42 : socklen_t fromlen;
43 : struct nlmsghdr *h;
44 26016 : int max_events = 10;
45 :
46 : try_again:
47 55494 : fromlen = sizeof(from);
48 55494 : left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
49 : (struct sockaddr *) &from, &fromlen);
50 55494 : if (left < 0) {
51 25994 : if (errno != EINTR && errno != EAGAIN)
52 0 : wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
53 0 : strerror(errno));
54 52010 : return;
55 : }
56 :
57 29500 : h = (struct nlmsghdr *) buf;
58 88500 : while (NLMSG_OK(h, left)) {
59 29500 : switch (h->nlmsg_type) {
60 : case RTM_NEWLINK:
61 28998 : netlink_receive_link(netlink, netlink->cfg->newlink_cb,
62 : h);
63 28998 : break;
64 : case RTM_DELLINK:
65 500 : netlink_receive_link(netlink, netlink->cfg->dellink_cb,
66 : h);
67 500 : break;
68 : }
69 :
70 29500 : h = NLMSG_NEXT(h, left);
71 : }
72 :
73 29500 : if (left > 0) {
74 0 : wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
75 : "netlink message", left);
76 : }
77 :
78 29500 : if (--max_events > 0) {
79 : /*
80 : * Try to receive all events in one eloop call in order to
81 : * limit race condition on cases where AssocInfo event, Assoc
82 : * event, and EAPOL frames are received more or less at the
83 : * same time. We want to process the event messages first
84 : * before starting EAPOL processing.
85 : */
86 29478 : goto try_again;
87 : }
88 : }
89 :
90 :
91 5 : struct netlink_data * netlink_init(struct netlink_config *cfg)
92 : {
93 : struct netlink_data *netlink;
94 : struct sockaddr_nl local;
95 :
96 5 : netlink = os_zalloc(sizeof(*netlink));
97 5 : if (netlink == NULL)
98 0 : return NULL;
99 :
100 5 : netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
101 5 : if (netlink->sock < 0) {
102 0 : wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
103 0 : "socket: %s", strerror(errno));
104 0 : netlink_deinit(netlink);
105 0 : return NULL;
106 : }
107 :
108 5 : os_memset(&local, 0, sizeof(local));
109 5 : local.nl_family = AF_NETLINK;
110 5 : local.nl_groups = RTMGRP_LINK;
111 5 : if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
112 : {
113 0 : wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
114 0 : "socket: %s", strerror(errno));
115 0 : netlink_deinit(netlink);
116 0 : return NULL;
117 : }
118 :
119 5 : eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
120 : NULL);
121 :
122 5 : netlink->cfg = cfg;
123 :
124 5 : return netlink;
125 : }
126 :
127 :
128 5 : void netlink_deinit(struct netlink_data *netlink)
129 : {
130 5 : if (netlink == NULL)
131 5 : return;
132 5 : if (netlink->sock >= 0) {
133 5 : eloop_unregister_read_sock(netlink->sock);
134 5 : close(netlink->sock);
135 : }
136 5 : os_free(netlink->cfg);
137 5 : os_free(netlink);
138 : }
139 :
140 :
141 7033 : static const char * linkmode_str(int mode)
142 : {
143 7033 : switch (mode) {
144 : case -1:
145 6343 : return "no change";
146 : case 0:
147 621 : return "kernel-control";
148 : case 1:
149 69 : return "userspace-control";
150 : }
151 0 : return "?";
152 : }
153 :
154 :
155 7033 : static const char * operstate_str(int state)
156 : {
157 7033 : switch (state) {
158 : case -1:
159 0 : return "no change";
160 : case IF_OPER_DORMANT:
161 4652 : return "IF_OPER_DORMANT";
162 : case IF_OPER_UP:
163 2381 : return "IF_OPER_UP";
164 : }
165 0 : return "?";
166 : }
167 :
168 :
169 7033 : int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
170 : int linkmode, int operstate)
171 : {
172 : struct {
173 : struct nlmsghdr hdr;
174 : struct ifinfomsg ifinfo;
175 : char opts[16];
176 : } req;
177 : struct rtattr *rta;
178 : static int nl_seq;
179 : ssize_t ret;
180 :
181 7033 : os_memset(&req, 0, sizeof(req));
182 :
183 7033 : req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
184 7033 : req.hdr.nlmsg_type = RTM_SETLINK;
185 7033 : req.hdr.nlmsg_flags = NLM_F_REQUEST;
186 7033 : req.hdr.nlmsg_seq = ++nl_seq;
187 7033 : req.hdr.nlmsg_pid = 0;
188 :
189 7033 : req.ifinfo.ifi_family = AF_UNSPEC;
190 7033 : req.ifinfo.ifi_type = 0;
191 7033 : req.ifinfo.ifi_index = ifindex;
192 7033 : req.ifinfo.ifi_flags = 0;
193 7033 : req.ifinfo.ifi_change = 0;
194 :
195 7033 : if (linkmode != -1) {
196 690 : rta = aliasing_hide_typecast(
197 : ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
198 : struct rtattr);
199 690 : rta->rta_type = IFLA_LINKMODE;
200 690 : rta->rta_len = RTA_LENGTH(sizeof(char));
201 690 : *((char *) RTA_DATA(rta)) = linkmode;
202 690 : req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
203 : RTA_LENGTH(sizeof(char));
204 : }
205 7033 : if (operstate != -1) {
206 7033 : rta = aliasing_hide_typecast(
207 : ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
208 : struct rtattr);
209 7033 : rta->rta_type = IFLA_OPERSTATE;
210 7033 : rta->rta_len = RTA_LENGTH(sizeof(char));
211 7033 : *((char *) RTA_DATA(rta)) = operstate;
212 7033 : req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
213 : RTA_LENGTH(sizeof(char));
214 : }
215 :
216 7033 : wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
217 : ifindex, linkmode, linkmode_str(linkmode),
218 : operstate, operstate_str(operstate));
219 :
220 7033 : ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
221 7033 : if (ret < 0) {
222 0 : wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
223 : "failed: %s (assume operstate is not supported)",
224 0 : strerror(errno));
225 : }
226 :
227 7033 : return ret < 0 ? -1 : 0;
228 : }
|