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