Added WirelessManager, a port of wpa_supplicant.
[AROS.git] / workbench / network / WirelessManager / src / drivers / netlink.c
blobad15b1d62a8d8a6bbe1be1588d8fecdeccec5921
1 /*
2 * Netlink helper functions for driver wrappers
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eloop.h"
19 #include "priv_netlink.h"
20 #include "netlink.h"
23 struct netlink_data {
24 struct netlink_config *cfg;
25 int sock;
29 static void netlink_receive_link(struct netlink_data *netlink,
30 void (*cb)(void *ctx, struct ifinfomsg *ifi,
31 u8 *buf, size_t len),
32 struct nlmsghdr *h)
34 if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
35 return;
36 cb(netlink->cfg->ctx, NLMSG_DATA(h),
37 NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
38 NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
42 static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
44 struct netlink_data *netlink = eloop_ctx;
45 char buf[8192];
46 int left;
47 struct sockaddr_nl from;
48 socklen_t fromlen;
49 struct nlmsghdr *h;
50 int max_events = 10;
52 try_again:
53 fromlen = sizeof(from);
54 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
55 (struct sockaddr *) &from, &fromlen);
56 if (left < 0) {
57 if (errno != EINTR && errno != EAGAIN)
58 wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
59 strerror(errno));
60 return;
63 h = (struct nlmsghdr *) buf;
64 while (NLMSG_OK(h, left)) {
65 switch (h->nlmsg_type) {
66 case RTM_NEWLINK:
67 netlink_receive_link(netlink, netlink->cfg->newlink_cb,
68 h);
69 break;
70 case RTM_DELLINK:
71 netlink_receive_link(netlink, netlink->cfg->dellink_cb,
72 h);
73 break;
76 h = NLMSG_NEXT(h, left);
79 if (left > 0) {
80 wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
81 "netlink message", left);
84 if (--max_events > 0) {
86 * Try to receive all events in one eloop call in order to
87 * limit race condition on cases where AssocInfo event, Assoc
88 * event, and EAPOL frames are received more or less at the
89 * same time. We want to process the event messages first
90 * before starting EAPOL processing.
92 goto try_again;
97 struct netlink_data * netlink_init(struct netlink_config *cfg)
99 struct netlink_data *netlink;
100 struct sockaddr_nl local;
102 netlink = os_zalloc(sizeof(*netlink));
103 if (netlink == NULL)
104 return NULL;
106 netlink->cfg = cfg;
108 netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
109 if (netlink->sock < 0) {
110 wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
111 "socket: %s", strerror(errno));
112 netlink_deinit(netlink);
113 return NULL;
116 os_memset(&local, 0, sizeof(local));
117 local.nl_family = AF_NETLINK;
118 local.nl_groups = RTMGRP_LINK;
119 if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
121 wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
122 "socket: %s", strerror(errno));
123 netlink_deinit(netlink);
124 return NULL;
127 eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
128 NULL);
130 return netlink;
134 void netlink_deinit(struct netlink_data *netlink)
136 if (netlink == NULL)
137 return;
138 if (netlink->sock >= 0) {
139 eloop_unregister_read_sock(netlink->sock);
140 close(netlink->sock);
142 os_free(netlink->cfg);
143 os_free(netlink);
146 int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
147 int linkmode, int operstate)
149 struct {
150 struct nlmsghdr hdr;
151 struct ifinfomsg ifinfo;
152 char opts[16];
153 } req;
154 struct rtattr *rta;
155 static int nl_seq;
156 ssize_t ret;
158 os_memset(&req, 0, sizeof(req));
160 req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
161 req.hdr.nlmsg_type = RTM_SETLINK;
162 req.hdr.nlmsg_flags = NLM_F_REQUEST;
163 req.hdr.nlmsg_seq = ++nl_seq;
164 req.hdr.nlmsg_pid = 0;
166 req.ifinfo.ifi_family = AF_UNSPEC;
167 req.ifinfo.ifi_type = 0;
168 req.ifinfo.ifi_index = ifindex;
169 req.ifinfo.ifi_flags = 0;
170 req.ifinfo.ifi_change = 0;
172 if (linkmode != -1) {
173 rta = aliasing_hide_typecast(
174 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
175 struct rtattr);
176 rta->rta_type = IFLA_LINKMODE;
177 rta->rta_len = RTA_LENGTH(sizeof(char));
178 *((char *) RTA_DATA(rta)) = linkmode;
179 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
180 RTA_LENGTH(sizeof(char));
182 if (operstate != -1) {
183 rta = aliasing_hide_typecast(
184 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
185 struct rtattr);
186 rta->rta_type = IFLA_OPERSTATE;
187 rta->rta_len = RTA_LENGTH(sizeof(char));
188 *((char *) RTA_DATA(rta)) = operstate;
189 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
190 RTA_LENGTH(sizeof(char));
193 wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
194 linkmode, operstate);
196 ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
197 if (ret < 0) {
198 wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
199 "failed: %s (assume operstate is not supported)",
200 strerror(errno));
203 return ret < 0 ? -1 : 0;