1/*-
2 * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 *
16 * NO WARRANTY
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 *
29 * $FreeBSD$
30 */
31#include <sys/param.h>
32#include <sys/module.h>
33#include <sys/kernel.h>
34#include <sys/systm.h>
35#include <sys/sysctl.h>
36#include <sys/mbuf.h>
37#include <sys/malloc.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/proc.h>
41#include <sys/ucred.h>
42#include <sys/jail.h>
43
44#include <sys/types.h>
45#include <sys/sockio.h>
46#include <sys/socket.h>
47#include <sys/socketvar.h>
48#include <sys/errno.h>
49#include <sys/callout.h>
50#include <sys/endian.h>
51#include <sys/kthread.h>
52#include <sys/taskqueue.h>
53#include <sys/priv.h>
54#include <sys/sysctl.h>
55
56#include <machine/bus.h>
57
58#include <net/if.h>
59#include <net/if_dl.h>
60#include <net/if_media.h>
61#include <net/if_types.h>
62#include <net/if_arp.h>
63#include <net/ethernet.h>
64#include <net/if_llc.h>
65#include <net/vnet.h>
66
67#include <net80211/ieee80211_var.h>
68#include <net80211/ieee80211_regdomain.h>
69
70#include <net/bpf.h>
71
72
73#include <sys/errno.h>
74#include <sys/conf.h>   /* cdevsw struct */
75#include <sys/uio.h>    /* uio struct */
76
77#include <netinet/in.h>
78#include <netinet/if_ether.h>
79
80#include "visibility.h"
81
82/* Function prototypes */
83static d_ioctl_t	vis_ioctl;
84
85static struct cdevsw vis_cdevsw = {
86	.d_version =	D_VERSION,
87	.d_flags =	0,
88	.d_ioctl =	vis_ioctl,
89	.d_name =	"visctl",
90};
91
92void
93visibility_init(struct wtap_plugin *plugin)
94{
95	struct visibility_plugin *vis_plugin;
96
97	vis_plugin = (struct visibility_plugin *) plugin;
98	plugin->wp_sdev = make_dev(&vis_cdevsw,0,UID_ROOT,GID_WHEEL,0600,
99	    (const char *)"visctl");
100	plugin->wp_sdev->si_drv1 = vis_plugin;
101	mtx_init(&vis_plugin->pl_mtx, "visibility_plugin mtx",
102	    NULL, MTX_DEF | MTX_RECURSE);
103	printf("Using visibility wtap plugin...\n");
104}
105
106void
107visibility_deinit(struct wtap_plugin *plugin)
108{
109	struct visibility_plugin *vis_plugin;
110
111	vis_plugin = (struct visibility_plugin *) plugin;
112	destroy_dev(plugin->wp_sdev);
113	mtx_destroy(&vis_plugin->pl_mtx);
114	free(vis_plugin, M_WTAP_PLUGIN);
115	printf("Removing visibility wtap plugin...\n");
116}
117
118/* We need to use a mutex lock when we read out a visibility map
119 * and when we change visibility map from user space through IOCTL
120 */
121void
122visibility_work(struct wtap_plugin *plugin, struct packet *p)
123{
124	struct visibility_plugin *vis_plugin =
125	    (struct visibility_plugin *) plugin;
126	struct wtap_hal *hal = (struct wtap_hal *)vis_plugin->base.wp_hal;
127	struct vis_map *map;
128
129	KASSERT(mtod(p->m, const char *) != (const char *) 0xdeadc0de ||
130	    mtod(p->m, const char *) != NULL,
131	    ("[%s] got a corrupt packet from master queue, p->m=%p, p->id=%d\n",
132	    __func__, p->m, p->id));
133	DWTAP_PRINTF("[%d] BROADCASTING m=%p\n", p->id, p->m);
134	mtx_lock(&vis_plugin->pl_mtx);
135	map = &vis_plugin->pl_node[p->id];
136	mtx_unlock(&vis_plugin->pl_mtx);
137
138	/* This is O(n*n) which is not optimal for large
139	 * number of nodes. Another way of doing it is
140	 * creating groups of nodes that hear each other.
141	 * Atleast for this simple static node plugin.
142	 */
143	for(int i=0; i<ARRAY_SIZE; ++i){
144		uint32_t index = map->map[i];
145		for(int j=0; j<32; ++j){
146			int vis = index & 0x01;
147			if(vis){
148				int k = i*ARRAY_SIZE + j;
149				if(hal->hal_devs[k] != NULL
150				    && hal->hal_devs[k]->up == 1){
151					struct wtap_softc *sc =
152					    hal->hal_devs[k];
153					struct mbuf *m =
154					    m_dup(p->m, M_NOWAIT);
155					DWTAP_PRINTF("[%d] duplicated old_m=%p"
156					    "to new_m=%p\n", p->id, p->m, m);
157#if 0
158					printf("[%d] sending to %d\n",
159					    p->id, k);
160#endif
161					wtap_inject(sc, m);
162				}
163			}
164			index = index >> 1;
165		}
166	}
167}
168
169static void
170add_link(struct visibility_plugin *vis_plugin, struct link *l)
171{
172
173	mtx_lock(&vis_plugin->pl_mtx);
174	struct vis_map *map = &vis_plugin->pl_node[l->id1];
175	int index = l->id2/ARRAY_SIZE;
176	int bit = l->id2 % ARRAY_SIZE;
177	uint32_t value = 1 << bit;
178	map->map[index] = map->map[index] | value;
179	mtx_unlock(&vis_plugin->pl_mtx);
180#if 0
181	printf("l->id1=%d, l->id2=%d, map->map[%d] = %u, bit=%d\n",
182	    l->id1, l->id2, index, map->map[index], bit);
183#endif
184}
185
186static void
187del_link(struct visibility_plugin *vis_plugin, struct link *l)
188{
189
190	mtx_lock(&vis_plugin->pl_mtx);
191	struct vis_map *map = &vis_plugin->pl_node[l->id1];
192	int index = l->id2/ARRAY_SIZE;
193	int bit = l->id2 % ARRAY_SIZE;
194	uint32_t value = 1 << bit;
195	map->map[index] = map->map[index] & ~value;
196	mtx_unlock(&vis_plugin->pl_mtx);
197#if 0
198	printf("map->map[index] = %u\n", map->map[index]);
199#endif
200}
201
202
203int
204vis_ioctl(struct cdev *sdev, u_long cmd, caddr_t data,
205    int fflag, struct thread *td)
206{
207	struct visibility_plugin *vis_plugin =
208	    (struct visibility_plugin *) sdev->si_drv1;
209	struct wtap_hal *hal = vis_plugin->base.wp_hal;
210	struct link l;
211	int op;
212	int error = 0;
213
214	CURVNET_SET(CRED_TO_VNET(curthread->td_ucred));
215	switch(cmd) {
216	case VISIOCTLOPEN:
217		op =  *(int *)data;
218		if(op == 0)
219			medium_close(hal->hal_md);
220		else
221			medium_open(hal->hal_md);
222		break;
223	case VISIOCTLLINK:
224		l = *(struct link *)data;
225		if(l.op == 0)
226			del_link(vis_plugin, &l);
227		else
228			add_link(vis_plugin, &l);
229#if 0
230		printf("op=%d, id1=%d, id2=%d\n", l.op, l.id1, l.id2);
231#endif
232		break;
233	default:
234		DWTAP_PRINTF("Unknown WTAP IOCTL\n");
235		error = EINVAL;
236	}
237
238	CURVNET_RESTORE();
239	return error;
240}
241
242