0f2b1a34c8c3c5d140c5062ce62f7a0b1a53e9e5
[oonf.git] / src / generic / nl80211_listener / nl80211_get_interface.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 /*
47  * Much of the code of this file originally came from the iw userspace
48  * command source code and was adapted for OLSRv2.
49  *
50  * Copyright (c) 2007, 2008 Johannes Berg
51  * Copyright (c) 2007    Andy Lutomirski
52  * Copyright (c) 2007    Mike Kershaw
53  * Copyright (c) 2008-2009   Luis R. Rodriguez
54  *
55  * Permission to use, copy, modify, and/or distribute this software for any
56  * purpose with or without fee is hereby granted, provided that the above
57  * copyright notice and this permission notice appear in all copies.
58  *
59  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
60  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
61  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
62  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
63  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
64  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
65  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
66  */
67
68 #define _GNU_SOURCE
69
70 /* must be first because of a problem with linux/netlink.h */
71 #include <sys/socket.h>
72
73 /* and now the rest of the includes */
74 #include <linux/genetlink.h>
75 #include <linux/netlink.h>
76 #include <linux/types.h>
77 #include <netlink/attr.h>
78 #include <netlink/genl/genl.h>
79 #include <netlink/msg.h>
80
81 #include <oonf/oonf.h>
82 #include <oonf/subsystems/os_system.h>
83
84 #include <oonf/generic/nl80211_listener/nl80211.h>
85 #include <oonf/generic/nl80211_listener/nl80211_get_interface.h>
86 #include <oonf/generic/nl80211_listener/nl80211_listener.h>
87
88 static uint64_t _get_bandwidth(uint32_t width);
89
90 /**
91  * Send a netlink message to get the nl80211 interface information
92  * @param nl pointer to netlink handler
93  * @param nl_msg pointer to netlink message
94  * @param hdr pointer to generic netlink header
95  * @param interf nl80211 listener interface
96  */
97 void
98 nl80211_send_get_interface(
99   struct os_system_netlink *nl, struct nlmsghdr *nl_msg, struct genlmsghdr *hdr, struct nl80211_if *interf) {
100   int if_index = nl80211_get_if_baseindex(interf);
101
102   hdr->cmd = NL80211_CMD_GET_INTERFACE;
103
104   /* add interface index to the request */
105   os_system_linux_netlink_addreq(nl, nl_msg, NL80211_ATTR_IFINDEX, &if_index, sizeof(if_index));
106 }
107
108 /**
109  * Process NL80211_CMD_NEW_INTERFACE message
110  * @param interf nl80211 listener interface
111  * @param hdr pointer to netlink message header
112  */
113 void
114 nl80211_process_get_interface_result(struct nl80211_if *interf, struct nlmsghdr *hdr) {
115   struct genlmsghdr *gnlh;
116   struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
117   struct oonf_layer2_neigh *l2neigh;
118   uint64_t mc_rate;
119
120   gnlh = nlmsg_data(hdr);
121   nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
122
123   if (!tb_msg[NL80211_ATTR_IFNAME] || !tb_msg[NL80211_ATTR_WIPHY]) {
124     /* no name or no physical interface */
125     return;
126   }
127
128   interf->wifi_phy_if = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
129
130   if (tb_msg[NL80211_ATTR_SSID]) {
131     char ssid[33];
132     int len;
133
134     len = nla_len(tb_msg[NL80211_ATTR_SSID]);
135     if (len > (int)sizeof(ssid) - 1) {
136       len = sizeof(ssid) - 1;
137     }
138     memcpy(ssid, nla_data(tb_msg[NL80211_ATTR_SSID]), len);
139     ssid[len] = 0;
140
141     if (strcmp(interf->l2net->if_ident, ssid) != 0) {
142       strscpy(interf->l2net->if_ident, ssid, sizeof(interf->l2net->if_ident));
143       interf->ifdata_changed = true;
144     }
145   }
146   if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
147     uint64_t freq[2], bandwidth[2];
148
149     freq[0] = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
150     freq[1] = 0;
151
152     if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
153       bandwidth[0] = _get_bandwidth(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH]));
154     }
155     else {
156       bandwidth[0] = 0;
157     }
158     bandwidth[1] = 0;
159
160     if (tb_msg[NL80211_ATTR_CENTER_FREQ1] && tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
161       freq[0] = nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
162       freq[1] = nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
163
164       bandwidth[1] = bandwidth[0];
165     }
166
167     /* transform from MHz to Hz*/
168     freq[0] *= 1000000ull;
169     freq[1] *= 1000000ull;
170
171     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_1, freq[0]);
172     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_2, freq[1]);
173     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_1, bandwidth[0]);
174     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_2, bandwidth[1]);
175
176     if (bandwidth[0] > 0 && nl80211_create_broadcast_neighbor()) {
177       /* calculate multicast rate */
178       mc_rate = 6000000ull * 20000000ull / (bandwidth[0] + bandwidth[1]);
179
180       l2neigh = oonf_layer2_neigh_add(interf->l2net, &NETADDR_MAC48_BROADCAST);
181       if (l2neigh) {
182         nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BITRATE, mc_rate);
183       }
184     }
185   }
186 }
187
188 /**
189  * Parse nl80211 bandwidth constants and return bandwidth in
190  * megahertz. If radio use 80/80 split-channel, the function reports
191  * 80 megahertz.
192  * @param width bandwidth constant
193  * @return bandwidth in hertz
194  */
195 static uint64_t
196 _get_bandwidth(uint32_t width) {
197   switch (width) {
198     case NL80211_CHAN_WIDTH_5:
199       return 5ull * 1000000ull;
200     case NL80211_CHAN_WIDTH_10:
201       return 10ull * 1000000ull;
202     case NL80211_CHAN_WIDTH_20_NOHT:
203       return 20ull * 1000000ull;
204     case NL80211_CHAN_WIDTH_20:
205       return 20ull * 1000000ull;
206     case NL80211_CHAN_WIDTH_40:
207       return 40ull * 1000000ull;
208     case NL80211_CHAN_WIDTH_80:
209       return 80ull * 1000000ull;
210     case NL80211_CHAN_WIDTH_80P80:
211       return 80ull * 1000000ull;
212     case NL80211_CHAN_WIDTH_160:
213       return 160ull * 1000000ull;
214     default:
215       return 0;
216   }
217 }