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