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