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