xref: /openbsd/sys/dev/pcmcia/if_malo.c (revision 8b4b0e59)
1 /*      $OpenBSD: if_malo.c,v 1.100 2024/05/26 08:46:28 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "bpfilter.h"
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/device.h>
24 #include <sys/timeout.h>
25 #include <sys/malloc.h>
26 #include <sys/sockio.h>
27 #include <sys/mbuf.h>
28 
29 #if NBPFILTER > 0
30 #include <net/bpf.h>
31 #endif
32 
33 #include <net/if.h>
34 #include <net/if_dl.h>
35 #include <net/if_media.h>
36 #include <net/if_llc.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/if_ether.h>
40 
41 #include <net80211/ieee80211_var.h>
42 #include <net80211/ieee80211_radiotap.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/pcmcia/pcmciavar.h>
48 #include <dev/pcmcia/pcmciadevs.h>
49 
50 #include <dev/pcmcia/if_malovar.h>
51 #include <dev/pcmcia/if_maloreg.h>
52 
53 /*
54  * Driver for the Marvell 88W8385 chip (Compact Flash).
55  */
56 
57 #ifdef CMALO_DEBUG
58 int cmalo_d = 1;
59 #define DPRINTF(l, x...)	do { if ((l) <= cmalo_d) printf(x); } while (0)
60 #else
61 #define DPRINTF(l, x...)
62 #endif
63 
64 int	malo_pcmcia_match(struct device *, void *, void *);
65 void	malo_pcmcia_attach(struct device *, struct device *, void *);
66 int	malo_pcmcia_detach(struct device *, int);
67 int	malo_pcmcia_activate(struct device *, int);
68 void	malo_pcmcia_wakeup(struct malo_softc *);
69 
70 void	cmalo_attach(struct device *);
71 int	cmalo_ioctl(struct ifnet *, u_long, caddr_t);
72 int	cmalo_fw_alloc(struct malo_softc *);
73 void	cmalo_fw_free(struct malo_softc *);
74 int	cmalo_fw_load_helper(struct malo_softc *);
75 int	cmalo_fw_load_main(struct malo_softc *);
76 int	cmalo_init(struct ifnet *);
77 void	cmalo_stop(struct malo_softc *);
78 int	cmalo_media_change(struct ifnet *);
79 int	cmalo_newstate(struct ieee80211com *, enum ieee80211_state, int);
80 void	cmalo_detach(void *);
81 int	cmalo_intr(void *);
82 void	cmalo_intr_mask(struct malo_softc *, int);
83 void	cmalo_rx(struct malo_softc *);
84 void	cmalo_start(struct ifnet *);
85 void	cmalo_watchdog(struct ifnet *);
86 int	cmalo_tx(struct malo_softc *, struct mbuf *);
87 void	cmalo_tx_done(struct malo_softc *);
88 void	cmalo_event(struct malo_softc *);
89 void	cmalo_select_network(struct malo_softc *);
90 void	cmalo_reflect_network(struct malo_softc *);
91 int	cmalo_wep(struct malo_softc *);
92 int	cmalo_rate2bitmap(int);
93 
94 void	cmalo_hexdump(void *, int);
95 int	cmalo_cmd_get_hwspec(struct malo_softc *);
96 int	cmalo_cmd_rsp_hwspec(struct malo_softc *);
97 int	cmalo_cmd_set_reset(struct malo_softc *);
98 int	cmalo_cmd_set_scan(struct malo_softc *);
99 int	cmalo_cmd_rsp_scan(struct malo_softc *);
100 int	cmalo_parse_elements(struct malo_softc *, void *, int, int);
101 int	cmalo_cmd_set_auth(struct malo_softc *);
102 int	cmalo_cmd_set_wep(struct malo_softc *, uint16_t,
103 	    struct ieee80211_key *);
104 int	cmalo_cmd_set_snmp(struct malo_softc *, uint16_t);
105 int	cmalo_cmd_set_radio(struct malo_softc *, uint16_t);
106 int	cmalo_cmd_set_channel(struct malo_softc *, uint16_t);
107 int	cmalo_cmd_set_txpower(struct malo_softc *, int16_t);
108 int	cmalo_cmd_set_antenna(struct malo_softc *, uint16_t);
109 int	cmalo_cmd_set_macctrl(struct malo_softc *);
110 int	cmalo_cmd_set_macaddr(struct malo_softc *, uint8_t *);
111 int	cmalo_cmd_set_assoc(struct malo_softc *);
112 int	cmalo_cmd_rsp_assoc(struct malo_softc *);
113 int	cmalo_cmd_set_80211d(struct malo_softc *);
114 int	cmalo_cmd_set_bgscan_config(struct malo_softc *);
115 int	cmalo_cmd_set_bgscan_query(struct malo_softc *);
116 int	cmalo_cmd_set_rate(struct malo_softc *, int);
117 int	cmalo_cmd_request(struct malo_softc *, uint16_t, int);
118 int	cmalo_cmd_response(struct malo_softc *);
119 
120 /*
121  * PCMCIA bus.
122  */
123 struct malo_pcmcia_softc {
124 	struct malo_softc	 sc_malo;
125 
126 	struct pcmcia_function	*sc_pf;
127 	struct pcmcia_io_handle	 sc_pcioh;
128 	int			 sc_io_window;
129 	void			*sc_ih;
130 };
131 
132 const struct cfattach malo_pcmcia_ca = {
133 	sizeof(struct malo_pcmcia_softc),
134 	malo_pcmcia_match,
135 	malo_pcmcia_attach,
136 	malo_pcmcia_detach,
137 	malo_pcmcia_activate
138 };
139 
140 int
malo_pcmcia_match(struct device * parent,void * match,void * aux)141 malo_pcmcia_match(struct device *parent, void *match, void *aux)
142 {
143 	struct pcmcia_attach_args *pa = aux;
144 
145 	if (pa->manufacturer == PCMCIA_VENDOR_AMBICOM &&
146 	    pa->product == PCMCIA_PRODUCT_AMBICOM_WL54CF)
147 		return (1);
148 
149 	return (0);
150 }
151 
152 void
malo_pcmcia_attach(struct device * parent,struct device * self,void * aux)153 malo_pcmcia_attach(struct device *parent, struct device *self, void *aux)
154 {
155 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)self;
156 	struct malo_softc *sc = &psc->sc_malo;
157 	struct pcmcia_attach_args *pa = aux;
158 	struct pcmcia_config_entry *cfe;
159 	const char *intrstr = NULL;
160 
161 	psc->sc_pf = pa->pf;
162 	cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
163 
164 	/* enable card */
165 	pcmcia_function_init(psc->sc_pf, cfe);
166 	if (pcmcia_function_enable(psc->sc_pf)) {
167 		printf(": can't enable function\n");
168 		return;
169 	}
170 
171 	/* allocate I/O space */
172 	if (pcmcia_io_alloc(psc->sc_pf, 0,
173 	    cfe->iospace[0].length, cfe->iospace[0].length, &psc->sc_pcioh)) {
174 		printf(": can't allocate i/o space\n");
175 		pcmcia_function_disable(psc->sc_pf);
176 		return;
177 	}
178 
179 	/* map I/O space */
180 	if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0,
181 	    cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) {
182 		printf(": can't map i/o space\n");
183 		pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
184 		pcmcia_function_disable(psc->sc_pf);
185 		return;
186 	}
187 	sc->sc_iot = psc->sc_pcioh.iot;
188 	sc->sc_ioh = psc->sc_pcioh.ioh;
189 
190 	printf(" port 0x%lx/%ld", psc->sc_pcioh.addr, psc->sc_pcioh.size);
191 
192 	/* establish interrupt */
193 	psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cmalo_intr, sc,
194 	    sc->sc_dev.dv_xname);
195 	if (psc->sc_ih == NULL) {
196 		printf(": can't establish interrupt\n");
197 		return;
198 	}
199 	intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
200 	if (intrstr != NULL) {
201 		if (*intrstr != '\0')
202 			printf(", %s", intrstr);
203 	}
204 	printf("\n");
205 
206 	config_mountroot(self, cmalo_attach);
207 }
208 
209 int
malo_pcmcia_detach(struct device * dev,int flags)210 malo_pcmcia_detach(struct device *dev, int flags)
211 {
212 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
213 	struct malo_softc *sc = &psc->sc_malo;
214 
215 	cmalo_detach(sc);
216 
217 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
218 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
219 
220 	return (0);
221 }
222 
223 int
malo_pcmcia_activate(struct device * dev,int act)224 malo_pcmcia_activate(struct device *dev, int act)
225 {
226 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
227 	struct malo_softc *sc = &psc->sc_malo;
228 	struct ieee80211com *ic = &sc->sc_ic;
229 	struct ifnet *ifp = &ic->ic_if;
230 
231 	switch (act) {
232 	case DVACT_SUSPEND:
233 		if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
234 		    (ifp->if_flags & IFF_RUNNING))
235 			cmalo_stop(sc);
236 		if (psc->sc_ih)
237 			pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
238 		psc->sc_ih = NULL;
239 		pcmcia_function_disable(psc->sc_pf);
240 		break;
241 	case DVACT_RESUME:
242 		pcmcia_function_enable(psc->sc_pf);
243 		psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
244 		    cmalo_intr, sc, sc->sc_dev.dv_xname);
245 		break;
246 	case DVACT_WAKEUP:
247 		malo_pcmcia_wakeup(sc);
248 		break;
249 	case DVACT_DEACTIVATE:
250 		if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
251 		    (ifp->if_flags & IFF_RUNNING))
252 			cmalo_stop(sc);		/* XXX tries to touch regs */
253 		if (psc->sc_ih)
254 			pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
255 		psc->sc_ih = NULL;
256 		pcmcia_function_disable(psc->sc_pf);
257 		break;
258 	}
259 	return (0);
260 }
261 
262 void
malo_pcmcia_wakeup(struct malo_softc * sc)263 malo_pcmcia_wakeup(struct malo_softc *sc)
264 {
265 	struct ieee80211com *ic = &sc->sc_ic;
266 	struct ifnet *ifp = &ic->ic_if;
267 	int s;
268 
269 	s = splnet();
270 	while (sc->sc_flags & MALO_BUSY)
271 		tsleep_nsec(&sc->sc_flags, 0, "malopwr", INFSLP);
272 	sc->sc_flags |= MALO_BUSY;
273 
274 	cmalo_init(ifp);
275 
276 	sc->sc_flags &= ~MALO_BUSY;
277 	wakeup(&sc->sc_flags);
278 	splx(s);
279 }
280 
281 /*
282  * Driver.
283  */
284 void
cmalo_attach(struct device * self)285 cmalo_attach(struct device *self)
286 {
287 	struct malo_softc *sc = (struct malo_softc *)self;
288 	struct ieee80211com *ic = &sc->sc_ic;
289 	struct ifnet *ifp = &sc->sc_ic.ic_if;
290 	int i;
291 
292 	/* disable interrupts */
293 	cmalo_intr_mask(sc, 0);
294 
295 	/* load firmware */
296 	if (cmalo_fw_alloc(sc) != 0)
297 		return;
298 	if (cmalo_fw_load_helper(sc) != 0)
299 		return;
300 	if (cmalo_fw_load_main(sc) != 0)
301 		return;
302 	sc->sc_flags |= MALO_FW_LOADED;
303 
304 	/* allocate command buffer */
305 	sc->sc_cmd = malloc(MALO_CMD_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
306 
307 	/* allocate data buffer */
308 	sc->sc_data = malloc(MCLBYTES, M_DEVBUF, M_NOWAIT);
309 
310 	/* enable interrupts */
311 	cmalo_intr_mask(sc, 1);
312 
313 	/* we are context save here for FW commands */
314 	sc->sc_cmd_ctxsave = 1;
315 
316 	/* get hardware specs */
317 	cmalo_cmd_get_hwspec(sc);
318 
319 	/* setup interface */
320 	ifp->if_softc = sc;
321 	ifp->if_ioctl = cmalo_ioctl;
322 	ifp->if_start = cmalo_start;
323 	ifp->if_watchdog = cmalo_watchdog;
324 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
325 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
326 
327 	ic->ic_opmode = IEEE80211_M_STA;
328 	ic->ic_state = IEEE80211_S_INIT;
329 	ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_WEP;
330 
331 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
332 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
333 
334 	for (i = 0; i <= 14; i++) {
335 		ic->ic_channels[i].ic_freq =
336 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
337 		ic->ic_channels[i].ic_flags =
338 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
339 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
340 	}
341 
342 	/* attach interface */
343 	if_attach(ifp);
344 	ieee80211_ifattach(ifp);
345 
346 	sc->sc_newstate = ic->ic_newstate;
347 	ic->ic_newstate = cmalo_newstate;
348 	ieee80211_media_init(ifp, cmalo_media_change, ieee80211_media_status);
349 
350 	/* second attach line */
351 	printf("%s: address %s\n",
352 	    sc->sc_dev.dv_xname, ether_sprintf(ic->ic_myaddr));
353 
354 	/* device attached */
355 	sc->sc_flags |= MALO_DEVICE_ATTACHED;
356 }
357 
358 int
cmalo_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)359 cmalo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
360 {
361 	struct malo_softc *sc = ifp->if_softc;
362 	struct ieee80211_nodereq_all *na;
363 	struct ieee80211_nodereq *nr;
364 	int i, j, s, error = 0;
365 
366 	s = splnet();
367 	/*
368 	 * Prevent processes from entering this function while another
369 	 * process is tsleep'ing in it.
370 	 */
371 	while ((sc->sc_flags & MALO_BUSY) && error == 0)
372 		error = tsleep_nsec(&sc->sc_flags, PCATCH, "maloioc", INFSLP);
373 	if (error != 0) {
374 		splx(s);
375 		return error;
376 	}
377 	sc->sc_flags |= MALO_BUSY;
378 
379 	switch (cmd) {
380 	case SIOCSIFADDR:
381 		ifp->if_flags |= IFF_UP;
382 		/* FALLTHROUGH */
383 	case SIOCSIFFLAGS:
384 		if (ifp->if_flags & IFF_UP) {
385 			if ((ifp->if_flags & IFF_RUNNING) == 0)
386 				cmalo_init(ifp);
387 		} else {
388 			if (ifp->if_flags & IFF_RUNNING)
389 				cmalo_stop(sc);
390 		}
391 		break;
392 	case SIOCS80211SCAN:
393 		cmalo_cmd_set_scan(sc);
394 		break;
395 	case SIOCG80211ALLNODES:
396 		nr = NULL;
397 		na = (struct ieee80211_nodereq_all *)data;
398 
399 		if ((nr = malloc(sizeof(*nr), M_DEVBUF, M_WAITOK)) == NULL)
400 			break;
401 
402 		for (na->na_nodes = i = j = 0; i < sc->sc_net_num &&
403 		    (na->na_size >= j + sizeof(struct ieee80211_nodereq));
404 		    i++) {
405 			bzero(nr, sizeof(*nr));
406 
407 			IEEE80211_ADDR_COPY(nr->nr_macaddr,
408 			    sc->sc_net[i].bssid);
409 			IEEE80211_ADDR_COPY(nr->nr_bssid,
410 			    sc->sc_net[i].bssid);
411 			nr->nr_channel = sc->sc_net[i].channel;
412 			nr->nr_chan_flags = IEEE80211_CHAN_B; /* XXX */
413 			nr->nr_rssi = sc->sc_net[i].rssi;
414 			nr->nr_max_rssi = 0; /* XXX */
415 			nr->nr_nwid_len = strlen(sc->sc_net[i].ssid);
416 			bcopy(sc->sc_net[i].ssid, nr->nr_nwid,
417 			    nr->nr_nwid_len);
418 			nr->nr_intval = sc->sc_net[i].beaconintvl;
419 			nr->nr_capinfo = sc->sc_net[i].capinfo;
420 			nr->nr_flags |= IEEE80211_NODEREQ_AP;
421 
422 			if (copyout(nr, (caddr_t)na->na_node + j,
423 			    sizeof(struct ieee80211_nodereq)))
424 				break;
425 
426 			j += sizeof(struct ieee80211_nodereq);
427 			na->na_nodes++;
428 		}
429 
430 		if (nr)
431 			free(nr, M_DEVBUF, 0);
432 		break;
433 	default:
434 		error = ieee80211_ioctl(ifp, cmd, data);
435 		break;
436 	}
437 
438 	if (error == ENETRESET) {
439 		if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
440 			cmalo_init(ifp);
441 		error = 0;
442 	}
443 
444 	sc->sc_flags &= ~MALO_BUSY;
445 	wakeup(&sc->sc_flags);
446 	splx(s);
447 
448 	return (error);
449 }
450 
451 int
cmalo_fw_alloc(struct malo_softc * sc)452 cmalo_fw_alloc(struct malo_softc *sc)
453 {
454 	const char *name_h = "malo8385-h";
455 	const char *name_m = "malo8385-m";
456 	int error;
457 
458 	if (sc->sc_fw_h == NULL) {
459 		/* read helper firmware image */
460 		error = loadfirmware(name_h, &sc->sc_fw_h, &sc->sc_fw_h_size);
461 		if (error != 0) {
462 			printf("%s: error %d, could not read firmware %s\n",
463 			    sc->sc_dev.dv_xname, error, name_h);
464 			return (EIO);
465 		}
466 	}
467 
468 	if (sc->sc_fw_m == NULL) {
469 		/* read main firmware image */
470 		error = loadfirmware(name_m, &sc->sc_fw_m, &sc->sc_fw_m_size);
471 		if (error != 0) {
472 			printf("%s: error %d, could not read firmware %s\n",
473 			    sc->sc_dev.dv_xname, error, name_m);
474 			return (EIO);
475 		}
476 	}
477 
478 	return (0);
479 }
480 
481 void
cmalo_fw_free(struct malo_softc * sc)482 cmalo_fw_free(struct malo_softc *sc)
483 {
484 	if (sc->sc_fw_h != NULL) {
485 		free(sc->sc_fw_h, M_DEVBUF, 0);
486 		sc->sc_fw_h = NULL;
487 	}
488 
489 	if (sc->sc_fw_m != NULL) {
490 		free(sc->sc_fw_m, M_DEVBUF, 0);
491 		sc->sc_fw_m = NULL;
492 	}
493 }
494 
495 int
cmalo_fw_load_helper(struct malo_softc * sc)496 cmalo_fw_load_helper(struct malo_softc *sc)
497 {
498 	uint8_t val8;
499 	uint16_t bsize, *uc;
500 	int offset, i;
501 
502 	/* verify if the card is ready for firmware download */
503 	val8 = MALO_READ_1(sc, MALO_REG_SCRATCH);
504 	if (val8 == MALO_VAL_SCRATCH_FW_LOADED)
505 		/* firmware already loaded */
506 		return (0);
507 	if (val8 != MALO_VAL_SCRATCH_READY) {
508 		/* bad register value */
509 		printf("%s: device not ready for FW download\n",
510 		    sc->sc_dev.dv_xname);
511 		return (EIO);
512 	}
513 
514 	/* download the helper firmware */
515 	for (offset = 0; offset < sc->sc_fw_h_size; offset += bsize) {
516 		if (sc->sc_fw_h_size - offset >= MALO_FW_HELPER_BSIZE)
517 			bsize = MALO_FW_HELPER_BSIZE;
518 		else
519 			bsize = sc->sc_fw_h_size - offset;
520 
521 		/* send a block in words and confirm it */
522 		DPRINTF(3, "%s: download helper FW block (%d bytes, %d off)\n",
523 		    sc->sc_dev.dv_xname, bsize, offset);
524 		MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
525 		uc = (uint16_t *)(sc->sc_fw_h + offset);
526 		for (i = 0; i < bsize / 2; i++)
527 			MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
528 		MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
529 		MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
530 		    MALO_VAL_CMD_DL_OVER);
531 
532 		/* poll for an acknowledgement */
533 		for (i = 0; i < 50; i++) {
534 			if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
535 			    MALO_VAL_CMD_DL_OVER)
536 				break;
537 			delay(1000);
538 		}
539 		if (i == 50) {
540 			printf("%s: timeout while helper FW block download\n",
541 			    sc->sc_dev.dv_xname);
542 			return (EIO);
543 		}
544 	}
545 
546 	/* helper firmware download done */
547 	MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, 0);
548 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
549 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
550 	DPRINTF(1, "%s: helper FW downloaded\n", sc->sc_dev.dv_xname);
551 
552 	return (0);
553 }
554 
555 int
cmalo_fw_load_main(struct malo_softc * sc)556 cmalo_fw_load_main(struct malo_softc *sc)
557 {
558 	uint16_t val16, bsize, *uc;
559 	int offset, i, retry = 0;
560 
561 	/* verify if the helper firmware has been loaded correctly */
562 	for (i = 0; i < 10; i++) {
563 		if (MALO_READ_1(sc, MALO_REG_RBAL) == MALO_FW_HELPER_LOADED)
564 			break;
565 		delay(1000);
566 	}
567 	if (i == 10) {
568 		printf("%s: helper FW not loaded\n", sc->sc_dev.dv_xname);
569 		return (EIO);
570 	}
571 	DPRINTF(1, "%s: helper FW loaded successfully\n", sc->sc_dev.dv_xname);
572 
573 	/* download the main firmware */
574 	bsize = 0; /* XXX really??? */
575 	for (offset = 0; offset < sc->sc_fw_m_size; offset += bsize) {
576 		val16 = MALO_READ_2(sc, MALO_REG_RBAL);
577 		/*
578 		 * If the helper firmware serves us an odd integer then
579 		 * something went wrong and we retry to download the last
580 		 * block until we receive a good integer again, or give up.
581 		 */
582 		if (val16 & 0x0001) {
583 			if (retry > MALO_FW_MAIN_MAXRETRY) {
584 				printf("%s: main FW download failed\n",
585 				    sc->sc_dev.dv_xname);
586 				return (EIO);
587 			}
588 			retry++;
589 			offset -= bsize;
590 		} else {
591 			retry = 0;
592 			bsize = val16;
593 		}
594 
595 		/* send a block in words and confirm it */
596 		DPRINTF(3, "%s: download main FW block (%d bytes, %d off)\n",
597 		    sc->sc_dev.dv_xname, bsize, offset);
598 		MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
599 		uc = (uint16_t *)(sc->sc_fw_m + offset);
600 		for (i = 0; i < bsize / 2; i++)
601 			MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
602 		MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
603 		MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
604 		    MALO_VAL_CMD_DL_OVER);
605 
606 		/* poll for an acknowledgement */
607 		for (i = 0; i < 5000; i++) {
608 			if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
609 			    MALO_VAL_CMD_DL_OVER)
610 				break;
611 		}
612 		if (i == 5000) {
613 			printf("%s: timeout while main FW block download\n",
614 			    sc->sc_dev.dv_xname);
615 			return (EIO);
616 		}
617 	}
618 
619 	DPRINTF(1, "%s: main FW downloaded\n", sc->sc_dev.dv_xname);
620 
621 	/* verify if the main firmware has been loaded correctly */
622 	for (i = 0; i < 500; i++) {
623 		if (MALO_READ_1(sc, MALO_REG_SCRATCH) ==
624 		    MALO_VAL_SCRATCH_FW_LOADED)
625 			break;
626 		delay(1000);
627 	}
628 	if (i == 500) {
629 		printf("%s: main FW not loaded\n", sc->sc_dev.dv_xname);
630 		return (EIO);
631 	}
632 
633 	DPRINTF(1, "%s: main FW loaded successfully\n", sc->sc_dev.dv_xname);
634 
635 	return (0);
636 }
637 
638 int
cmalo_init(struct ifnet * ifp)639 cmalo_init(struct ifnet *ifp)
640 {
641 	struct malo_softc *sc = ifp->if_softc;
642 	struct ieee80211com *ic = &sc->sc_ic;
643 
644 	/* reload the firmware if necessary */
645 	if (!(sc->sc_flags & MALO_FW_LOADED)) {
646 		/* disable interrupts */
647 		cmalo_intr_mask(sc, 0);
648 
649 		/* load firmware */
650 		if (cmalo_fw_load_helper(sc) != 0)
651 			return (EIO);
652 		if (cmalo_fw_load_main(sc) != 0)
653 			return (EIO);
654 		sc->sc_flags |= MALO_FW_LOADED;
655 
656 		/* enable interrupts */
657 		cmalo_intr_mask(sc, 1);
658 	}
659 
660 	/* reset association state flag */
661 	sc->sc_flags &= ~MALO_ASSOC_FAILED;
662 
663 	/* get current channel */
664 	ic->ic_bss->ni_chan = ic->ic_ibss_chan;
665 	sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
666 	DPRINTF(1, "%s: current channel is %d\n",
667 	    sc->sc_dev.dv_xname, sc->sc_curchan);
668 
669 	/* setup device */
670 	if (cmalo_cmd_set_macctrl(sc) != 0)
671 		return (EIO);
672 	if (cmalo_cmd_set_txpower(sc, 15) != 0)
673 		return (EIO);
674 	if (cmalo_cmd_set_antenna(sc, 1) != 0)
675 		return (EIO);
676 	if (cmalo_cmd_set_antenna(sc, 2) != 0)
677 		return (EIO);
678 	if (cmalo_cmd_set_radio(sc, 1) != 0)
679 		return (EIO);
680 	if (cmalo_cmd_set_channel(sc, sc->sc_curchan) != 0)
681 		return (EIO);
682 	if (cmalo_cmd_set_rate(sc, ic->ic_fixed_rate) != 0)
683 		return (EIO);
684 	if (cmalo_cmd_set_snmp(sc, MALO_OID_RTSTRESH) != 0)
685 		return (EIO);
686 	if (cmalo_cmd_set_snmp(sc, MALO_OID_SHORTRETRY) != 0)
687 		return (EIO);
688 	if (cmalo_cmd_set_snmp(sc, MALO_OID_FRAGTRESH) != 0)
689 		return (EIO);
690 	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
691 	if (cmalo_cmd_set_macaddr(sc, ic->ic_myaddr) != 0)
692 		return (EIO);
693 	if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
694 		if (cmalo_wep(sc) != 0)
695 			return (EIO);
696 	}
697 
698 	/* device up */
699 	ifp->if_flags |= IFF_RUNNING;
700 	ifq_clr_oactive(&ifp->if_snd);
701 
702 	/* start network */
703 	if (ic->ic_opmode != IEEE80211_M_MONITOR)
704 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
705 	if (sc->sc_flags & MALO_ASSOC_FAILED)
706 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
707 	else
708 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
709 
710 	/* we are not context save anymore for FW commands */
711 	sc->sc_cmd_ctxsave = 0;
712 
713 	return (0);
714 }
715 
716 void
cmalo_stop(struct malo_softc * sc)717 cmalo_stop(struct malo_softc *sc)
718 {
719 	struct ieee80211com *ic = &sc->sc_ic;
720 	struct ifnet *ifp = &ic->ic_if;
721 
722 	/* device down */
723 	ifp->if_flags &= ~IFF_RUNNING;
724 	ifq_clr_oactive(&ifp->if_snd);
725 
726 	/* change device back to initial state */
727 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
728 
729 	/* reset device */
730 	cmalo_cmd_set_reset(sc);
731 	sc->sc_flags &= ~MALO_FW_LOADED;
732 	ifp->if_timer = 0;
733 
734 	DPRINTF(1, "%s: device down\n", sc->sc_dev.dv_xname);
735 }
736 
737 int
cmalo_media_change(struct ifnet * ifp)738 cmalo_media_change(struct ifnet *ifp)
739 {
740 	int error;
741 
742 	if ((error = ieee80211_media_change(ifp)) != ENETRESET)
743 		return (error);
744 
745 	if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
746 		cmalo_init(ifp);
747 
748 	return (0);
749 }
750 
751 int
cmalo_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)752 cmalo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
753 {
754 	struct malo_softc *sc = ic->ic_if.if_softc;
755 	enum ieee80211_state ostate;
756 
757 	ostate = ic->ic_state;
758 
759 	if (ostate == nstate)
760 		goto out;
761 
762 	switch (nstate) {
763 		case IEEE80211_S_INIT:
764 			DPRINTF(1, "%s: newstate is IEEE80211_S_INIT\n",
765 			    sc->sc_dev.dv_xname);
766 			break;
767 		case IEEE80211_S_SCAN:
768 			DPRINTF(1, "%s: newstate is IEEE80211_S_SCAN\n",
769 			    sc->sc_dev.dv_xname);
770 			cmalo_cmd_set_scan(sc);
771 			if (!sc->sc_net_num) {
772 				/* no networks found */
773 				DPRINTF(1, "%s: no networks found\n",
774 				    sc->sc_dev.dv_xname);
775 				break;
776 			}
777 			cmalo_select_network(sc);
778 			cmalo_cmd_set_auth(sc);
779 			cmalo_cmd_set_assoc(sc);
780 			break;
781 		case IEEE80211_S_AUTH:
782 			DPRINTF(1, "%s: newstate is IEEE80211_S_AUTH\n",
783 			    sc->sc_dev.dv_xname);
784 			break;
785 		case IEEE80211_S_ASSOC:
786 			DPRINTF(1, "%s: newstate is IEEE80211_S_ASSOC\n",
787 			    sc->sc_dev.dv_xname);
788 			break;
789 		case IEEE80211_S_RUN:
790 			DPRINTF(1, "%s: newstate is IEEE80211_S_RUN\n",
791 			    sc->sc_dev.dv_xname);
792 			cmalo_reflect_network(sc);
793 			break;
794 		default:
795 			break;
796 	}
797 
798 out:
799 	return (sc->sc_newstate(ic, nstate, arg));
800 }
801 
802 void
cmalo_detach(void * arg)803 cmalo_detach(void *arg)
804 {
805 	struct malo_softc *sc = arg;
806 	struct ieee80211com *ic = &sc->sc_ic;
807 	struct ifnet *ifp = &ic->ic_if;
808 
809 	if (!(sc->sc_flags & MALO_DEVICE_ATTACHED))
810 		/* device was not properly attached */
811 		return;
812 
813 	/* free command buffer */
814 	if (sc->sc_cmd != NULL)
815 		free(sc->sc_cmd, M_DEVBUF, 0);
816 
817 	/* free data buffer */
818 	if (sc->sc_data != NULL)
819 		free(sc->sc_data, M_DEVBUF, 0);
820 
821 	/* free firmware */
822 	cmalo_fw_free(sc);
823 
824 	/* detach interface */
825 	ieee80211_ifdetach(ifp);
826 	if_detach(ifp);
827 }
828 
829 int
cmalo_intr(void * arg)830 cmalo_intr(void *arg)
831 {
832 	struct malo_softc *sc = arg;
833 	uint16_t intr = 0;
834 
835 	/* read interrupt reason */
836 	intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
837 	if (intr == 0) {
838 		/* interrupt not for us */
839 		return (0);
840 	}
841 	if (intr == 0xffff) {
842 		/* card has been detached */
843 		return (0);
844 	}
845 
846 	/* disable interrupts */
847 	cmalo_intr_mask(sc, 0);
848 
849 	/* acknowledge interrupt */
850 	MALO_WRITE_2(sc, MALO_REG_HOST_INTR_CAUSE,
851 	    intr & MALO_VAL_HOST_INTR_MASK_ON);
852 
853 	/* enable interrupts */
854 	cmalo_intr_mask(sc, 1);
855 
856 	DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
857 	    sc->sc_dev.dv_xname, intr);
858 
859 	if (intr & MALO_VAL_HOST_INTR_TX)
860 		/* TX frame sent */
861 		cmalo_tx_done(sc);
862 	if (intr & MALO_VAL_HOST_INTR_RX)
863 		/* RX frame received */
864 		cmalo_rx(sc);
865 	if (intr & MALO_VAL_HOST_INTR_CMD) {
866 		/* command response */
867 		wakeup(sc);
868 		if (!sc->sc_cmd_ctxsave)
869 			cmalo_cmd_response(sc);
870 	}
871 	if (intr & MALO_VAL_HOST_INTR_EVENT)
872 		/* event */
873 		cmalo_event(sc);
874 
875 	return (1);
876 }
877 
878 void
cmalo_intr_mask(struct malo_softc * sc,int enable)879 cmalo_intr_mask(struct malo_softc *sc, int enable)
880 {
881 	uint16_t val16;
882 
883 	val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
884 
885 	DPRINTF(3, "%s: intr mask changed from 0x%04x ",
886 	    sc->sc_dev.dv_xname, val16);
887 
888 	if (enable)
889 		MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
890 		    val16 & ~MALO_VAL_HOST_INTR_MASK_ON);
891 	else
892 		MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
893 		    val16 | MALO_VAL_HOST_INTR_MASK_ON);
894 
895 	val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
896 
897 	DPRINTF(3, "to 0x%04x\n", val16);
898 }
899 
900 void
cmalo_rx(struct malo_softc * sc)901 cmalo_rx(struct malo_softc *sc)
902 {
903 	struct ieee80211com *ic = &sc->sc_ic;
904 	struct ifnet *ifp = &ic->ic_if;
905 	struct malo_rx_desc *rxdesc;
906 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
907 	struct mbuf *m;
908 	uint8_t *data;
909 	uint16_t psize;
910 	int i;
911 
912 	splassert(IPL_NET);
913 
914 	/* read the whole RX packet which is always 802.3 */
915 	psize = MALO_READ_2(sc, MALO_REG_DATA_READ_LEN);
916 	if (psize & 0x0001) {
917 		MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data,
918 		    psize - 1);
919 		data = (uint8_t *)sc->sc_data;
920 		data[psize - 1] = MALO_READ_1(sc, MALO_REG_DATA_READ);
921 	} else
922 		MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data, psize);
923 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_RX_DL_OVER);
924 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_RX_DL_OVER);
925 
926 	/* access RX packet descriptor */
927 	rxdesc = (struct malo_rx_desc *)sc->sc_data;
928 	rxdesc->status = letoh16(rxdesc->status);
929 	rxdesc->pkglen = letoh16(rxdesc->pkglen);
930 	rxdesc->pkgoffset = letoh32(rxdesc->pkgoffset);
931 
932 	DPRINTF(2, "RX status=%d, pkglen=%d, pkgoffset=%d\n",
933 	    rxdesc->status, rxdesc->pkglen, rxdesc->pkgoffset);
934 
935 	if (rxdesc->status != MALO_RX_STATUS_OK)
936 		/* RX packet is not OK */
937 		return;
938 
939 	/* remove the LLC / SNAP header */
940 	data = sc->sc_data + rxdesc->pkgoffset;
941 	i = (ETHER_ADDR_LEN * 2) + sizeof(struct llc);
942 	bcopy(data + i, data + (ETHER_ADDR_LEN * 2), rxdesc->pkglen - i);
943 	rxdesc->pkglen -= sizeof(struct llc);
944 
945 	/* prepare mbuf */
946 	m = m_devget(sc->sc_data + rxdesc->pkgoffset,
947 	    rxdesc->pkglen, ETHER_ALIGN);
948 	if (m == NULL) {
949 		DPRINTF(1, "RX m_devget failed\n");
950 		ifp->if_ierrors++;
951 		return;
952 	}
953 
954 	/* push the frame up to the network stack if not in monitor mode */
955 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
956 		ml_enqueue(&ml, m);
957 		if_input(ifp, &ml);
958 #if NBPFILTER > 0
959 	} else {
960 		if (ifp->if_bpf)
961 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
962 #endif
963 	}
964 
965 }
966 
967 void
cmalo_start(struct ifnet * ifp)968 cmalo_start(struct ifnet *ifp)
969 {
970 	struct malo_softc *sc = ifp->if_softc;
971 	struct mbuf *m;
972 
973 	/* don't transmit packets if interface is busy or down */
974 	if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
975 		return;
976 
977 	m = ifq_dequeue(&ifp->if_snd);
978 	if (m == NULL)
979 		return;
980 
981 #if NBPFILTER > 0
982 	if (ifp->if_bpf)
983 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
984 #endif
985 
986 	if (cmalo_tx(sc, m) != 0)
987 		ifp->if_oerrors++;
988 }
989 
990 void
cmalo_watchdog(struct ifnet * ifp)991 cmalo_watchdog(struct ifnet *ifp)
992 {
993 	DPRINTF(2, "watchdog timeout\n");
994 
995 	/* accept TX packets again */
996 	ifq_clr_oactive(&ifp->if_snd);
997 }
998 
999 int
cmalo_tx(struct malo_softc * sc,struct mbuf * m)1000 cmalo_tx(struct malo_softc *sc, struct mbuf *m)
1001 {
1002 	struct ifnet *ifp = &sc->sc_ic.ic_if;
1003 	struct malo_tx_desc *txdesc = sc->sc_data;
1004 	uint8_t *data;
1005 	uint16_t psize;
1006 
1007 	splassert(IPL_NET);
1008 
1009 	bzero(sc->sc_data, sizeof(*txdesc));
1010 	psize = sizeof(*txdesc) + m->m_pkthdr.len;
1011 	data = mtod(m, uint8_t *);
1012 
1013 	/* prepare TX descriptor */
1014 	txdesc->pkgoffset = htole32(sizeof(*txdesc));
1015 	txdesc->pkglen = htole16(m->m_pkthdr.len);
1016 	bcopy(data, txdesc->dstaddrhigh, sizeof(txdesc->dstaddrhigh));
1017 	bcopy(data + sizeof(txdesc->dstaddrhigh), txdesc->dstaddrlow,
1018 	    sizeof(txdesc->dstaddrlow));
1019 
1020 	/* copy mbuf data to the buffer */
1021 	m_copydata(m, 0, m->m_pkthdr.len, sc->sc_data + sizeof(*txdesc));
1022 	m_freem(m);
1023 
1024 	/* send TX packet to the device */
1025 	MALO_WRITE_2(sc, MALO_REG_DATA_WRITE_LEN, psize);
1026 	if (psize & 0x0001) {
1027 		MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data,
1028 		    psize - 1);
1029 		data = (uint8_t *)sc->sc_data;
1030 		MALO_WRITE_1(sc, MALO_REG_DATA_WRITE, data[psize - 1]);
1031 	} else
1032 		MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data, psize);
1033 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_TX_DL_OVER);
1034 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_TX_DL_OVER);
1035 
1036 	ifq_set_oactive(&ifp->if_snd);
1037 	ifp->if_timer = 5;
1038 
1039 	DPRINTF(2, "%s: TX status=%d, pkglen=%d, pkgoffset=%d\n",
1040 	    sc->sc_dev.dv_xname, txdesc->status, letoh16(txdesc->pkglen),
1041 	    sizeof(*txdesc));
1042 
1043 	return (0);
1044 }
1045 
1046 void
cmalo_tx_done(struct malo_softc * sc)1047 cmalo_tx_done(struct malo_softc *sc)
1048 {
1049 	struct ifnet *ifp = &sc->sc_ic.ic_if;
1050 
1051 	splassert(IPL_NET);
1052 
1053 	DPRINTF(2, "%s: TX done\n", sc->sc_dev.dv_xname);
1054 
1055 	ifq_clr_oactive(&ifp->if_snd);
1056 	ifp->if_timer = 0;
1057 	cmalo_start(ifp);
1058 }
1059 
1060 void
cmalo_event(struct malo_softc * sc)1061 cmalo_event(struct malo_softc *sc)
1062 {
1063 	uint16_t event;
1064 
1065 	/* read event reason */
1066 	event = MALO_READ_2(sc, MALO_REG_CARD_STATUS);
1067 	event &= MALO_VAL_CARD_STATUS_MASK;
1068 	event = event >> 8;
1069 
1070 	switch (event) {
1071 	case MALO_EVENT_DEAUTH:
1072 		DPRINTF(1, "%s: got deauthentication event (0x%04x)\n",
1073 		    sc->sc_dev.dv_xname, event);
1074 		/* try to associate again */
1075 		cmalo_cmd_set_assoc(sc);
1076 		break;
1077 	case MALO_EVENT_DISASSOC:
1078 		DPRINTF(1, "%s: got disassociation event (0x%04x)\n",
1079 		    sc->sc_dev.dv_xname, event);
1080 		/* try to associate again */
1081 		cmalo_cmd_set_assoc(sc);
1082 		break;
1083 	default:
1084 		DPRINTF(1, "%s: got unknown event (0x%04x)\n",
1085 		    sc->sc_dev.dv_xname, event);
1086 		break;
1087 	}
1088 
1089 	/* acknowledge event */
1090 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_HOST_INTR_EVENT);
1091 }
1092 
1093 void
cmalo_select_network(struct malo_softc * sc)1094 cmalo_select_network(struct malo_softc *sc)
1095 {
1096 	struct ieee80211com *ic = &sc->sc_ic;
1097 	int i, best_rssi;
1098 
1099 	/* reset last selected network */
1100 	sc->sc_net_cur = 0;
1101 
1102 	/* get desired network */
1103 	if (ic->ic_des_esslen) {
1104 		for (i = 0; i < sc->sc_net_num; i++) {
1105 			if (!strcmp(ic->ic_des_essid, sc->sc_net[i].ssid)) {
1106 				sc->sc_net_cur = i;
1107 				DPRINTF(1, "%s: desired network found (%s)\n",
1108 				    sc->sc_dev.dv_xname, ic->ic_des_essid);
1109 				return;
1110 			}
1111 		}
1112 		DPRINTF(1, "%s: desired network not found in scan results "
1113 		    "(%s)\n",
1114 		    sc->sc_dev.dv_xname, ic->ic_des_essid);
1115 	}
1116 
1117 	/* get network with best signal strength */
1118 	best_rssi = sc->sc_net[0].rssi;
1119 	for (i = 0; i < sc->sc_net_num; i++) {
1120 		if (best_rssi < sc->sc_net[i].rssi) {
1121 			best_rssi = sc->sc_net[i].rssi;
1122 			sc->sc_net_cur = i;
1123 		}
1124 	}
1125 	DPRINTF(1, "%s: best network found (%s)\n",
1126 	    sc->sc_dev.dv_xname, sc->sc_net[sc->sc_net_cur].ssid);
1127 }
1128 
1129 void
cmalo_reflect_network(struct malo_softc * sc)1130 cmalo_reflect_network(struct malo_softc *sc)
1131 {
1132 	struct ieee80211com *ic = &sc->sc_ic;
1133 	uint8_t chan;
1134 
1135 	/* reflect active network to our 80211 stack */
1136 
1137 	/* BSSID */
1138 	IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid,
1139 	    sc->sc_net[sc->sc_net_cur].bssid);
1140 
1141 	/* SSID */
1142 	ic->ic_bss->ni_esslen = strlen(sc->sc_net[sc->sc_net_cur].ssid);
1143 	bcopy(sc->sc_net[sc->sc_net_cur].ssid, ic->ic_bss->ni_essid,
1144 	    ic->ic_bss->ni_esslen);
1145 
1146 	/* channel */
1147 	chan = sc->sc_net[sc->sc_net_cur].channel;
1148 	ic->ic_bss->ni_chan = &ic->ic_channels[chan];
1149 }
1150 
1151 int
cmalo_wep(struct malo_softc * sc)1152 cmalo_wep(struct malo_softc *sc)
1153 {
1154 	struct ieee80211com *ic = &sc->sc_ic;
1155 	int i;
1156 
1157 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1158 		struct ieee80211_key *key = &ic->ic_nw_keys[i];
1159 
1160 		if (!key->k_len)
1161 			continue;
1162 
1163 		DPRINTF(1, "%s: setting wep key for index %d\n",
1164 		    sc->sc_dev.dv_xname, i);
1165 
1166 		cmalo_cmd_set_wep(sc, i, key);
1167 	}
1168 
1169 	return (0);
1170 }
1171 
1172 int
cmalo_rate2bitmap(int rate)1173 cmalo_rate2bitmap(int rate)
1174 {
1175 	switch (rate) {
1176 	/* CCK rates */
1177 	case  0:	return (MALO_RATE_BITMAP_DS1);
1178 	case  1:	return (MALO_RATE_BITMAP_DS2);
1179 	case  2:	return (MALO_RATE_BITMAP_DS5);
1180 	case  3:	return (MALO_RATE_BITMAP_DS11);
1181 
1182 	/* OFDM rates */
1183 	case  4:	return (MALO_RATE_BITMAP_OFDM6);
1184 	case  5:	return (MALO_RATE_BITMAP_OFDM9);
1185 	case  6:	return (MALO_RATE_BITMAP_OFDM12);
1186 	case  7:	return (MALO_RATE_BITMAP_OFDM18);
1187 	case  8:	return (MALO_RATE_BITMAP_OFDM24);
1188 	case  9:	return (MALO_RATE_BITMAP_OFDM36);
1189 	case 10:	return (MALO_RATE_BITMAP_OFDM48);
1190 	case 11:	return (MALO_RATE_BITMAP_OFDM54);
1191 
1192 	/* unknown rate: should not happen */
1193 	default:	return (0);
1194 	}
1195 }
1196 
1197 void
cmalo_hexdump(void * buf,int len)1198 cmalo_hexdump(void *buf, int len)
1199 {
1200 #ifdef CMALO_DEBUG
1201 	int i;
1202 
1203 	if (cmalo_d >= 2) {
1204 		for (i = 0; i < len; i++) {
1205 			if (i % 16 == 0)
1206 				printf("%s%5i:", i ? "\n" : "", i);
1207 			if (i % 4 == 0)
1208 				printf(" ");
1209 			printf("%02x", (int)*((u_char *)buf + i));
1210 		}
1211 		printf("\n");
1212 	}
1213 #endif
1214 }
1215 
1216 int
cmalo_cmd_get_hwspec(struct malo_softc * sc)1217 cmalo_cmd_get_hwspec(struct malo_softc *sc)
1218 {
1219 	struct malo_cmd_header *hdr = sc->sc_cmd;
1220 	struct malo_cmd_body_spec *body;
1221 	uint16_t psize;
1222 
1223 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1224 	psize = sizeof(*hdr) + sizeof(*body);
1225 
1226 	hdr->cmd = htole16(MALO_CMD_HWSPEC);
1227 	hdr->size = htole16(sizeof(*body));
1228 	hdr->seqnum = htole16(1);
1229 	hdr->result = 0;
1230 	body = (struct malo_cmd_body_spec *)(hdr + 1);
1231 
1232 	/* set all bits for MAC address, otherwise we won't get one back */
1233 	memset(body->macaddr, 0xff, ETHER_ADDR_LEN);
1234 
1235 	/* process command request */
1236 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1237 		return (EIO);
1238 
1239 	/* process command response */
1240 	cmalo_cmd_response(sc);
1241 
1242 	return (0);
1243 }
1244 
1245 int
cmalo_cmd_rsp_hwspec(struct malo_softc * sc)1246 cmalo_cmd_rsp_hwspec(struct malo_softc *sc)
1247 {
1248 	struct ieee80211com *ic = &sc->sc_ic;
1249 	struct malo_cmd_header *hdr = sc->sc_cmd;
1250 	struct malo_cmd_body_spec *body;
1251 	int i;
1252 
1253 	body = (struct malo_cmd_body_spec *)(hdr + 1);
1254 
1255 	/* get our MAC address */
1256 	for (i = 0; i < ETHER_ADDR_LEN; i++)
1257 		ic->ic_myaddr[i] = body->macaddr[i];
1258 
1259 	return (0);
1260 }
1261 
1262 int
cmalo_cmd_set_reset(struct malo_softc * sc)1263 cmalo_cmd_set_reset(struct malo_softc *sc)
1264 {
1265 	struct malo_cmd_header *hdr = sc->sc_cmd;
1266 	uint16_t psize;
1267 
1268 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1269 	psize = sizeof(*hdr);
1270 
1271 	hdr->cmd = htole16(MALO_CMD_RESET);
1272 	hdr->size = 0;
1273 	hdr->seqnum = htole16(1);
1274 	hdr->result = 0;
1275 
1276 	/* process command request */
1277 	if (cmalo_cmd_request(sc, psize, 1) != 0)
1278 		return (EIO);
1279 
1280 	/* give the device some time to finish the reset */
1281 	delay(100);
1282 
1283 	return (0);
1284 }
1285 
1286 int
cmalo_cmd_set_scan(struct malo_softc * sc)1287 cmalo_cmd_set_scan(struct malo_softc *sc)
1288 {
1289 	struct ieee80211com *ic = &sc->sc_ic;
1290 	struct malo_cmd_header *hdr = sc->sc_cmd;
1291 	struct malo_cmd_body_scan *body;
1292 	struct malo_cmd_tlv_ssid *body_ssid;
1293 	struct malo_cmd_tlv_chanlist *body_chanlist;
1294 	struct malo_cmd_tlv_rates *body_rates;
1295 	//struct malo_cmd_tlv_numprobes *body_numprobes;
1296 	uint16_t psize;
1297 	int i;
1298 
1299 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1300 	psize = sizeof(*hdr) + sizeof(*body);
1301 
1302 	hdr->cmd = htole16(MALO_CMD_SCAN);
1303 	hdr->seqnum = htole16(1);
1304 	hdr->result = 0;
1305 	body = (struct malo_cmd_body_scan *)(hdr + 1);
1306 
1307 	body->bsstype = 0x03; /* any BSS */
1308 	memset(body->bssid, 0xff, ETHER_ADDR_LEN);
1309 
1310 	body_ssid = sc->sc_cmd + psize;
1311 	body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1312 	body_ssid->size = htole16(0);
1313 	psize += (sizeof(*body_ssid) - 1);
1314 
1315 	body_chanlist = sc->sc_cmd + psize;
1316 	body_chanlist->type = htole16(MALO_TLV_TYPE_CHANLIST);
1317 	body_chanlist->size = htole16(sizeof(body_chanlist->data));
1318 	for (i = 0; i < CHANNELS; i++) {
1319 		body_chanlist->data[i].radiotype = 0x00;
1320 		body_chanlist->data[i].channumber = (i + 1);
1321 		body_chanlist->data[i].scantype = 0x00; /* active */
1322 		body_chanlist->data[i].minscantime = htole16(0);
1323 		body_chanlist->data[i].maxscantime = htole16(100);
1324 	}
1325 	psize += sizeof(*body_chanlist);
1326 
1327 	body_rates = sc->sc_cmd + psize;
1328 	body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1329 	body_rates->size =
1330 	    htole16(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1331 	bcopy(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates, body_rates->data,
1332 	    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1333 	psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1334 #if 0
1335 	body_numprobes = sc->sc_cmd + psize;
1336 	body_numprobes->type = htole16(MALO_TLV_TYPE_NUMPROBES);
1337 	body_numprobes->size = htole16(2);
1338 	body_numprobes->numprobes = htole16(1);
1339 	psize += sizeof(*body_numprobes);
1340 #endif
1341 	hdr->size = htole16(psize - sizeof(*hdr));
1342 
1343 	/* process command request */
1344 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1345 		return (EIO);
1346 
1347 	/* process command response */
1348 	cmalo_cmd_response(sc);
1349 
1350 	return (0);
1351 }
1352 
1353 int
cmalo_cmd_rsp_scan(struct malo_softc * sc)1354 cmalo_cmd_rsp_scan(struct malo_softc *sc)
1355 {
1356 	struct malo_cmd_header *hdr = sc->sc_cmd;
1357 	struct malo_cmd_body_rsp_scan *body;
1358 	struct malo_cmd_body_rsp_scan_set *set;
1359 	uint16_t psize;
1360 	int i;
1361 
1362 	bzero(sc->sc_net, sizeof(sc->sc_net));
1363 	psize = sizeof(*hdr) + sizeof(*body);
1364 
1365 	body = (struct malo_cmd_body_rsp_scan *)(hdr + 1);
1366 
1367 	body->bufsize = letoh16(body->bufsize);
1368 
1369 	DPRINTF(1, "bufsize=%d, APs=%d\n", body->bufsize, body->numofset);
1370 	sc->sc_net_num = body->numofset;
1371 
1372 	/* cycle through found networks */
1373 	for (i = 0; i < body->numofset; i++) {
1374 		set = (struct malo_cmd_body_rsp_scan_set *)(sc->sc_cmd + psize);
1375 
1376 		set->size = letoh16(set->size);
1377 		set->beaconintvl = letoh16(set->beaconintvl);
1378 		set->capinfo = letoh16(set->capinfo);
1379 
1380 		DPRINTF(1, "size=%d, bssid=%s, rssi=%d, beaconintvl=%d, "
1381 		    "capinfo=0x%04x\n",
1382 		    set->size, ether_sprintf(set->bssid), set->rssi,
1383 		    set->beaconintvl, set->capinfo);
1384 
1385 		/* save scan results */
1386 		bcopy(set->bssid, sc->sc_net[i].bssid, sizeof(set->bssid));
1387 		bcopy(set->timestamp, sc->sc_net[i].timestamp,
1388 		    sizeof(set->timestamp));
1389 		sc->sc_net[i].rssi = set->rssi;
1390 		sc->sc_net[i].beaconintvl = set->beaconintvl;
1391 		sc->sc_net[i].capinfo = set->capinfo;
1392 		cmalo_parse_elements(sc, (set + 1),
1393 		    set->size - (sizeof(*set) - sizeof(set->size)), i);
1394 
1395 		psize += (set->size + sizeof(set->size));
1396 	}
1397 
1398 	return (0);
1399 }
1400 
1401 int
cmalo_parse_elements(struct malo_softc * sc,void * buf,int size,int pos)1402 cmalo_parse_elements(struct malo_softc *sc, void *buf, int size, int pos)
1403 {
1404 	uint8_t eid, len;
1405 	int i;
1406 
1407 	DPRINTF(2, "element_size=%d, element_pos=%d\n", size, pos);
1408 
1409 	for (i = 0; i < size; ) {
1410 		eid = *(uint8_t *)(buf + i);
1411 		i++;
1412 		len = *(uint8_t *)(buf + i);
1413 		i++;
1414 		DPRINTF(2, "eid=%d, len=%d, ", eid, len);
1415 
1416 		switch (eid) {
1417 		case IEEE80211_ELEMID_SSID:
1418 			bcopy(buf + i, sc->sc_net[pos].ssid, len);
1419 			DPRINTF(2, "ssid=%s\n", sc->sc_net[pos].ssid);
1420 			break;
1421 		case IEEE80211_ELEMID_RATES:
1422 			bcopy(buf + i, sc->sc_net[pos].rates, len);
1423 			DPRINTF(2, "rates\n");
1424 			break;
1425 		case IEEE80211_ELEMID_DSPARMS:
1426 			sc->sc_net[pos].channel = *(uint8_t *)(buf + i);
1427 			DPRINTF(2, "chnl=%d\n", sc->sc_net[pos].channel);
1428 			break;
1429 		default:
1430 			DPRINTF(2, "unknown\n");
1431 			break;
1432 		}
1433 
1434 		i += len;
1435 	}
1436 
1437 	return (0);
1438 }
1439 
1440 int
cmalo_cmd_set_auth(struct malo_softc * sc)1441 cmalo_cmd_set_auth(struct malo_softc *sc)
1442 {
1443 	struct malo_cmd_header *hdr = sc->sc_cmd;
1444 	struct malo_cmd_body_auth *body;
1445 	uint16_t psize;
1446 
1447 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1448 	psize = sizeof(*hdr) + sizeof(*body);
1449 
1450 	hdr->cmd = htole16(MALO_CMD_AUTH);
1451 	hdr->size = htole16(sizeof(*body));
1452 	hdr->seqnum = htole16(1);
1453 	hdr->result = 0;
1454 	body = (struct malo_cmd_body_auth *)(hdr + 1);
1455 
1456 	bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1457 	body->authtype = 0;
1458 
1459 	/* process command request */
1460 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1461 		return (EIO);
1462 
1463 	/* process command response */
1464 	cmalo_cmd_response(sc);
1465 
1466 	return (0);
1467 }
1468 
1469 int
cmalo_cmd_set_wep(struct malo_softc * sc,uint16_t index,struct ieee80211_key * key)1470 cmalo_cmd_set_wep(struct malo_softc *sc, uint16_t index,
1471     struct ieee80211_key *key)
1472 {
1473 	struct malo_cmd_header *hdr = sc->sc_cmd;
1474 	struct malo_cmd_body_wep *body;
1475 	uint16_t psize;
1476 
1477 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1478 	psize = sizeof(*hdr) + sizeof(*body);
1479 
1480 	hdr->cmd = htole16(MALO_CMD_WEP);
1481 	hdr->size = htole16(sizeof(*body));
1482 	hdr->seqnum = htole16(1);
1483 	hdr->result = 0;
1484 	body = (struct malo_cmd_body_wep *)(hdr + 1);
1485 
1486 	body->action = htole16(MALO_WEP_ACTION_TYPE_ADD);
1487 	body->key_index = htole16(index);
1488 
1489 	if (body->key_index == 0) {
1490 		if (key->k_len > 5)
1491 			body->key_type_1 = MALO_WEP_KEY_TYPE_104BIT;
1492 		else
1493 			body->key_type_1 = MALO_WEP_KEY_TYPE_40BIT;
1494 		bcopy(key->k_key, body->key_value_1, key->k_len);
1495 	}
1496 	if (body->key_index == 1) {
1497 		if (key->k_len > 5)
1498 			body->key_type_2 = MALO_WEP_KEY_TYPE_104BIT;
1499 		else
1500 			body->key_type_2 = MALO_WEP_KEY_TYPE_40BIT;
1501 		bcopy(key->k_key, body->key_value_2, key->k_len);
1502 	}
1503 	if (body->key_index == 2) {
1504 		if (key->k_len > 5)
1505 			body->key_type_3 = MALO_WEP_KEY_TYPE_104BIT;
1506 		else
1507 			body->key_type_3 = MALO_WEP_KEY_TYPE_40BIT;
1508 		bcopy(key->k_key, body->key_value_3, key->k_len);
1509 	}
1510 	if (body->key_index == 3) {
1511 		if (key->k_len > 5)
1512 			body->key_type_4 = MALO_WEP_KEY_TYPE_104BIT;
1513 		else
1514 			body->key_type_4 = MALO_WEP_KEY_TYPE_40BIT;
1515 		bcopy(key->k_key, body->key_value_4, key->k_len);
1516 	}
1517 
1518 	/* process command request */
1519 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1520 		return (EIO);
1521 
1522 	/* process command response */
1523 	cmalo_cmd_response(sc);
1524 
1525 	return (0);
1526 }
1527 
1528 int
cmalo_cmd_set_snmp(struct malo_softc * sc,uint16_t oid)1529 cmalo_cmd_set_snmp(struct malo_softc *sc, uint16_t oid)
1530 {
1531 	struct malo_cmd_header *hdr = sc->sc_cmd;
1532 	struct malo_cmd_body_snmp *body;
1533 	uint16_t psize;
1534 
1535 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1536 	psize = sizeof(*hdr) + sizeof(*body);
1537 
1538 	hdr->cmd = htole16(MALO_CMD_SNMP);
1539 	hdr->size = htole16(sizeof(*body));
1540 	hdr->seqnum = htole16(1);
1541 	hdr->result = 0;
1542 	body = (struct malo_cmd_body_snmp *)(hdr + 1);
1543 
1544 	body->action = htole16(1);
1545 
1546 	switch (oid) {
1547 	case MALO_OID_RTSTRESH:
1548 		body->oid = htole16(MALO_OID_RTSTRESH);
1549 		body->size = htole16(2);
1550 		*(uint16_t *)body->data = htole16(2347);
1551 		break;
1552 	case MALO_OID_SHORTRETRY:
1553 		body->oid = htole16(MALO_OID_SHORTRETRY);
1554 		body->size = htole16(2);
1555 		*(uint16_t *)body->data = htole16(4);
1556 		break;
1557 	case MALO_OID_FRAGTRESH:
1558 		body->oid = htole16(MALO_OID_FRAGTRESH);
1559 		body->size = htole16(2);
1560 		*(uint16_t *)body->data = htole16(2346);
1561 		break;
1562 	case MALO_OID_80211D:
1563 		body->oid = htole16(MALO_OID_80211D);
1564 		body->size = htole16(2);
1565 		*(uint16_t *)body->data = htole16(1);
1566 		break;
1567 	default:
1568 		break;
1569 	}
1570 
1571 	/* process command request */
1572 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1573 		return (EIO);
1574 
1575 	/* process command response */
1576 	cmalo_cmd_response(sc);
1577 
1578 	return (0);
1579 }
1580 
1581 int
cmalo_cmd_set_radio(struct malo_softc * sc,uint16_t control)1582 cmalo_cmd_set_radio(struct malo_softc *sc, uint16_t control)
1583 {
1584 	struct malo_cmd_header *hdr = sc->sc_cmd;
1585 	struct malo_cmd_body_radio *body;
1586 	uint16_t psize;
1587 
1588 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1589 	psize = sizeof(*hdr) + sizeof(*body);
1590 
1591 	hdr->cmd = htole16(MALO_CMD_RADIO);
1592 	hdr->size = htole16(sizeof(*body));
1593 	hdr->seqnum = htole16(1);
1594 	hdr->result = 0;
1595 	body = (struct malo_cmd_body_radio *)(hdr + 1);
1596 
1597 	body->action = htole16(1);
1598 
1599 	if (control) {
1600 		body->control  = htole16(MALO_CMD_RADIO_ON);
1601 		body->control |= htole16(MALO_CMD_RADIO_AUTO_P);
1602 	}
1603 
1604 	/* process command request */
1605 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1606 		return (EIO);
1607 
1608 	/* process command response */
1609 	cmalo_cmd_response(sc);
1610 
1611 	return (0);
1612 }
1613 
1614 int
cmalo_cmd_set_channel(struct malo_softc * sc,uint16_t channel)1615 cmalo_cmd_set_channel(struct malo_softc *sc, uint16_t channel)
1616 {
1617 	struct malo_cmd_header *hdr = sc->sc_cmd;
1618 	struct malo_cmd_body_channel *body;
1619 	uint16_t psize;
1620 
1621 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1622 	psize = sizeof(*hdr) + sizeof(*body);
1623 
1624 	hdr->cmd = htole16(MALO_CMD_CHANNEL);
1625 	hdr->size = htole16(sizeof(*body));
1626 	hdr->seqnum = htole16(1);
1627 	hdr->result = 0;
1628 	body = (struct malo_cmd_body_channel *)(hdr + 1);
1629 
1630 	body->action = htole16(1);
1631 	body->channel = htole16(channel);
1632 
1633 	/* process command request */
1634 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1635 		return (EIO);
1636 
1637 	/* process command response */
1638 	cmalo_cmd_response(sc);
1639 
1640 	return (0);
1641 }
1642 
1643 
1644 int
cmalo_cmd_set_txpower(struct malo_softc * sc,int16_t txpower)1645 cmalo_cmd_set_txpower(struct malo_softc *sc, int16_t txpower)
1646 {
1647 	struct malo_cmd_header *hdr = sc->sc_cmd;
1648 	struct malo_cmd_body_txpower *body;
1649 	uint16_t psize;
1650 
1651 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1652 	psize = sizeof(*hdr) + sizeof(*body);
1653 
1654 	hdr->cmd = htole16(MALO_CMD_TXPOWER);
1655 	hdr->size = htole16(sizeof(*body));
1656 	hdr->seqnum = htole16(1);
1657 	hdr->result = 0;
1658 	body = (struct malo_cmd_body_txpower *)(hdr + 1);
1659 
1660 	body->action = htole16(1);
1661 	body->txpower = htole16(txpower);
1662 
1663 	/* process command request */
1664 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1665 		return (EIO);
1666 
1667 	/* process command response */
1668 	cmalo_cmd_response(sc);
1669 
1670 	return (0);
1671 }
1672 
1673 int
cmalo_cmd_set_antenna(struct malo_softc * sc,uint16_t action)1674 cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action)
1675 {
1676 	struct malo_cmd_header *hdr = sc->sc_cmd;
1677 	struct malo_cmd_body_antenna *body;
1678 	uint16_t psize;
1679 
1680 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1681 	psize = sizeof(*hdr) + sizeof(*body);
1682 
1683 	hdr->cmd = htole16(MALO_CMD_ANTENNA);
1684 	hdr->size = htole16(sizeof(*body));
1685 	hdr->seqnum = htole16(1);
1686 	hdr->result = 0;
1687 	body = (struct malo_cmd_body_antenna *)(hdr + 1);
1688 
1689 	/* 1 = set RX, 2 = set TX */
1690 	body->action = htole16(action);
1691 
1692 	if (action == 1)
1693 		/* set RX antenna */
1694 		body->antenna_mode = htole16(0xffff);
1695 	if (action == 2)
1696 		/* set TX antenna */
1697 		body->antenna_mode = htole16(2);
1698 
1699 	/* process command request */
1700 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1701 		return (EIO);
1702 
1703 	/* process command response */
1704 	cmalo_cmd_response(sc);
1705 
1706 	return (0);
1707 }
1708 
1709 int
cmalo_cmd_set_macctrl(struct malo_softc * sc)1710 cmalo_cmd_set_macctrl(struct malo_softc *sc)
1711 {
1712 	struct ieee80211com *ic = &sc->sc_ic;
1713 	struct malo_cmd_header *hdr = sc->sc_cmd;
1714 	struct malo_cmd_body_macctrl *body;
1715 	uint16_t psize;
1716 
1717 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1718 	psize = sizeof(*hdr) + sizeof(*body);
1719 
1720 	hdr->cmd = htole16(MALO_CMD_MACCTRL);
1721 	hdr->size = htole16(sizeof(*body));
1722 	hdr->seqnum = htole16(1);
1723 	hdr->result = 0;
1724 	body = (struct malo_cmd_body_macctrl *)(hdr + 1);
1725 
1726 	body->action  = htole16(MALO_CMD_MACCTRL_RX_ON);
1727 	body->action |= htole16(MALO_CMD_MACCTRL_TX_ON);
1728 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
1729 		body->action |= htole16(MALO_CMD_MACCTRL_PROMISC_ON);
1730 
1731 	/* process command request */
1732 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1733 		return (EIO);
1734 
1735 	/* process command response */
1736 	cmalo_cmd_response(sc);
1737 
1738 	return (0);
1739 }
1740 
1741 int
cmalo_cmd_set_macaddr(struct malo_softc * sc,uint8_t * macaddr)1742 cmalo_cmd_set_macaddr(struct malo_softc *sc, uint8_t *macaddr)
1743 {
1744 	struct malo_cmd_header *hdr = sc->sc_cmd;
1745 	struct malo_cmd_body_macaddr *body;
1746 	uint16_t psize;
1747 
1748 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1749 	psize = sizeof(*hdr) + sizeof(*body);
1750 
1751 	hdr->cmd = htole16(MALO_CMD_MACADDR);
1752 	hdr->size = htole16(sizeof(*body));
1753 	hdr->seqnum = htole16(1);
1754 	hdr->result = 0;
1755 	body = (struct malo_cmd_body_macaddr *)(hdr + 1);
1756 
1757 	body->action = htole16(1);
1758 	bcopy(macaddr, body->macaddr, ETHER_ADDR_LEN);
1759 
1760 	/* process command request */
1761 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1762 		return (EIO);
1763 
1764 	/* process command response */
1765 	cmalo_cmd_response(sc);
1766 
1767 	return (0);
1768 }
1769 
1770 int
cmalo_cmd_set_assoc(struct malo_softc * sc)1771 cmalo_cmd_set_assoc(struct malo_softc *sc)
1772 {
1773 	struct malo_cmd_header *hdr = sc->sc_cmd;
1774 	struct malo_cmd_body_assoc *body;
1775 	struct malo_cmd_tlv_ssid *body_ssid;
1776 	struct malo_cmd_tlv_phy *body_phy;
1777 	struct malo_cmd_tlv_cf *body_cf;
1778 	struct malo_cmd_tlv_rates *body_rates;
1779 	struct malo_cmd_tlv_passeid *body_passeid;
1780 	uint16_t psize;
1781 
1782 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1783 	psize = sizeof(*hdr) + sizeof(*body);
1784 
1785 	hdr->cmd = htole16(MALO_CMD_ASSOC);
1786 	hdr->seqnum = htole16(1);
1787 	hdr->result = 0;
1788 	body = (struct malo_cmd_body_assoc *)(hdr + 1);
1789 
1790 	bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1791 	body->capinfo = htole16(sc->sc_net[sc->sc_net_cur].capinfo);
1792 	body->listenintrv = htole16(10);
1793 
1794 	body_ssid = sc->sc_cmd + psize;
1795 	body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1796 	body_ssid->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].ssid));
1797 	bcopy(sc->sc_net[sc->sc_net_cur].ssid, body_ssid->data,
1798 	    letoh16(body_ssid->size));
1799 	psize += (sizeof(*body_ssid) - 1) + letoh16(body_ssid->size);
1800 
1801 	body_phy = sc->sc_cmd + psize;
1802 	body_phy->type = htole16(MALO_TLV_TYPE_PHY);
1803 	body_phy->size = htole16(1);
1804 	bcopy(&sc->sc_net[sc->sc_net_cur].channel, body_phy->data, 1);
1805 	psize += sizeof(*body_phy);
1806 
1807 	body_cf = sc->sc_cmd + psize;
1808 	body_cf->type = htole16(MALO_TLV_TYPE_CF);
1809 	body_cf->size = htole16(0);
1810 	psize += (sizeof(*body_cf) - 1);
1811 
1812 	body_rates = sc->sc_cmd + psize;
1813 	body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1814 	body_rates->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].rates));
1815 	bcopy(sc->sc_net[sc->sc_net_cur].rates, body_rates->data,
1816 	    letoh16(body_rates->size));
1817 	psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1818 
1819 	/* hack to correct FW's wrong generated rates-element-id */
1820 	body_passeid = sc->sc_cmd + psize;
1821 	body_passeid->type = htole16(MALO_TLV_TYPE_PASSEID);
1822 	body_passeid->size = body_rates->size;
1823 	bcopy(body_rates->data, body_passeid->data, letoh16(body_rates->size));
1824 	psize += (sizeof(*body_passeid) - 1) + letoh16(body_passeid->size);
1825 
1826 	hdr->size = htole16(psize - sizeof(*hdr));
1827 
1828 	/* process command request */
1829 	if (!sc->sc_cmd_ctxsave) {
1830 		if (cmalo_cmd_request(sc, psize, 1) != 0)
1831 			return (EIO);
1832 		return (0);
1833 	}
1834 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1835 		return (EIO);
1836 
1837 	/* process command response */
1838 	cmalo_cmd_response(sc);
1839 
1840 	return (0);
1841 }
1842 
1843 int
cmalo_cmd_rsp_assoc(struct malo_softc * sc)1844 cmalo_cmd_rsp_assoc(struct malo_softc *sc)
1845 {
1846 	struct malo_cmd_header *hdr = sc->sc_cmd;
1847 	struct malo_cmd_body_rsp_assoc *body;
1848 
1849 	body = (struct malo_cmd_body_rsp_assoc *)(hdr + 1);
1850 
1851 	if (body->status) {
1852 		DPRINTF(1, "%s: association failed (status %d)\n",
1853 		    sc->sc_dev.dv_xname, body->status);
1854 		sc->sc_flags |= MALO_ASSOC_FAILED;
1855 	} else
1856 		DPRINTF(1, "%s: association successful\n",
1857 		    sc->sc_dev.dv_xname, body->status);
1858 
1859 	return (0);
1860 }
1861 
1862 int
cmalo_cmd_set_80211d(struct malo_softc * sc)1863 cmalo_cmd_set_80211d(struct malo_softc *sc)
1864 {
1865 	struct malo_cmd_header *hdr = sc->sc_cmd;
1866 	struct malo_cmd_body_80211d *body;
1867 	struct malo_cmd_tlv_80211d *body_80211d;
1868 	uint16_t psize;
1869 	int i;
1870 
1871 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1872 	psize = sizeof(*hdr) + sizeof(*body);
1873 
1874 	hdr->cmd = htole16(MALO_CMD_80211D);
1875 	hdr->seqnum = htole16(1);
1876 	hdr->result = 0;
1877 	body = (struct malo_cmd_body_80211d *)(hdr + 1);
1878 
1879 	body->action = htole16(1);
1880 
1881 	body_80211d = sc->sc_cmd + psize;
1882 	body_80211d->type = htole16(MALO_TLV_TYPE_80211D);
1883 	body_80211d->size = htole16(sizeof(body_80211d->data) +
1884 	    sizeof(body_80211d->countrycode));
1885 	bcopy("EU ", body_80211d->countrycode,
1886 	    sizeof(body_80211d->countrycode));
1887 	for (i = 0; i < CHANNELS; i++) {
1888 		body_80211d->data[i].firstchannel = 1;
1889 		body_80211d->data[i].numchannels = 12;
1890 		body_80211d->data[i].maxtxpower = 10;
1891 	}
1892 	psize += sizeof(*body_80211d);
1893 
1894 	hdr->size = htole16(psize - sizeof(*hdr));
1895 
1896 	/* process command request */
1897 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1898 		return (EIO);
1899 
1900 	/* process command response */
1901 	cmalo_cmd_response(sc);
1902 
1903 	return (0);
1904 }
1905 
1906 int
cmalo_cmd_set_bgscan_config(struct malo_softc * sc)1907 cmalo_cmd_set_bgscan_config(struct malo_softc *sc)
1908 {
1909 	struct malo_cmd_header *hdr = sc->sc_cmd;
1910 	struct malo_cmd_body_bgscan_config *body;
1911 	uint16_t psize;
1912 
1913 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1914 	psize = sizeof(*hdr) + sizeof(*body);
1915 
1916 	hdr->cmd = htole16(MALO_CMD_BGSCAN_CONFIG);
1917 	hdr->size = htole16(sizeof(*body));
1918 	hdr->seqnum = htole16(1);
1919 	hdr->result = 0;
1920 	body = (struct malo_cmd_body_bgscan_config *)(hdr + 1);
1921 
1922 	body->action = htole16(1);
1923 	body->enable = 1;
1924 	body->bsstype = 0x03;
1925 	body->chperscan = 12;
1926 	body->scanintvl = htole32(100);
1927 	body->maxscanres = htole16(12);
1928 
1929 	/* process command request */
1930 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1931 		return (EIO);
1932 
1933 	/* process command response */
1934 	cmalo_cmd_response(sc);
1935 
1936 	return (0);
1937 }
1938 
1939 int
cmalo_cmd_set_bgscan_query(struct malo_softc * sc)1940 cmalo_cmd_set_bgscan_query(struct malo_softc *sc)
1941 {
1942 	struct malo_cmd_header *hdr = sc->sc_cmd;
1943 	struct malo_cmd_body_bgscan_query *body;
1944 	uint16_t psize;
1945 
1946 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1947 	psize = sizeof(*hdr) + sizeof(*body);
1948 
1949 	hdr->cmd = htole16(MALO_CMD_BGSCAN_QUERY);
1950 	hdr->size = htole16(sizeof(*body));
1951 	hdr->seqnum = htole16(1);
1952 	hdr->result = 0;
1953 	body = (struct malo_cmd_body_bgscan_query *)(hdr + 1);
1954 
1955 	body->flush = 0;
1956 
1957 	/* process command request */
1958 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1959 		return (EIO);
1960 
1961 	/* process command response */
1962 	cmalo_cmd_response(sc);
1963 
1964 	return (0);
1965 }
1966 
1967 int
cmalo_cmd_set_rate(struct malo_softc * sc,int rate)1968 cmalo_cmd_set_rate(struct malo_softc *sc, int rate)
1969 {
1970 	struct malo_cmd_header *hdr = sc->sc_cmd;
1971 	struct malo_cmd_body_rate *body;
1972 	uint16_t psize;
1973 
1974 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1975 	psize = sizeof(*hdr) + sizeof(*body);
1976 
1977 	hdr->cmd = htole16(MALO_CMD_RATE);
1978 	hdr->size = htole16(sizeof(*body));
1979 	hdr->seqnum = htole16(1);
1980 	hdr->result = 0;
1981 	body = (struct malo_cmd_body_rate *)(hdr + 1);
1982 
1983 	body->action = htole16(1);
1984 	if (rate == -1) {
1985  		body->hwauto = htole16(1);
1986 		body->ratebitmap = htole16(MALO_RATE_BITMAP_AUTO);
1987 	} else {
1988  		body->hwauto = 0;
1989 		body->ratebitmap = htole16(cmalo_rate2bitmap(rate));
1990 	}
1991 
1992 	/* process command request */
1993 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1994 		return (EIO);
1995 
1996 	/* process command response */
1997 	cmalo_cmd_response(sc);
1998 
1999 	return (0);
2000 }
2001 
2002 int
cmalo_cmd_request(struct malo_softc * sc,uint16_t psize,int no_response)2003 cmalo_cmd_request(struct malo_softc *sc, uint16_t psize, int no_response)
2004 {
2005 	uint8_t *cmd;
2006 
2007 	cmalo_hexdump(sc->sc_cmd, psize);
2008 
2009 	/* send command request */
2010 	MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, psize);
2011 	if (psize & 0x0001) {
2012 		MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd,
2013 		    psize - 1);
2014 		cmd = (uint8_t *)sc->sc_cmd;
2015 		MALO_WRITE_1(sc, MALO_REG_CMD_WRITE, cmd[psize - 1]);
2016 	} else
2017 		MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd, psize);
2018 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
2019 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
2020 
2021 	if (no_response)
2022 		/* we don't expect a response */
2023 		return (0);
2024 
2025 	/* wait for the command response */
2026 	if (tsleep_nsec(sc, 0, "malocmd", SEC_TO_NSEC(5))) {
2027 		printf("%s: timeout while waiting for cmd response\n",
2028 		    sc->sc_dev.dv_xname);
2029 		return (EIO);
2030 	}
2031 
2032 	return (0);
2033 }
2034 
2035 int
cmalo_cmd_response(struct malo_softc * sc)2036 cmalo_cmd_response(struct malo_softc *sc)
2037 {
2038 	struct malo_cmd_header *hdr = sc->sc_cmd;
2039 	uint16_t psize;
2040 	uint8_t *cmd;
2041 	int s;
2042 
2043 	s = splnet();
2044 
2045 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
2046 
2047 	/* read the whole command response */
2048 	psize = MALO_READ_2(sc, MALO_REG_CMD_READ_LEN);
2049 	if (psize & 0x0001) {
2050 		MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd,
2051 		    psize - 1);
2052 		cmd = (uint8_t *)sc->sc_cmd;
2053 		cmd[psize - 1] = MALO_READ_1(sc, MALO_REG_CMD_READ);
2054 	} else
2055 		MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd, psize);
2056 
2057 	cmalo_hexdump(sc->sc_cmd, psize);
2058 
2059 	/*
2060 	 * We convert the header values into the machines correct endianness,
2061 	 * so we don't have to letoh16() all over the code.  The body is
2062 	 * kept in the cards order, little endian.  We need to take care
2063 	 * about the body endianness in the corresponding response routines.
2064 	 */
2065 	hdr->cmd = letoh16(hdr->cmd);
2066 	hdr->size = letoh16(hdr->size);
2067 	hdr->seqnum = letoh16(hdr->seqnum);
2068 	hdr->result = letoh16(hdr->result);
2069 
2070 	/* check for a valid command response */
2071 	if (!(hdr->cmd & MALO_CMD_RESP)) {
2072 		printf("%s: got invalid command response (0x%04x)\n",
2073 		    sc->sc_dev.dv_xname, hdr->cmd);
2074 		splx(s);
2075 		return (EIO);
2076 	}
2077 	hdr->cmd &= ~MALO_CMD_RESP;
2078 
2079 	/* association cmd response is special */
2080 	if (hdr->cmd == 0x0012)
2081 		hdr->cmd = MALO_CMD_ASSOC;
2082 
2083 	/* to which command does the response belong */
2084 	switch (hdr->cmd) {
2085 	case MALO_CMD_HWSPEC:
2086 		DPRINTF(1, "%s: got hwspec cmd response\n",
2087 		    sc->sc_dev.dv_xname);
2088 		cmalo_cmd_rsp_hwspec(sc);
2089 		break;
2090 	case MALO_CMD_RESET:
2091 		/* reset will not send back a response */
2092 		break;
2093 	case MALO_CMD_SCAN:
2094 		DPRINTF(1, "%s: got scan cmd response\n",
2095 		    sc->sc_dev.dv_xname);
2096 		cmalo_cmd_rsp_scan(sc);
2097 		break;
2098 	case MALO_CMD_AUTH:
2099 		/* do nothing */
2100 		DPRINTF(1, "%s: got auth cmd response\n",
2101 		    sc->sc_dev.dv_xname);
2102 		break;
2103 	case MALO_CMD_WEP:
2104 		/* do nothing */
2105 		DPRINTF(1, "%s: got wep cmd response\n",
2106 		    sc->sc_dev.dv_xname);
2107 		break;
2108 	case MALO_CMD_SNMP:
2109 		/* do nothing */
2110 		DPRINTF(1, "%s: got snmp cmd response\n",
2111 		    sc->sc_dev.dv_xname);
2112 		break;
2113 	case MALO_CMD_RADIO:
2114 		/* do nothing */
2115 		DPRINTF(1, "%s: got radio cmd response\n",
2116 		    sc->sc_dev.dv_xname);
2117 		break;
2118 	case MALO_CMD_CHANNEL:
2119 		/* do nothing */
2120 		DPRINTF(1, "%s: got channel cmd response\n",
2121 		    sc->sc_dev.dv_xname);
2122 		break;
2123 	case MALO_CMD_TXPOWER:
2124 		/* do nothing */
2125 		DPRINTF(1, "%s: got txpower cmd response\n",
2126 		    sc->sc_dev.dv_xname);
2127 		break;
2128 	case MALO_CMD_ANTENNA:
2129 		/* do nothing */
2130 		DPRINTF(1, "%s: got antenna cmd response\n",
2131 		    sc->sc_dev.dv_xname);
2132 		break;
2133 	case MALO_CMD_MACCTRL:
2134 		/* do nothing */
2135 		DPRINTF(1, "%s: got macctrl cmd response\n",
2136 		    sc->sc_dev.dv_xname);
2137 		break;
2138 	case MALO_CMD_MACADDR:
2139 		/* do nothing */
2140 		DPRINTF(1, "%s: got macaddr cmd response\n",
2141 		    sc->sc_dev.dv_xname);
2142 		break;
2143 	case MALO_CMD_ASSOC:
2144 		/* do nothing */
2145 		DPRINTF(1, "%s: got assoc cmd response\n",
2146 		    sc->sc_dev.dv_xname);
2147 		cmalo_cmd_rsp_assoc(sc);
2148 		break;
2149 	case MALO_CMD_80211D:
2150 		/* do nothing */
2151 		DPRINTF(1, "%s: got 80211d cmd response\n",
2152 		    sc->sc_dev.dv_xname);
2153 		break;
2154 	case MALO_CMD_BGSCAN_CONFIG:
2155 		/* do nothing */
2156 		DPRINTF(1, "%s: got bgscan config cmd response\n",
2157 		    sc->sc_dev.dv_xname);
2158 		break;
2159 	case MALO_CMD_BGSCAN_QUERY:
2160 		/* do nothing */
2161 		DPRINTF(1, "%s: got bgscan query cmd response\n",
2162 		    sc->sc_dev.dv_xname);
2163 		break;
2164 	case MALO_CMD_RATE:
2165 		/* do nothing */
2166 		DPRINTF(1, "%s: got rate cmd response\n",
2167 		    sc->sc_dev.dv_xname);
2168 		break;
2169 	default:
2170 		printf("%s: got unknown cmd response (0x%04x)\n",
2171 		    sc->sc_dev.dv_xname, hdr->cmd);
2172 		break;
2173 	}
2174 
2175 	splx(s);
2176 
2177 	return (0);
2178 }
2179