]>
Commit | Line | Data |
---|---|---|
a9533e7e HP |
1 | /* |
2 | * Copyright (c) 2010 Broadcom Corporation | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include <wlc_cfg.h> | |
18 | #include <typedefs.h> | |
19 | #include <bcmdefs.h> | |
20 | #include <osl.h> | |
21 | #include <bcmutils.h> | |
22 | #include <siutils.h> | |
23 | #include <proto/802.11.h> | |
24 | #include <proto/802.11e.h> | |
25 | #include <proto/wpa.h> | |
26 | #include <wlioctl.h> | |
27 | #include <bcmwpa.h> | |
28 | #include <d11.h> | |
29 | #include <wlc_rate.h> | |
30 | #include <wlc_pub.h> | |
31 | #include <wlc_key.h> | |
32 | #include <wlc_bsscfg.h> | |
33 | #include <wlc_mac80211.h> | |
34 | #include <wlc_alloc.h> | |
35 | ||
36 | static wlc_pub_t *wlc_pub_malloc(osl_t * osh, uint unit, uint * err, | |
37 | uint devid); | |
38 | static void wlc_pub_mfree(osl_t * osh, wlc_pub_t * pub); | |
39 | static void wlc_tunables_init(wlc_tunables_t * tunables, uint devid); | |
40 | ||
41 | void *wlc_calloc(osl_t * osh, uint unit, uint size) | |
42 | { | |
43 | void *item; | |
44 | ||
45 | if ((item = MALLOC(osh, size)) == NULL) | |
46 | WL_ERROR(("wl%d: %s: out of memory, malloced %d bytes\n", | |
47 | unit, __func__, MALLOCED(osh))); | |
48 | else | |
49 | bzero((char *)item, size); | |
50 | return item; | |
51 | } | |
52 | ||
53 | void BCMATTACHFN(wlc_tunables_init) (wlc_tunables_t * tunables, uint devid) { | |
54 | tunables->ntxd = NTXD; | |
55 | tunables->nrxd = NRXD; | |
56 | tunables->rxbufsz = RXBUFSZ; | |
57 | tunables->nrxbufpost = NRXBUFPOST; | |
58 | tunables->maxscb = MAXSCB; | |
59 | tunables->ampdunummpdu = AMPDU_NUM_MPDU; | |
60 | tunables->maxpktcb = MAXPKTCB; | |
61 | tunables->maxucodebss = WLC_MAX_UCODE_BSS; | |
62 | tunables->maxucodebss4 = WLC_MAX_UCODE_BSS4; | |
63 | tunables->maxbss = MAXBSS; | |
64 | tunables->datahiwat = WLC_DATAHIWAT; | |
65 | tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT; | |
66 | tunables->rxbnd = RXBND; | |
67 | tunables->txsbnd = TXSBND; | |
68 | #if defined(WLC_HIGH_ONLY) && defined(NTXD_USB_4319) | |
69 | if (devid == BCM4319_CHIP_ID) { | |
70 | tunables->ntxd = NTXD_USB_4319; | |
71 | } | |
72 | #endif /* WLC_HIGH_ONLY */ | |
73 | } | |
74 | ||
75 | static wlc_pub_t *BCMATTACHFN(wlc_pub_malloc) (osl_t * osh, uint unit, | |
76 | uint * err, uint devid) { | |
77 | wlc_pub_t *pub; | |
78 | ||
79 | if ((pub = | |
80 | (wlc_pub_t *) wlc_calloc(osh, unit, sizeof(wlc_pub_t))) == NULL) { | |
81 | *err = 1001; | |
82 | goto fail; | |
83 | } | |
84 | ||
85 | if ((pub->tunables = (wlc_tunables_t *) | |
86 | wlc_calloc(osh, unit, sizeof(wlc_tunables_t))) == NULL) { | |
87 | *err = 1028; | |
88 | goto fail; | |
89 | } | |
90 | ||
91 | /* need to init the tunables now */ | |
92 | wlc_tunables_init(pub->tunables, devid); | |
93 | ||
94 | if ((pub->multicast = (struct ether_addr *) | |
95 | wlc_calloc(osh, unit, | |
96 | (sizeof(struct ether_addr) * MAXMULTILIST))) == NULL) { | |
97 | *err = 1003; | |
98 | goto fail; | |
99 | } | |
100 | ||
101 | return pub; | |
102 | ||
103 | fail: | |
104 | wlc_pub_mfree(osh, pub); | |
105 | return NULL; | |
106 | } | |
107 | ||
108 | static void BCMATTACHFN(wlc_pub_mfree) (osl_t * osh, wlc_pub_t * pub) { | |
109 | if (pub == NULL) | |
110 | return; | |
111 | ||
112 | if (pub->multicast) | |
113 | MFREE(osh, pub->multicast, | |
114 | (sizeof(struct ether_addr) * MAXMULTILIST)); | |
115 | ||
116 | if (pub->tunables) { | |
117 | MFREE(osh, pub->tunables, sizeof(wlc_tunables_t)); | |
118 | pub->tunables = NULL; | |
119 | } | |
120 | ||
121 | MFREE(osh, pub, sizeof(wlc_pub_t)); | |
122 | } | |
123 | ||
124 | wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t * osh, uint unit) | |
125 | { | |
126 | wlc_bsscfg_t *cfg; | |
127 | ||
128 | if ((cfg = | |
129 | (wlc_bsscfg_t *) wlc_calloc(osh, unit, | |
130 | sizeof(wlc_bsscfg_t))) == NULL) | |
131 | goto fail; | |
132 | ||
133 | if ((cfg->current_bss = (wlc_bss_info_t *) | |
134 | wlc_calloc(osh, unit, sizeof(wlc_bss_info_t))) == NULL) | |
135 | goto fail; | |
136 | ||
137 | return cfg; | |
138 | ||
139 | fail: | |
140 | wlc_bsscfg_mfree(osh, cfg); | |
141 | return NULL; | |
142 | } | |
143 | ||
144 | void wlc_bsscfg_mfree(osl_t * osh, wlc_bsscfg_t * cfg) | |
145 | { | |
146 | if (cfg == NULL) | |
147 | return; | |
148 | ||
149 | if (cfg->maclist) { | |
150 | MFREE(osh, cfg->maclist, | |
151 | (int)(OFFSETOF(struct maclist, ea) + | |
152 | cfg->nmac * ETHER_ADDR_LEN)); | |
153 | cfg->maclist = NULL; | |
154 | } | |
155 | ||
156 | if (cfg->current_bss != NULL) { | |
157 | wlc_bss_info_t *current_bss = cfg->current_bss; | |
158 | if (current_bss->bcn_prb != NULL) | |
159 | MFREE(osh, current_bss->bcn_prb, | |
160 | current_bss->bcn_prb_len); | |
161 | MFREE(osh, current_bss, sizeof(wlc_bss_info_t)); | |
162 | cfg->current_bss = NULL; | |
163 | } | |
164 | ||
165 | MFREE(osh, cfg, sizeof(wlc_bsscfg_t)); | |
166 | } | |
167 | ||
168 | void wlc_bsscfg_ID_assign(wlc_info_t * wlc, wlc_bsscfg_t * bsscfg) | |
169 | { | |
170 | bsscfg->ID = wlc->next_bsscfg_ID; | |
171 | wlc->next_bsscfg_ID++; | |
172 | } | |
173 | ||
174 | /* | |
175 | * The common driver entry routine. Error codes should be unique | |
176 | */ | |
177 | wlc_info_t *BCMATTACHFN(wlc_attach_malloc) (osl_t * osh, uint unit, uint * err, | |
178 | uint devid) { | |
179 | wlc_info_t *wlc; | |
180 | ||
181 | if ((wlc = | |
182 | (wlc_info_t *) wlc_calloc(osh, unit, | |
183 | sizeof(wlc_info_t))) == NULL) { | |
184 | *err = 1002; | |
185 | goto fail; | |
186 | } | |
187 | ||
188 | wlc->hwrxoff = WL_HWRXOFF; | |
189 | ||
190 | /* allocate wlc_pub_t state structure */ | |
191 | if ((wlc->pub = wlc_pub_malloc(osh, unit, err, devid)) == NULL) { | |
192 | *err = 1003; | |
193 | goto fail; | |
194 | } | |
195 | wlc->pub->wlc = wlc; | |
196 | ||
197 | /* allocate wlc_hw_info_t state structure */ | |
198 | ||
199 | if ((wlc->hw = (wlc_hw_info_t *) | |
200 | wlc_calloc(osh, unit, sizeof(wlc_hw_info_t))) == NULL) { | |
201 | *err = 1005; | |
202 | goto fail; | |
203 | } | |
204 | wlc->hw->wlc = wlc; | |
205 | ||
206 | #ifdef WLC_LOW | |
207 | if ((wlc->hw->bandstate[0] = (wlc_hwband_t *) | |
208 | wlc_calloc(osh, unit, (sizeof(wlc_hwband_t) * MAXBANDS))) == NULL) { | |
209 | *err = 1006; | |
210 | goto fail; | |
211 | } else { | |
212 | int i; | |
213 | ||
214 | for (i = 1; i < MAXBANDS; i++) { | |
215 | wlc->hw->bandstate[i] = (wlc_hwband_t *) | |
216 | ((uintptr) wlc->hw->bandstate[0] + | |
217 | (sizeof(wlc_hwband_t) * i)); | |
218 | } | |
219 | } | |
220 | #endif /* WLC_LOW */ | |
221 | ||
222 | if ((wlc->modulecb = (modulecb_t *) | |
223 | wlc_calloc(osh, unit, | |
224 | sizeof(modulecb_t) * WLC_MAXMODULES)) == NULL) { | |
225 | *err = 1009; | |
226 | goto fail; | |
227 | } | |
228 | ||
229 | if ((wlc->default_bss = (wlc_bss_info_t *) | |
230 | wlc_calloc(osh, unit, sizeof(wlc_bss_info_t))) == NULL) { | |
231 | *err = 1010; | |
232 | goto fail; | |
233 | } | |
234 | ||
235 | if ((wlc->cfg = wlc_bsscfg_malloc(osh, unit)) == NULL) { | |
236 | *err = 1011; | |
237 | goto fail; | |
238 | } | |
239 | wlc_bsscfg_ID_assign(wlc, wlc->cfg); | |
240 | ||
241 | if ((wlc->pkt_callback = (pkt_cb_t *) | |
242 | wlc_calloc(osh, unit, | |
243 | (sizeof(pkt_cb_t) * | |
244 | (wlc->pub->tunables->maxpktcb + 1)))) == NULL) { | |
245 | *err = 1013; | |
246 | goto fail; | |
247 | } | |
248 | ||
249 | if ((wlc->wsec_def_keys[0] = (wsec_key_t *) | |
250 | wlc_calloc(osh, unit, | |
251 | (sizeof(wsec_key_t) * WLC_DEFAULT_KEYS))) == NULL) { | |
252 | *err = 1015; | |
253 | goto fail; | |
254 | } else { | |
255 | int i; | |
256 | for (i = 1; i < WLC_DEFAULT_KEYS; i++) { | |
257 | wlc->wsec_def_keys[i] = (wsec_key_t *) | |
258 | ((uintptr) wlc->wsec_def_keys[0] + | |
259 | (sizeof(wsec_key_t) * i)); | |
260 | } | |
261 | } | |
262 | ||
263 | if ((wlc->protection = (wlc_protection_t *) | |
264 | wlc_calloc(osh, unit, sizeof(wlc_protection_t))) == NULL) { | |
265 | *err = 1016; | |
266 | goto fail; | |
267 | } | |
268 | ||
269 | if ((wlc->stf = (wlc_stf_t *) | |
270 | wlc_calloc(osh, unit, sizeof(wlc_stf_t))) == NULL) { | |
271 | *err = 1017; | |
272 | goto fail; | |
273 | } | |
274 | ||
275 | if ((wlc->bandstate[0] = (wlcband_t *) | |
276 | wlc_calloc(osh, unit, (sizeof(wlcband_t) * MAXBANDS))) == NULL) { | |
277 | *err = 1025; | |
278 | goto fail; | |
279 | } else { | |
280 | int i; | |
281 | ||
282 | for (i = 1; i < MAXBANDS; i++) { | |
283 | wlc->bandstate[i] = | |
284 | (wlcband_t *) ((uintptr) wlc->bandstate[0] + | |
285 | (sizeof(wlcband_t) * i)); | |
286 | } | |
287 | } | |
288 | ||
289 | if ((wlc->corestate = (wlccore_t *) | |
290 | wlc_calloc(osh, unit, sizeof(wlccore_t))) == NULL) { | |
291 | *err = 1026; | |
292 | goto fail; | |
293 | } | |
294 | ||
295 | if ((wlc->corestate->macstat_snapshot = (macstat_t *) | |
296 | wlc_calloc(osh, unit, sizeof(macstat_t))) == NULL) { | |
297 | *err = 1027; | |
298 | goto fail; | |
299 | } | |
300 | ||
301 | return wlc; | |
302 | ||
303 | fail: | |
304 | wlc_detach_mfree(wlc, osh); | |
305 | return NULL; | |
306 | } | |
307 | ||
308 | void BCMATTACHFN(wlc_detach_mfree) (wlc_info_t * wlc, osl_t * osh) { | |
309 | if (wlc == NULL) | |
310 | return; | |
311 | ||
312 | if (wlc->modulecb) { | |
313 | MFREE(osh, wlc->modulecb, sizeof(modulecb_t) * WLC_MAXMODULES); | |
314 | wlc->modulecb = NULL; | |
315 | } | |
316 | ||
317 | if (wlc->default_bss) { | |
318 | MFREE(osh, wlc->default_bss, sizeof(wlc_bss_info_t)); | |
319 | wlc->default_bss = NULL; | |
320 | } | |
321 | if (wlc->cfg) { | |
322 | wlc_bsscfg_mfree(osh, wlc->cfg); | |
323 | wlc->cfg = NULL; | |
324 | } | |
325 | ||
326 | if (wlc->pkt_callback && wlc->pub && wlc->pub->tunables) { | |
327 | MFREE(osh, | |
328 | wlc->pkt_callback, | |
329 | sizeof(pkt_cb_t) * (wlc->pub->tunables->maxpktcb + 1)); | |
330 | wlc->pkt_callback = NULL; | |
331 | } | |
332 | ||
333 | if (wlc->wsec_def_keys[0]) | |
334 | MFREE(osh, wlc->wsec_def_keys[0], | |
335 | (sizeof(wsec_key_t) * WLC_DEFAULT_KEYS)); | |
336 | ||
337 | if (wlc->protection) { | |
338 | MFREE(osh, wlc->protection, sizeof(wlc_protection_t)); | |
339 | wlc->protection = NULL; | |
340 | } | |
341 | ||
342 | if (wlc->stf) { | |
343 | MFREE(osh, wlc->stf, sizeof(wlc_stf_t)); | |
344 | wlc->stf = NULL; | |
345 | } | |
346 | ||
347 | if (wlc->bandstate[0]) | |
348 | MFREE(osh, wlc->bandstate[0], (sizeof(wlcband_t) * MAXBANDS)); | |
349 | ||
350 | if (wlc->corestate) { | |
351 | if (wlc->corestate->macstat_snapshot) { | |
352 | MFREE(osh, wlc->corestate->macstat_snapshot, | |
353 | sizeof(macstat_t)); | |
354 | wlc->corestate->macstat_snapshot = NULL; | |
355 | } | |
356 | MFREE(osh, wlc->corestate, sizeof(wlccore_t)); | |
357 | wlc->corestate = NULL; | |
358 | } | |
359 | ||
360 | if (wlc->pub) { | |
361 | /* free pub struct */ | |
362 | wlc_pub_mfree(osh, wlc->pub); | |
363 | wlc->pub = NULL; | |
364 | } | |
365 | ||
366 | if (wlc->hw) { | |
367 | #ifdef WLC_LOW | |
368 | if (wlc->hw->bandstate[0]) { | |
369 | MFREE(osh, wlc->hw->bandstate[0], | |
370 | (sizeof(wlc_hwband_t) * MAXBANDS)); | |
371 | wlc->hw->bandstate[0] = NULL; | |
372 | } | |
373 | #endif | |
374 | ||
375 | /* free hw struct */ | |
376 | MFREE(osh, wlc->hw, sizeof(wlc_hw_info_t)); | |
377 | wlc->hw = NULL; | |
378 | } | |
379 | ||
380 | /* free the wlc */ | |
381 | MFREE(osh, wlc, sizeof(wlc_info_t)); | |
382 | wlc = NULL; | |
383 | } |