1*085ff963SMatthew Dillon /*-
2*085ff963SMatthew Dillon * Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd
3*085ff963SMatthew Dillon * All rights reserved.
4*085ff963SMatthew Dillon *
5*085ff963SMatthew Dillon * Redistribution and use in source and binary forms, with or without
6*085ff963SMatthew Dillon * modification, are permitted provided that the following conditions
7*085ff963SMatthew Dillon * are met:
8*085ff963SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
9*085ff963SMatthew Dillon * notice, this list of conditions and the following disclaimer.
10*085ff963SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
11*085ff963SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
12*085ff963SMatthew Dillon * documentation and/or other materials provided with the distribution.
13*085ff963SMatthew Dillon *
14*085ff963SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*085ff963SMatthew Dillon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*085ff963SMatthew Dillon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*085ff963SMatthew Dillon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*085ff963SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*085ff963SMatthew Dillon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*085ff963SMatthew Dillon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*085ff963SMatthew Dillon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*085ff963SMatthew Dillon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*085ff963SMatthew Dillon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*085ff963SMatthew Dillon */
25*085ff963SMatthew Dillon
26*085ff963SMatthew Dillon #include <sys/cdefs.h>
27*085ff963SMatthew Dillon #ifdef __FreeBSD__
28*085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
29*085ff963SMatthew Dillon #endif
30*085ff963SMatthew Dillon
31*085ff963SMatthew Dillon /*
32*085ff963SMatthew Dillon * net80211 fast-logging support, primarily for debugging.
33*085ff963SMatthew Dillon *
34*085ff963SMatthew Dillon * This implements a single debugging queue which includes
35*085ff963SMatthew Dillon * per-device enumeration where needed.
36*085ff963SMatthew Dillon */
37*085ff963SMatthew Dillon
38*085ff963SMatthew Dillon #include "opt_wlan.h"
39*085ff963SMatthew Dillon
40*085ff963SMatthew Dillon #include <sys/param.h>
41*085ff963SMatthew Dillon #include <sys/systm.h>
42*085ff963SMatthew Dillon #include <sys/mbuf.h>
43*085ff963SMatthew Dillon #include <sys/malloc.h>
44*085ff963SMatthew Dillon #include <sys/endian.h>
45*085ff963SMatthew Dillon #include <sys/kernel.h>
46*085ff963SMatthew Dillon #include <sys/sysctl.h>
47*085ff963SMatthew Dillon #include <sys/pcpu.h>
48*085ff963SMatthew Dillon #include <sys/proc.h>
49*085ff963SMatthew Dillon #include <sys/ucred.h>
50*085ff963SMatthew Dillon #include <sys/alq.h>
51*085ff963SMatthew Dillon
52*085ff963SMatthew Dillon #include <sys/socket.h>
53*085ff963SMatthew Dillon
54*085ff963SMatthew Dillon #include <net/if.h>
55*085ff963SMatthew Dillon #include <net/if_var.h>
56*085ff963SMatthew Dillon #include <net/if_media.h>
57*085ff963SMatthew Dillon #include <net/ethernet.h>
58*085ff963SMatthew Dillon
59*085ff963SMatthew Dillon #include <netproto/802_11/ieee80211_var.h>
60*085ff963SMatthew Dillon #include <netproto/802_11/ieee80211_freebsd.h>
61*085ff963SMatthew Dillon #include <netproto/802_11/ieee80211_alq.h>
62*085ff963SMatthew Dillon
63*085ff963SMatthew Dillon static struct alq *ieee80211_alq;
64*085ff963SMatthew Dillon static int ieee80211_alq_lost;
65*085ff963SMatthew Dillon static int ieee80211_alq_logged;
66*085ff963SMatthew Dillon static char ieee80211_alq_logfile[MAXPATHLEN] = "/tmp/net80211.log";
67*085ff963SMatthew Dillon static unsigned int ieee80211_alq_qsize = 64*1024;
68*085ff963SMatthew Dillon
69*085ff963SMatthew Dillon static int
ieee80211_alq_setlogging(int enable)70*085ff963SMatthew Dillon ieee80211_alq_setlogging(int enable)
71*085ff963SMatthew Dillon {
72*085ff963SMatthew Dillon int error;
73*085ff963SMatthew Dillon
74*085ff963SMatthew Dillon if (enable) {
75*085ff963SMatthew Dillon if (ieee80211_alq)
76*085ff963SMatthew Dillon alq_close(ieee80211_alq);
77*085ff963SMatthew Dillon
78*085ff963SMatthew Dillon error = alq_open(&ieee80211_alq,
79*085ff963SMatthew Dillon ieee80211_alq_logfile,
80*085ff963SMatthew Dillon curthread->td_ucred,
81*085ff963SMatthew Dillon ALQ_DEFAULT_CMODE,
82*085ff963SMatthew Dillon sizeof (struct ieee80211_alq_rec),
83*085ff963SMatthew Dillon ieee80211_alq_qsize);
84*085ff963SMatthew Dillon ieee80211_alq_lost = 0;
85*085ff963SMatthew Dillon ieee80211_alq_logged = 0;
86*085ff963SMatthew Dillon kprintf("net80211: logging to %s enabled; "
87*085ff963SMatthew Dillon "struct size %d bytes\n",
88*085ff963SMatthew Dillon ieee80211_alq_logfile,
89*085ff963SMatthew Dillon sizeof(struct ieee80211_alq_rec));
90*085ff963SMatthew Dillon } else {
91*085ff963SMatthew Dillon if (ieee80211_alq)
92*085ff963SMatthew Dillon alq_close(ieee80211_alq);
93*085ff963SMatthew Dillon ieee80211_alq = NULL;
94*085ff963SMatthew Dillon kprintf("net80211: logging disabled\n");
95*085ff963SMatthew Dillon error = 0;
96*085ff963SMatthew Dillon }
97*085ff963SMatthew Dillon return (error);
98*085ff963SMatthew Dillon }
99*085ff963SMatthew Dillon
100*085ff963SMatthew Dillon static int
sysctl_ieee80211_alq_log(SYSCTL_HANDLER_ARGS)101*085ff963SMatthew Dillon sysctl_ieee80211_alq_log(SYSCTL_HANDLER_ARGS)
102*085ff963SMatthew Dillon {
103*085ff963SMatthew Dillon int error, enable;
104*085ff963SMatthew Dillon
105*085ff963SMatthew Dillon enable = (ieee80211_alq != NULL);
106*085ff963SMatthew Dillon error = sysctl_handle_int(oidp, &enable, 0, req);
107*085ff963SMatthew Dillon if (error || !req->newptr)
108*085ff963SMatthew Dillon return (error);
109*085ff963SMatthew Dillon else
110*085ff963SMatthew Dillon return (ieee80211_alq_setlogging(enable));
111*085ff963SMatthew Dillon }
112*085ff963SMatthew Dillon
113*085ff963SMatthew Dillon SYSCTL_PROC(_net_wlan, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
114*085ff963SMatthew Dillon 0, 0, sysctl_ieee80211_alq_log, "I", "Enable net80211 alq logging");
115*085ff963SMatthew Dillon SYSCTL_INT(_net_wlan, OID_AUTO, alq_size, CTLFLAG_RW,
116*085ff963SMatthew Dillon &ieee80211_alq_qsize, 0, "In-memory log size (#records)");
117*085ff963SMatthew Dillon SYSCTL_INT(_net_wlan, OID_AUTO, alq_lost, CTLFLAG_RW,
118*085ff963SMatthew Dillon &ieee80211_alq_lost, 0, "Debugging operations not logged");
119*085ff963SMatthew Dillon SYSCTL_INT(_net_wlan, OID_AUTO, alq_logged, CTLFLAG_RW,
120*085ff963SMatthew Dillon &ieee80211_alq_logged, 0, "Debugging operations logged");
121*085ff963SMatthew Dillon
122*085ff963SMatthew Dillon static struct ale *
ieee80211_alq_get(void)123*085ff963SMatthew Dillon ieee80211_alq_get(void)
124*085ff963SMatthew Dillon {
125*085ff963SMatthew Dillon struct ale *ale;
126*085ff963SMatthew Dillon
127*085ff963SMatthew Dillon ale = alq_get(ieee80211_alq, ALQ_NOWAIT);
128*085ff963SMatthew Dillon if (!ale)
129*085ff963SMatthew Dillon ieee80211_alq_lost++;
130*085ff963SMatthew Dillon else
131*085ff963SMatthew Dillon ieee80211_alq_logged++;
132*085ff963SMatthew Dillon return ale;
133*085ff963SMatthew Dillon }
134*085ff963SMatthew Dillon
135*085ff963SMatthew Dillon void
ieee80211_alq_log(struct ieee80211vap * vap,uint8_t op,u_char * p,int l)136*085ff963SMatthew Dillon ieee80211_alq_log(struct ieee80211vap *vap, uint8_t op, u_char *p, int l)
137*085ff963SMatthew Dillon {
138*085ff963SMatthew Dillon struct ale *ale;
139*085ff963SMatthew Dillon struct ieee80211_alq_rec *r;
140*085ff963SMatthew Dillon
141*085ff963SMatthew Dillon if (ieee80211_alq == NULL)
142*085ff963SMatthew Dillon return;
143*085ff963SMatthew Dillon
144*085ff963SMatthew Dillon ale = ieee80211_alq_get();
145*085ff963SMatthew Dillon if (! ale)
146*085ff963SMatthew Dillon return;
147*085ff963SMatthew Dillon
148*085ff963SMatthew Dillon r = (struct ieee80211_alq_rec *) ale->ae_data;
149*085ff963SMatthew Dillon r->r_timestamp = htonl(ticks);
150*085ff963SMatthew Dillon r->r_version = 1;
151*085ff963SMatthew Dillon r->r_wlan = htons(vap->iv_ifp->if_dunit);
152*085ff963SMatthew Dillon r->r_op = op;
153*085ff963SMatthew Dillon r->r_threadid = htonl((uint32_t) curthread->td_tid);
154*085ff963SMatthew Dillon memcpy(&r->r_payload, p, MIN(l, sizeof(r->r_payload)));
155*085ff963SMatthew Dillon alq_post(ieee80211_alq, ale);
156*085ff963SMatthew Dillon }
157