channel.c revision 281210
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 281210 2015-04-07 16:48:23Z takawata $ */ 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> 38281210Stakawata#define L2CAP_SOCKET_CHECKED 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