ISAAC  0.2.11
Flight software for the ISAAC project, adding functionality to the Astrobee robot, operating inside the International Space Station.
All Classes Functions Variables Pages
wifi.h
1 /*
2  * wifi-scan library header
3  *
4  * Copyright 2016-2018 (C) Bartosz Meglicki <meglickib@gmail.com>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  */
11 
12 #ifndef WIFI_WIFI_H_
13 #define WIFI_WIFI_H_
14 
15 // Standard includes
16 
17 #include <libmnl/libmnl.h> // netlink libmnl
18 #include <linux/nl80211.h> // nl80211 netlink
19 #include <linux/genetlink.h> // generic netlink
20 
21 #include <sys/socket.h>
22 #include <net/if.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <malloc.h>
26 #include <stdlib.h>
27 #include <fcntl.h> // fntnl (set descriptor options)
28 #include <errno.h> // errno
29 
30 #include <ros/ros.h>
31 #include <nodelet/nodelet.h>
32 #include <pluginlib/class_list_macros.h>
33 #include <string>
34 
38 namespace wifi {
39 
40 // some constants - mac address length, mac adress string length, max length of wireless network id with null character
41 enum wifi_constants {
42  BSSID_LENGTH = 6,
43  BSSID_STRING_LENGTH = 18,
44  SSID_MAX_LENGTH_WITH_NULL = 33
45 };
46 
47 // anything >=0 should mean that your are associated with the station
48 enum bss_status {
49  BSS_NONE = -1,
50  BSS_AUTHENTHICATED = 0,
51  BSS_ASSOCIATED = 1,
52  BSS_IBSS_JOINED = 2
53 };
54 
55 
56 
57 // a single wireless network can have multiple BSSes working as network under one SSID
58 struct bss_info {
59  uint8_t bssid[BSSID_LENGTH]; // this is hardware mac address of your AP
60  uint32_t frequency; // this is AP frequency in mHz
61  char ssid[SSID_MAX_LENGTH_WITH_NULL]; // this is the name of your AP as you see it when connecting
62  enum bss_status status; // anything >=0 means that your are connected to this station/network
63  int32_t signal_mbm; // signal strength in mBm, divide it by 100 to get signal in dBm
64  int32_t seen_ms_ago; // when the above information was collected
65 };
66 
67 
68 // like above
69 struct station_info {
70  uint8_t bssid[BSSID_LENGTH]; // this is hardware mac address of your AP
71  char ssid[SSID_MAX_LENGTH_WITH_NULL]; // this is the name of your AP as you see it when connecting
72  enum bss_status status; // anything >=0 means that your are connected to this station/network
73  int8_t signal_dbm; // signal strength in dBm from last received PPDU
74  int8_t signal_avg_dbm; // signal strength average in dBm
75  uint32_t rx_packets; // the number of received packets
76  uint32_t tx_packets; // the number of transmitted packets
77 };
78 
79 
80 class Wifi {
81  public:
82  // Constructor
83  Wifi();
84 
85  /* Initializes the library
86  *
87  * If this functions fails the library will die with error message explaining why
88  *
89  * parameters:
90  * interface - wireless interface, e.g. wlan0, wlan1
91  *
92  */
93  int WifiScanInit(const char *interface);
94 
95  /* Frees the resources used by library
96  *
97  */
98  void WifiScanClose();
99 
100  /* Retrieve information about station you are associated to
101  *
102  * Retrieves information only about single station.
103  * This function can be called repeateadly fast.
104  *
105  * parameters:
106  * station - to be filled with information
107  *
108  * returns:
109  * -1 on error (errno is set), 0 if not associated to any station, 1 if data was retrieved
110  *
111  * preconditions:
112  * wifi initialized with wifi_scan_init
113  *
114  */
115  int WifiScanStation(struct station_info *station);
116 
117  /* Make a passive scan of all networks around.
118  *
119  * This function triggers passive scan if necessery, waits for completion and returns the data.
120  * If some other scan was triggered in the meanwhile the library will collect it's results.
121  * Triggering a scan requires permissions, for testing you may use sudo.
122  *
123  * Scanning may take some time (it can be order of second).
124  * While scanning the link may be unusable for other programs!
125  *
126  * parameters:
127  * bss_infos - array of bss_info of size bss_infos_length
128  * bss_infos_length - the length of passed array
129  *
130  * returns:
131  * -1 on error (errno is set) or the number of found BSSes, the number may be greater then bss_infos_length
132  *
133  * Some devices may fail with -1 and errno=EBUSY if triggering scan when another scan is in progress. You may wait and retry in that case
134  *
135  * preconditions:
136  * wifi initialized with wifi_scan_init
137  *
138  */
139  int WifiScanAll(struct bss_info *bss_infos, int bss_infos_length);
140 
141  // convert bssid to printable hardware mac address
142  std::string bssid_to_string(const uint8_t bssid[BSSID_LENGTH]) {
143  char bssid_buff[BSSID_STRING_LENGTH];
144  snprintf(bssid_buff, BSSID_STRING_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
145  bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);\
146  return bssid_buff;
147  }
148 
149  private:
150  // everything needed for sending/receiving with netlink
151  struct netlink_channel {
152  struct mnl_socket *nl; // netlink socket
153  char *buf; // buffer for messages (in and out)
154  uint16_t nl80211_id; // generic netlink nl80211 id
155  uint32_t ifindex; // the wireless interface number (e.g. interface number for wlan0)
156  uint32_t sequence; // the sequence number of netlink message
157  void *context; // additional data to be stored/used when processing concrete message
158  };
159 
160  // internal library data passed around by user
161  struct wifi_scan {
162  struct netlink_channel notification_channel;
163  struct netlink_channel command_channel;
164  };
165  // DECLARATIONS AND TOP-DOWN LIBRARY OVERVIEW
166 
167  // INITIALIZATION
168 
169  // data needed from CTRL_CMD_GETFAMILY for nl80211, nl80211 id is stored in the channel rather then here
170  struct context_CTRL_CMD_GETFAMILY {
171  uint32_t id_NL80211_MULTICAST_GROUP_SCAN; // the id of group scan which we need to subscribe to
172  };
173 
174  // allocate memory, set initial values, etc.
175  static int InitNetlinkChannel(struct netlink_channel *channel, const char *interface);
176  // execute command to get nl80211 family and process the results
177  static int GetFamilyAndScanIds(struct netlink_channel *channel);
178  // this processes kernel reply for get family request, stores family id
179  static int handle_CTRL_CMD_GETFAMILY(const struct nlmsghdr *nlh, void *data);
180  // parses multicast groups to get scan multicast group id
181  static void parse_CTRL_ATTR_MCAST_GROUPS(struct nlattr *nested, struct netlink_channel *channel);
182 
183  // subscribes channel to multicast group scan using scan group id
184  static void subscribe_NL80211_MULTICAST_GROUP_SCAN(struct netlink_channel *channel, uint32_t scan_group_id);
185 
186  // CLEANUP
187 
188  // cleans up after single channel
189  static void CloseNetlinkChannel(struct netlink_channel *channel);
190 
191  // SCANNING
192  // SCANNING - notification related
193 
194  // the data needed from notifications
195  struct context_NL80211_MULTICAST_GROUP_SCAN {
196  int new_scan_results; // are new scan results waiting for us?
197  int scan_triggered; // was scan was already triggered by somebody else?
198  };
199 
200  // read but do not block
201  static int ReadPastNotifications(struct netlink_channel *notifications);
202  // this handles notifications
203  static int handle_NL80211_MULTICAST_GROUP_SCAN(const struct nlmsghdr *nlh, void *data);
204  // triggers scan if no results are waiting yet and if it was not already triggered
205  static int TriggerScanIfNecessary(struct netlink_channel *commands,
206  struct context_NL80211_MULTICAST_GROUP_SCAN *scanning);
207  // wait for the notification that scan finished
208  static int WaitForNewScanResults(struct netlink_channel *notifications);
209 
210  // // SCANNING - scan related
211 
212  // the data needed from new scan results
213  struct context_NL80211_CMD_NEW_SCAN_RESULTS {
214  struct bss_info *bss_infos;
215  int bss_infos_length;
216  int scanned;
217  };
218 
219  // get scan results cached by the driver
220  static int GetScan(struct netlink_channel *channel);
221  // process the new scan results
222  static int handle_NL80211_CMD_NEW_SCAN_RESULTS(const struct nlmsghdr *nlh, void *data);
223  // get the information about bss (nested attribute)
224  static void parse_NL80211_ATTR_BSS(struct nlattr *nested, struct netlink_channel *channel);
225  // get the information from IE (non-netlink binary data here!)
226  static void parse_NL80211_BSS_INFORMATION_ELEMENTS(struct nlattr *attr, char SSID_OUT[33]);
227  // get BSSID (mac address)
228  static void parse_NL80211_BSS_BSSID(struct nlattr *attr, uint8_t bssid_out[BSSID_LENGTH]);
229 
230  // STATION
231 
232  // data needed from command new station
233  struct context_NL80211_CMD_NEW_STATION {
234  struct station_info *station;
235  };
236 
237  // get information about station with BSSID
238  static int GetStation(struct netlink_channel *channel, uint8_t bssid[BSSID_LENGTH]);
239  // process command new station
240  static int handle_NL80211_CMD_NEW_STATION(const struct nlmsghdr *nlh, void *data);
241  // process station info (nested attribute)
242  static void parse_NL80211_ATTR_STA_INFO(struct nlattr *nested, struct netlink_channel *channel);
243 
244  // NETLINK HELPERS
245 
246  // NETLINK HELPERS - message construction/sending/receiving
247 
248  // create the message with specified parameters for the channel
249  // fill the message with additional attributes as needed with:
250  // mnl_attr_put_[|u8|u16|u32|u64|str|strz] and mnl_attr_nest_[start|end]
251  static struct nlmsghdr *PrepareNlMessage(uint32_t type, uint16_t flags,
252  uint8_t genl_cmd, struct netlink_channel *channel);
253  // send the above message
254  static void SendNlMessage(struct nlmsghdr *nlh, struct netlink_channel *channel);
255  // receive the results and process them using callback function
256  static int ReceiveNlMessage(struct netlink_channel *channel, mnl_cb_t callback);
257 
258  // NETLINK HELPERS - validation
259 
260  // all information needed to validate attributes
261  struct validation_data {
262  // validated attributes are returned here
263  struct nlattr **attribute_table;
264  // at most that many, distinct constants from nl80211.h go here
265  int attribute_length;
266  // vavildate against that table
267  const struct attribute_validation *validation;
268  int validation_length;
269  };
270 
271  // data of type struct validation_data*, validate attr against data, this is called for each attribute
272  static int Validate(const struct nlattr *attr, void *data);
273 
274  // #####################################################################
275  // IMPLEMENTATION
276 
277  struct wifi_scan *wifi_;
278 };
279  // NETLINK HELPERS - validation
280 
281  // formal requirements for attribute
283  // attribute constant from nl80211.h
284  int attr;
285  // MNL_TYPE_[UNSPEC|U8|U16|U32|U64|STRING|FLAG|MSECS|NESTED|NESTED_COMPAT|NUL_STRING|BINARY]
286  enum mnl_attr_data_type type;
287  // length in bytes, can be ommitted for attibutes of known size (e.g. U16), can be 0 if unspeciffied
288  size_t len;
289  };
290  // validate only what we are going to use, note that
291  // this lists all the attributes used by the library
292 
293  static constexpr struct attribute_validation NL80211_VALIDATION[2] = {
294  {CTRL_ATTR_FAMILY_ID, MNL_TYPE_U16},
295  {CTRL_ATTR_MCAST_GROUPS, MNL_TYPE_NESTED}
296  };
297 
298  static constexpr struct attribute_validation NL80211_MCAST_GROUPS_VALIDATION[2] = {
299  {CTRL_ATTR_MCAST_GRP_ID, MNL_TYPE_U32},
300  {CTRL_ATTR_MCAST_GRP_NAME, MNL_TYPE_STRING}
301  };
302 
303  static constexpr struct attribute_validation NL80211_BSS_VALIDATION[6] = {
304  {NL80211_BSS_BSSID, MNL_TYPE_BINARY, 6},
305  {NL80211_BSS_FREQUENCY, MNL_TYPE_U32},
306  {NL80211_BSS_INFORMATION_ELEMENTS, MNL_TYPE_BINARY},
307  {NL80211_BSS_STATUS, MNL_TYPE_U32},
308  {NL80211_BSS_SIGNAL_MBM, MNL_TYPE_U32},
309  {NL80211_BSS_SEEN_MS_AGO, MNL_TYPE_U32}
310  };
311 
312  static constexpr struct attribute_validation NL80211_NEW_SCAN_RESULTS_VALIDATION[3] = {
313  {NL80211_ATTR_IFINDEX, MNL_TYPE_U32},
314  {NL80211_ATTR_SCAN_SSIDS, MNL_TYPE_NESTED},
315  {NL80211_ATTR_BSS, MNL_TYPE_NESTED}
316  };
317 
318  static constexpr struct attribute_validation NL80211_CMD_NEW_STATION_VALIDATION[1] = {
319  {NL80211_ATTR_STA_INFO, MNL_TYPE_NESTED}
320  };
321 
322  static constexpr struct attribute_validation NL80211_STA_INFO_VALIDATION[4] = {
323  {NL80211_STA_INFO_SIGNAL, MNL_TYPE_U8},
324  {NL80211_STA_INFO_SIGNAL_AVG, MNL_TYPE_U8},
325  {NL80211_STA_INFO_RX_PACKETS, MNL_TYPE_U32},
326  {NL80211_STA_INFO_TX_PACKETS, MNL_TYPE_U32}
327  };
328 
329  static constexpr int NL80211_VALIDATION_LENGTH
330  = sizeof(NL80211_VALIDATION)/sizeof(struct attribute_validation);
331  static constexpr int NL80211_MCAST_GROUPS_VALIDATION_LENGTH
332  = sizeof(NL80211_MCAST_GROUPS_VALIDATION)/sizeof(struct attribute_validation);
333  static constexpr int NL80211_BSS_VALIDATION_LENGTH
334  = sizeof(NL80211_BSS_VALIDATION)/sizeof(struct attribute_validation);
335  static constexpr int NL80211_NEW_SCAN_RESULTS_VALIDATION_LENGTH
336  = sizeof(NL80211_NEW_SCAN_RESULTS_VALIDATION)/sizeof(struct attribute_validation);
337  static constexpr int NL80211_CMD_NEW_STATION_VALIDATION_LENGTH
338  = sizeof(NL80211_CMD_NEW_STATION_VALIDATION)/sizeof(struct attribute_validation);
339  static constexpr int NL80211_STA_INFO_VALIDATION_LENGTH
340  = sizeof(NL80211_STA_INFO_VALIDATION)/sizeof(struct attribute_validation);
341 
342 
343 } // namespace wifi
344 #endif // WIFI_WIFI_H_
wifi::attribute_validation
Definition: wifi.h:282
wifi::Wifi
Definition: wifi.h:80
wifi::bss_info
Definition: wifi.h:58
wifi::station_info
Definition: wifi.h:69