Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / fst / fst.c
1 /*
2  * FST module implementation
3  * Copyright (c) 2014, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "fst/fst.h"
14 #include "fst/fst_internal.h"
15 #include "fst/fst_defs.h"
16 #include "fst/fst_ctrl_iface.h"
17
18 struct dl_list fst_global_ctrls_list;
19
20
21 static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
22                                                     Boolean connected,
23                                                     const u8 *peer_addr)
24 {
25         union fst_event_extra extra;
26
27         extra.peer_state.connected = connected;
28         os_strlcpy(extra.peer_state.ifname, fst_iface_get_name(iface),
29                    sizeof(extra.peer_state.ifname));
30         os_memcpy(extra.peer_state.addr, peer_addr, ETH_ALEN);
31
32         foreach_fst_ctrl_call(on_event, EVENT_PEER_STATE_CHANGED,
33                               iface, NULL, &extra);
34 }
35
36
37 struct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
38                               const struct fst_wpa_obj *iface_obj,
39                               const struct fst_iface_cfg *cfg)
40 {
41         struct fst_group *g;
42         struct fst_group *group = NULL;
43         struct fst_iface *iface = NULL;
44         Boolean new_group = FALSE;
45
46         WPA_ASSERT(ifname != NULL);
47         WPA_ASSERT(iface_obj != NULL);
48         WPA_ASSERT(cfg != NULL);
49
50         foreach_fst_group(g) {
51                 if (os_strcmp(cfg->group_id, fst_group_get_id(g)) == 0) {
52                         group = g;
53                         break;
54                 }
55         }
56
57         if (!group) {
58                 group = fst_group_create(cfg->group_id);
59                 if (!group) {
60                         fst_printf(MSG_ERROR, "%s: FST group cannot be created",
61                                    cfg->group_id);
62                         return NULL;
63                 }
64                 new_group = TRUE;
65         }
66
67         iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
68         if (!iface) {
69                 fst_printf_group(group, MSG_ERROR, "cannot create iface for %s",
70                                  ifname);
71                 if (new_group)
72                         fst_group_delete(group);
73                 return NULL;
74         }
75
76         fst_group_attach_iface(group, iface);
77         fst_group_update_ie(group);
78
79         foreach_fst_ctrl_call(on_iface_added, iface);
80
81         fst_printf_iface(iface, MSG_DEBUG,
82                          "iface attached to group %s (prio=%d, llt=%d)",
83                          cfg->group_id, cfg->priority, cfg->llt);
84
85         return iface;
86 }
87
88
89 void fst_detach(struct fst_iface *iface)
90 {
91         struct fst_group *group = fst_iface_get_group(iface);
92
93         fst_printf_iface(iface, MSG_DEBUG, "iface detached from group %s",
94                          fst_group_get_id(group));
95         fst_session_global_on_iface_detached(iface);
96         foreach_fst_ctrl_call(on_iface_removed, iface);
97         fst_group_detach_iface(group, iface);
98         fst_iface_delete(iface);
99         fst_group_update_ie(group);
100         fst_group_delete_if_empty(group);
101 }
102
103
104 int fst_global_init(void)
105 {
106         dl_list_init(&fst_global_groups_list);
107         dl_list_init(&fst_global_ctrls_list);
108         fst_session_global_init();
109         return 0;
110 }
111
112
113 void fst_global_deinit(void)
114 {
115         struct fst_group *group;
116         struct fst_ctrl_handle *h;
117
118         fst_session_global_deinit();
119         while ((group = fst_first_group()) != NULL)
120                 fst_group_delete(group);
121         while ((h = dl_list_first(&fst_global_ctrls_list,
122                                   struct fst_ctrl_handle,
123                                   global_ctrls_lentry)))
124                 fst_global_del_ctrl(h);
125 }
126
127
128 struct fst_ctrl_handle * fst_global_add_ctrl(const struct fst_ctrl *ctrl)
129 {
130         struct fst_ctrl_handle *h;
131
132         if (!ctrl)
133                 return NULL;
134
135         h = os_zalloc(sizeof(*h));
136         if (!h)
137                 return NULL;
138
139         if (ctrl->init && ctrl->init()) {
140                 os_free(h);
141                 return NULL;
142         }
143
144         h->ctrl = *ctrl;
145         dl_list_add_tail(&fst_global_ctrls_list, &h->global_ctrls_lentry);
146
147         return h;
148 }
149
150
151 void fst_global_del_ctrl(struct fst_ctrl_handle *h)
152 {
153         dl_list_del(&h->global_ctrls_lentry);
154         if (h->ctrl.deinit)
155                 h->ctrl.deinit();
156         os_free(h);
157 }
158
159
160 void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
161                    size_t len)
162 {
163         if (fst_iface_is_connected(iface, mgmt->sa))
164                 fst_session_on_action_rx(iface, mgmt, len);
165         else
166                 wpa_printf(MSG_DEBUG,
167                            "FST: Ignore FST Action frame - no FST connection with "
168                            MACSTR, MAC2STR(mgmt->sa));
169 }
170
171
172 void fst_notify_peer_connected(struct fst_iface *iface, const u8 *addr)
173 {
174         if (is_zero_ether_addr(addr))
175                 return;
176
177 #ifndef HOSTAPD
178         fst_group_update_ie(fst_iface_get_group(iface));
179 #endif /* HOSTAPD */
180
181         fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
182                          MAC2STR(addr));
183
184         fst_ctrl_iface_notify_peer_state_change(iface, TRUE, addr);
185 }
186
187
188 void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr)
189 {
190         if (is_zero_ether_addr(addr))
191                 return;
192
193 #ifndef HOSTAPD
194         fst_group_update_ie(fst_iface_get_group(iface));
195 #endif /* HOSTAPD */
196
197         fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
198                          MAC2STR(addr));
199
200         fst_ctrl_iface_notify_peer_state_change(iface, FALSE, addr);
201 }
202
203
204 Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
205                                   struct fst_iface *iface2)
206 {
207         return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
208 }
209
210
211 enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
212 {
213         switch (mode) {
214         case HOSTAPD_MODE_IEEE80211B:
215         case HOSTAPD_MODE_IEEE80211G:
216                 return MB_BAND_ID_WIFI_2_4GHZ;
217         case HOSTAPD_MODE_IEEE80211A:
218                 return MB_BAND_ID_WIFI_5GHZ;
219         case HOSTAPD_MODE_IEEE80211AD:
220                 return MB_BAND_ID_WIFI_60GHZ;
221         default:
222                 WPA_ASSERT(0);
223                 return MB_BAND_ID_WIFI_2_4GHZ;
224         }
225 }