channel.c revision 187938
1187938Semax/*	$NetBSD: channel.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
2187938Semax
3187938Semax/*-
4187938Semax * Copyright (c) 2008 Iain Hibbert
5187938Semax * All rights reserved.
6187938Semax *
7187938Semax * Redistribution and use in source and binary forms, with or without
8187938Semax * modification, are permitted provided that the following conditions
9187938Semax * are met:
10187938Semax * 1. Redistributions of source code must retain the above copyright
11187938Semax *    notice, this list of conditions and the following disclaimer.
12187938Semax * 2. Redistributions in binary form must reproduce the above copyright
13187938Semax *    notice, this list of conditions and the following disclaimer in the
14187938Semax *    documentation and/or other materials provided with the distribution.
15187938Semax *
16187938Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17187938Semax * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18187938Semax * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19187938Semax * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20187938Semax * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21187938Semax * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22187938Semax * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23187938Semax * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24187938Semax * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25187938Semax * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26187938Semax */
27187938Semax
28187938Semax/* $FreeBSD: head/usr.sbin/bluetooth/btpand/channel.c 187938 2009-01-30 22:23:21Z emax $ */
29187938Semax
30187938Semax#include <sys/cdefs.h>
31187938Semax__RCSID("$NetBSD: channel.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
32187938Semax
33187938Semax#include <sys/param.h>
34187938Semax#include <sys/ioctl.h>
35187938Semax
36187938Semax#include <libutil.h>
37187938Semax#include <unistd.h>
38187938Semax
39187938Semax#include "btpand.h"
40187938Semax
41187938Semaxstatic struct chlist	channel_list;
42187938Semaxstatic int		channel_count;
43187938Semaxstatic int		channel_tick;
44187938Semax
45187938Semaxstatic void channel_start(int, short, void *);
46187938Semaxstatic void channel_read(int, short, void *);
47187938Semaxstatic void channel_dispatch(packet_t *);
48187938Semaxstatic void channel_watchdog(int, short, void *);
49187938Semax
50187938Semaxvoid
51187938Semaxchannel_init(void)
52187938Semax{
53187938Semax
54187938Semax	LIST_INIT(&channel_list);
55187938Semax}
56187938Semax
57187938Semaxchannel_t *
58187938Semaxchannel_alloc(void)
59187938Semax{
60187938Semax	channel_t *chan;
61187938Semax
62187938Semax	chan = malloc(sizeof(channel_t));
63187938Semax	if (chan == NULL) {
64187938Semax		log_err("%s() failed: %m", __func__);
65187938Semax		return NULL;
66187938Semax	}
67187938Semax
68187938Semax	memset(chan, 0, sizeof(channel_t));
69187938Semax	STAILQ_INIT(&chan->pktlist);
70187938Semax	chan->state = CHANNEL_CLOSED;
71187938Semax	LIST_INSERT_HEAD(&channel_list, chan, next);
72187938Semax
73187938Semax	server_update(++channel_count);
74187938Semax
75187938Semax	return chan;
76187938Semax}
77187938Semax
78187938Semaxbool
79187938Semaxchannel_open(channel_t *chan, int fd)
80187938Semax{
81187938Semax	int n;
82187938Semax
83187938Semax	assert(chan->refcnt == 0);
84187938Semax	assert(chan->state != CHANNEL_CLOSED);
85187938Semax
86187938Semax	if (chan->mtu > 0) {
87187938Semax		chan->sendbuf = malloc(chan->mtu);
88187938Semax		if (chan->sendbuf == NULL) {
89187938Semax			log_err("Could not malloc channel sendbuf: %m");
90187938Semax			return false;
91187938Semax		}
92187938Semax	}
93187938Semax
94187938Semax	n = 1;
95187938Semax	if (ioctl(fd, FIONBIO, &n) == -1) {
96187938Semax		log_err("Could not set non-blocking IO: %m");
97187938Semax		return false;
98187938Semax	}
99187938Semax
100187938Semax	event_set(&chan->rd_ev, fd, EV_READ | EV_PERSIST, channel_read, chan);
101187938Semax	if (event_add(&chan->rd_ev, NULL) == -1) {
102187938Semax		log_err("Could not add channel read event: %m");
103187938Semax		return false;
104187938Semax	}
105187938Semax
106187938Semax	event_set(&chan->wr_ev, fd, EV_WRITE, channel_start, chan);
107187938Semax
108187938Semax	chan->refcnt++;
109187938Semax	chan->fd = fd;
110187938Semax
111187938Semax	log_debug("(fd#%d)", chan->fd);
112187938Semax
113187938Semax	return true;
114187938Semax}
115187938Semax
116187938Semaxvoid
117187938Semaxchannel_close(channel_t *chan)
118187938Semax{
119187938Semax	pkthdr_t *ph;
120187938Semax
121187938Semax	assert(chan->state != CHANNEL_CLOSED);
122187938Semax
123187938Semax	log_debug("(fd#%d)", chan->fd);
124187938Semax
125187938Semax	chan->state = CHANNEL_CLOSED;
126187938Semax	event_del(&chan->rd_ev);
127187938Semax	event_del(&chan->wr_ev);
128187938Semax	close(chan->fd);
129187938Semax	chan->refcnt--;
130187938Semax	chan->tick = 0;
131187938Semax
132187938Semax	while ((ph = STAILQ_FIRST(&chan->pktlist)) != NULL) {
133187938Semax		STAILQ_REMOVE_HEAD(&chan->pktlist, next);
134187938Semax		pkthdr_free(ph);
135187938Semax		chan->qlen--;
136187938Semax	}
137187938Semax
138187938Semax	if (chan->pfh != NULL) {
139187938Semax		pidfile_remove(chan->pfh);
140187938Semax		chan->pfh = NULL;
141187938Semax	}
142187938Semax
143187938Semax	if (chan->refcnt == 0)
144187938Semax		channel_free(chan);
145187938Semax}
146187938Semax
147187938Semaxvoid
148187938Semaxchannel_free(channel_t *chan)
149187938Semax{
150187938Semax
151187938Semax	assert(chan->refcnt == 0);
152187938Semax	assert(chan->state == CHANNEL_CLOSED);
153187938Semax	assert(chan->qlen == 0);
154187938Semax	assert(STAILQ_EMPTY(&chan->pktlist));
155187938Semax
156187938Semax	LIST_REMOVE(chan, next);
157187938Semax	free(chan->pfilter);
158187938Semax	free(chan->mfilter);
159187938Semax	free(chan->sendbuf);
160187938Semax	free(chan);
161187938Semax
162187938Semax	server_update(--channel_count);
163187938Semax
164187938Semax	if (server_limit == 0) {
165187938Semax		log_info("connection closed, exiting");
166187938Semax		exit(EXIT_SUCCESS);
167187938Semax	}
168187938Semax}
169187938Semax
170187938Semaxstatic void
171187938Semaxchannel_start(int fd, short ev, void *arg)
172187938Semax{
173187938Semax	channel_t *chan = arg;
174187938Semax	pkthdr_t *ph;
175187938Semax
176187938Semax	chan->oactive = true;
177187938Semax
178187938Semax	while (chan->qlen > 0) {
179187938Semax		ph = STAILQ_FIRST(&chan->pktlist);
180187938Semax
181187938Semax		channel_timeout(chan, 10);
182187938Semax		if (chan->send(chan, ph->data) == false) {
183187938Semax			if (event_add(&chan->wr_ev, NULL) == -1) {
184187938Semax				log_err("Could not add channel write event: %m");
185187938Semax				channel_close(chan);
186187938Semax			}
187187938Semax			return;
188187938Semax		}
189187938Semax
190187938Semax		STAILQ_REMOVE_HEAD(&chan->pktlist, next);
191187938Semax		pkthdr_free(ph);
192187938Semax		chan->qlen--;
193187938Semax	}
194187938Semax
195187938Semax	channel_timeout(chan, 0);
196187938Semax	chan->oactive = false;
197187938Semax}
198187938Semax
199187938Semaxstatic void
200187938Semaxchannel_read(int fd, short ev, void *arg)
201187938Semax{
202187938Semax	channel_t *chan = arg;
203187938Semax	packet_t *pkt;
204187938Semax	ssize_t nr;
205187938Semax
206187938Semax	pkt = packet_alloc(chan);
207187938Semax	if (pkt == NULL) {
208187938Semax		channel_close(chan);
209187938Semax		return;
210187938Semax	}
211187938Semax
212187938Semax	nr = read(fd, pkt->buf, chan->mru);
213187938Semax	if (nr == -1) {
214187938Semax		log_err("channel read error: %m");
215187938Semax		packet_free(pkt);
216187938Semax		channel_close(chan);
217187938Semax		return;
218187938Semax	}
219187938Semax	if (nr == 0) {	/* EOF */
220187938Semax		log_debug("(fd#%d) EOF", fd);
221187938Semax		packet_free(pkt);
222187938Semax		channel_close(chan);
223187938Semax		return;
224187938Semax	}
225187938Semax	pkt->len = nr;
226187938Semax
227187938Semax	if (chan->recv(pkt) == true)
228187938Semax		channel_dispatch(pkt);
229187938Semax
230187938Semax	packet_free(pkt);
231187938Semax}
232187938Semax
233187938Semaxstatic void
234187938Semaxchannel_dispatch(packet_t *pkt)
235187938Semax{
236187938Semax	channel_t *chan;
237187938Semax
238187938Semax	/*
239187938Semax	 * This is simple routing. I'm not sure if its allowed by
240187938Semax	 * the PAN or BNEP specifications, but it seems logical
241187938Semax	 * to send unicast packets to connected destinations where
242187938Semax	 * possible.
243187938Semax	 */
244187938Semax	if (!ETHER_IS_MULTICAST(pkt->dst)) {
245187938Semax		LIST_FOREACH(chan, &channel_list, next) {
246187938Semax			if (chan == pkt->chan
247187938Semax			    || chan->state != CHANNEL_OPEN)
248187938Semax				continue;
249187938Semax
250187938Semax			if (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) == 0) {
251187938Semax				if (chan->qlen > CHANNEL_MAXQLEN)
252187938Semax					log_notice("Queue overflow");
253187938Semax				else
254187938Semax					channel_put(chan, pkt);
255187938Semax
256187938Semax				return;
257187938Semax			}
258187938Semax		}
259187938Semax	}
260187938Semax
261187938Semax	LIST_FOREACH(chan, &channel_list, next) {
262187938Semax		if (chan == pkt->chan
263187938Semax		    || chan->state != CHANNEL_OPEN)
264187938Semax			continue;
265187938Semax
266187938Semax		if (chan->qlen > CHANNEL_MAXQLEN) {
267187938Semax			log_notice("Queue overflow");
268187938Semax			continue;
269187938Semax		}
270187938Semax
271187938Semax		channel_put(chan, pkt);
272187938Semax	}
273187938Semax}
274187938Semax
275187938Semaxvoid
276187938Semaxchannel_put(channel_t *chan, packet_t *pkt)
277187938Semax{
278187938Semax	pkthdr_t *ph;
279187938Semax
280187938Semax	ph = pkthdr_alloc(pkt);
281187938Semax	if (ph == NULL)
282187938Semax		return;
283187938Semax
284187938Semax	chan->qlen++;
285187938Semax	STAILQ_INSERT_TAIL(&chan->pktlist, ph, next);
286187938Semax
287187938Semax	if (!chan->oactive)
288187938Semax		channel_start(chan->fd, EV_WRITE, chan);
289187938Semax}
290187938Semax
291187938Semax/*
292187938Semax * Simple watchdog timer, only ticks when it is required and
293187938Semax * closes the channel down if it times out.
294187938Semax */
295187938Semaxvoid
296187938Semaxchannel_timeout(channel_t *chan, int to)
297187938Semax{
298187938Semax	static struct event ev;
299187938Semax
300187938Semax	if (to == 0)
301187938Semax		chan->tick = 0;
302187938Semax	else
303187938Semax		chan->tick = (channel_tick + to) % 60;
304187938Semax
305187938Semax	if (channel_tick == 0) {
306187938Semax		evtimer_set(&ev, channel_watchdog, &ev);
307187938Semax		channel_watchdog(0, 0, &ev);
308187938Semax	}
309187938Semax}
310187938Semax
311187938Semaxstatic void
312187938Semaxchannel_watchdog(int fd, short ev, void *arg)
313187938Semax{
314187938Semax	static struct timeval tv = { .tv_sec = 1 };
315187938Semax	channel_t *chan, *next;
316187938Semax	int tick;
317187938Semax
318187938Semax	tick = (channel_tick % 60) + 1;
319187938Semax	channel_tick = 0;
320187938Semax
321187938Semax	next = LIST_FIRST(&channel_list);
322187938Semax	while ((chan = next) != NULL) {
323187938Semax		next = LIST_NEXT(chan, next);
324187938Semax
325187938Semax		if (chan->tick == tick)
326187938Semax			channel_close(chan);
327187938Semax		else if (chan->tick != 0)
328187938Semax			channel_tick = tick;
329187938Semax	}
330187938Semax
331187938Semax	if (channel_tick != 0 && evtimer_add(arg, &tv) < 0) {
332187938Semax		log_err("Could not add watchdog event: %m");
333187938Semax		exit(EXIT_FAILURE);
334187938Semax	}
335187938Semax}
336