blob: 8cc8f3f0f8e73d3809556a6cb30c3c8cf588c111 [file] [log] [blame]
Johannes Berg4855d252006-01-12 21:12:59 +01001/*
2 * Event system
3 * Also see comments in public header file and longer explanation below.
4 *
Johannes Berg79859052006-01-31 19:31:41 +01005 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
6 * Joseph Jezak <josejx@gentoo.org>
7 * Larry Finger <Larry.Finger@lwfinger.net>
8 * Danny van Dyk <kugelfang@gentoo.org>
9 * Michael Buesch <mbuesch@freenet.de>
Johannes Berg4855d252006-01-12 21:12:59 +010010 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 * The full GNU General Public License is included in this distribution in the
25 * file called COPYING.
26 */
27
Johannes Berg370121e2006-01-04 16:32:16 +010028#include "ieee80211softmac_priv.h"
29
30/*
Johannes Berg370121e2006-01-04 16:32:16 +010031 * Each event has associated to it
32 * - an event type (see constants in public header)
33 * - an event context (see below)
34 * - the function to be called
35 * - a context (extra parameter to call the function with)
36 * - and the softmac struct
37 *
38 * The event context is private and can only be used from
39 * within this module. Its meaning varies with the event
40 * type:
41 * SCAN_FINISHED: no special meaning
42 * ASSOCIATED,
43 * ASSOCIATE_FAILED,
44 * ASSOCIATE_TIMEOUT,
45 * AUTHENTICATED,
46 * AUTH_FAILED,
47 * AUTH_TIMEOUT: a pointer to the network struct
48 * ...
49 * Code within this module can use the event context to be only
50 * called when the event is true for that specific context
51 * as per above table.
52 * If the event context is NULL, then the notification is always called,
53 * regardless of the event context. The event context is not passed to
54 * the callback, it is assumed that the context suffices.
55 *
56 * You can also use the event context only by setting the event type
57 * to -1 (private use only), in which case you'll be notified
58 * whenever the event context matches.
59 */
60
61static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
62 "scan finished",
63 "associated",
64 "associating failed",
65 "associating timed out",
66 "authenticated",
67 "authenticating failed",
68 "authenticating timed out",
69 "associating failed because no suitable network was found",
Johannes Bergfeeeaa82006-04-13 02:42:42 +020070 "disassociated",
Johannes Berg370121e2006-01-04 16:32:16 +010071};
72
73
74static void
75ieee80211softmac_notify_callback(void *d)
76{
77 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
78 kfree(d);
79
80 event.fun(event.mac->dev, event.context);
81}
82
83int
84ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
85 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
86{
87 struct ieee80211softmac_event *eventptr;
88 unsigned long flags;
89
90 if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
91 return -ENOSYS;
92
93 if (!fun)
94 return -EINVAL;
95
96 eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
97 if (!eventptr)
98 return -ENOMEM;
99
100 eventptr->event_type = event;
101 INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
102 eventptr->fun = fun;
103 eventptr->context = context;
104 eventptr->mac = mac;
105 eventptr->event_context = event_context;
106
107 spin_lock_irqsave(&mac->lock, flags);
108 list_add(&eventptr->list, &mac->events);
109 spin_unlock_irqrestore(&mac->lock, flags);
110
111 return 0;
112}
113
114int
115ieee80211softmac_notify_gfp(struct net_device *dev,
116 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
117{
118 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
119
120 if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
121 return -ENOSYS;
122
123 return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
124}
125EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
126
127/* private -- calling all callbacks that were specified */
128void
129ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
130{
131 struct ieee80211softmac_event *eventptr, *tmp;
Johannes Bergfeeeaa82006-04-13 02:42:42 +0200132 struct ieee80211softmac_network *network;
Johannes Berg370121e2006-01-04 16:32:16 +0100133
134 if (event >= 0) {
Johannes Bergfeeeaa82006-04-13 02:42:42 +0200135 union iwreq_data wrqu;
136 int we_event;
137 char *msg = NULL;
138
139 switch(event) {
140 case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
141 network = (struct ieee80211softmac_network *)event_ctx;
142 wrqu.data.length = 0;
143 wrqu.data.flags = 0;
144 memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
145 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
146 we_event = SIOCGIWAP;
147 break;
148 case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
149 wrqu.data.length = 0;
150 wrqu.data.flags = 0;
151 memset(&wrqu, '\0', sizeof (union iwreq_data));
152 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
153 we_event = SIOCGIWAP;
154 break;
Johannes Berg6788a072006-04-13 11:41:28 +0200155 case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
156 wrqu.data.length = 0;
157 wrqu.data.flags = 0;
158 memset(&wrqu, '\0', sizeof (union iwreq_data));
159 we_event = SIOCGIWSCAN;
160 break;
Johannes Bergfeeeaa82006-04-13 02:42:42 +0200161 default:
162 msg = event_descriptions[event];
163 wrqu.data.length = strlen(msg);
164 we_event = IWEVCUSTOM;
165 break;
166 }
167 wireless_send_event(mac->dev, we_event, &wrqu, msg);
Johannes Berg370121e2006-01-04 16:32:16 +0100168 }
169
170 if (!list_empty(&mac->events))
171 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
172 if ((eventptr->event_type == event || eventptr->event_type == -1)
173 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
174 list_del(&eventptr->list);
Johannes Berg5c4df6d2006-01-06 01:43:45 +0100175 schedule_work(&eventptr->work);
Johannes Berg370121e2006-01-04 16:32:16 +0100176 }
177 }
178}
179
180void
181ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
182{
183 unsigned long flags;
184
185 spin_lock_irqsave(&mac->lock, flags);
186 ieee80211softmac_call_events_locked(mac, event, event_ctx);
187
188 spin_unlock_irqrestore(&mac->lock, flags);
189}