1220908Sadrian/*-
2220908Sadrian * Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd
3220908Sadrian * All rights reserved.
4220908Sadrian *
5220908Sadrian * Redistribution and use in source and binary forms, with or without
6220908Sadrian * modification, are permitted provided that the following conditions
7220908Sadrian * are met:
8220908Sadrian * 1. Redistributions of source code must retain the above copyright
9220908Sadrian *    notice, this list of conditions and the following disclaimer.
10220908Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11220908Sadrian *    notice, this list of conditions and the following disclaimer in the
12220908Sadrian *    documentation and/or other materials provided with the distribution.
13220908Sadrian *
14220908Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15220908Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16220908Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17220908Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18220908Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19220908Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20220908Sadrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21220908Sadrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22220908Sadrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23220908Sadrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24220908Sadrian */
25220908Sadrian
26220908Sadrian#include <sys/cdefs.h>
27220908Sadrian#ifdef __FreeBSD__
28220908Sadrian__FBSDID("$FreeBSD$");
29220908Sadrian#endif
30220908Sadrian
31220908Sadrian/*
32220908Sadrian * net80211 fast-logging support, primarily for debugging.
33220908Sadrian *
34220908Sadrian * This implements a single debugging queue which includes
35220908Sadrian * per-device enumeration where needed.
36220908Sadrian */
37220908Sadrian
38220908Sadrian#include "opt_wlan.h"
39220908Sadrian
40220908Sadrian#include <sys/param.h>
41220908Sadrian#include <sys/systm.h>
42220908Sadrian#include <sys/mbuf.h>
43220908Sadrian#include <sys/malloc.h>
44220908Sadrian#include <sys/endian.h>
45220908Sadrian#include <sys/kernel.h>
46220908Sadrian#include <sys/sysctl.h>
47220908Sadrian#include <sys/pcpu.h>
48220908Sadrian#include <sys/proc.h>
49220908Sadrian#include <sys/ucred.h>
50220908Sadrian#include <sys/alq.h>
51220908Sadrian
52220908Sadrian#include <sys/socket.h>
53220908Sadrian
54220908Sadrian#include <net/if.h>
55220908Sadrian#include <net/if_var.h>
56220908Sadrian#include <net/if_dl.h>
57220908Sadrian#include <net/if_clone.h>
58220908Sadrian#include <net/if_media.h>
59220908Sadrian#include <net/if_types.h>
60220908Sadrian
61220908Sadrian#include <net80211/ieee80211_var.h>
62220908Sadrian#include <net80211/ieee80211_freebsd.h>
63220908Sadrian#include <net80211/ieee80211_alq.h>
64220908Sadrian
65220908Sadrianstatic struct alq *ieee80211_alq;
66220908Sadrianstatic int ieee80211_alq_lost;
67221781Sadrianstatic int ieee80211_alq_logged;
68221782Sadrianstatic char ieee80211_alq_logfile[MAXPATHLEN] = "/tmp/net80211.log";
69220908Sadrianstatic unsigned int ieee80211_alq_qsize = 64*1024;
70220908Sadrian
71220908Sadrianstatic int
72220908Sadrianieee80211_alq_setlogging(int enable)
73220908Sadrian{
74220908Sadrian	int error;
75220908Sadrian
76220908Sadrian	if (enable) {
77220908Sadrian		if (ieee80211_alq)
78220908Sadrian			alq_close(ieee80211_alq);
79220908Sadrian
80220908Sadrian		error = alq_open(&ieee80211_alq,
81220908Sadrian		    ieee80211_alq_logfile,
82220908Sadrian		    curthread->td_ucred,
83220908Sadrian		    ALQ_DEFAULT_CMODE,
84220908Sadrian		    sizeof (struct ieee80211_alq_rec),
85220908Sadrian		    ieee80211_alq_qsize);
86220908Sadrian		ieee80211_alq_lost = 0;
87221782Sadrian		ieee80211_alq_logged = 0;
88221782Sadrian		printf("net80211: logging to %s enabled; struct size %d bytes\n",
89221782Sadrian		    ieee80211_alq_logfile, sizeof(struct ieee80211_alq_rec));
90220908Sadrian	} else {
91220908Sadrian		if (ieee80211_alq)
92220908Sadrian			alq_close(ieee80211_alq);
93220908Sadrian		ieee80211_alq = NULL;
94220908Sadrian		printf("net80211: logging disabled\n");
95220908Sadrian		error = 0;
96220908Sadrian	}
97220908Sadrian	return (error);
98220908Sadrian}
99220908Sadrian
100220908Sadrianstatic int
101220908Sadriansysctl_ieee80211_alq_log(SYSCTL_HANDLER_ARGS)
102220908Sadrian{
103220908Sadrian        int error, enable;
104220908Sadrian
105220908Sadrian        enable = (ieee80211_alq != NULL);
106220908Sadrian        error = sysctl_handle_int(oidp, &enable, 0, req);
107220908Sadrian        if (error || !req->newptr)
108220908Sadrian                return (error);
109220908Sadrian        else
110220908Sadrian                return (ieee80211_alq_setlogging(enable));
111220908Sadrian}
112220908Sadrian
113220908SadrianSYSCTL_PROC(_net_wlan, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
114220908Sadrian	0, 0, sysctl_ieee80211_alq_log, "I", "Enable net80211 alq logging");
115220908SadrianSYSCTL_INT(_net_wlan, OID_AUTO, alq_size, CTLFLAG_RW,
116220908Sadrian	&ieee80211_alq_qsize, 0, "In-memory log size (#records)");
117220908SadrianSYSCTL_INT(_net_wlan, OID_AUTO, alq_lost, CTLFLAG_RW,
118220908Sadrian	&ieee80211_alq_lost, 0, "Debugging operations not logged");
119221781SadrianSYSCTL_INT(_net_wlan, OID_AUTO, alq_logged, CTLFLAG_RW,
120221781Sadrian	&ieee80211_alq_logged, 0, "Debugging operations logged");
121220908Sadrian
122220908Sadrianstatic struct ale *
123220908Sadrianieee80211_alq_get(void)
124220908Sadrian{
125220908Sadrian	struct ale *ale;
126220908Sadrian
127220908Sadrian	ale = alq_get(ieee80211_alq, ALQ_NOWAIT);
128220908Sadrian	if (!ale)
129220908Sadrian		ieee80211_alq_lost++;
130221781Sadrian	else
131221781Sadrian		ieee80211_alq_logged++;
132220908Sadrian	return ale;
133220908Sadrian}
134220908Sadrian
135220908Sadrianvoid
136220908Sadrianieee80211_alq_log(struct ieee80211vap *vap, uint8_t op, u_char *p, int l)
137220908Sadrian{
138220908Sadrian	struct ale *ale;
139220908Sadrian	struct ieee80211_alq_rec *r;
140220908Sadrian
141221781Sadrian	if (ieee80211_alq == NULL)
142221781Sadrian		return;
143221781Sadrian
144220908Sadrian	ale = ieee80211_alq_get();
145220908Sadrian	if (! ale)
146220908Sadrian		return;
147220908Sadrian
148221782Sadrian	r = (struct ieee80211_alq_rec *) ale->ae_data;
149221781Sadrian	r->r_timestamp = htonl(ticks);
150220908Sadrian	r->r_version = 1;
151221781Sadrian	r->r_wlan = htons(vap->iv_ifp->if_dunit);
152220908Sadrian	r->r_op = op;
153220908Sadrian	memcpy(&r->r_payload, p, MIN(l, sizeof(r->r_payload)));
154221781Sadrian	alq_post(ieee80211_alq, ale);
155220908Sadrian}
156