Date: Wed, 16 May 2007 23:03:47 +0200 From: Stefan `Sec` Zehl <sec@42.org> To: Maksim Yevmenkin <maksim.yevmenkin@gmail.com> Cc: freebsd-bluetooth@freebsd.org Subject: Re: send something TO a hid device Message-ID: <20070516210347.GC40029@ice.42.org> In-Reply-To: <bb4a86c70705141041s64b5e9dat98cf57ee3f6c3e3f@mail.gmail.com> References: <20070513140148.GA24803@ice.42.org> <bb4a86c70705131614t76526fbbya3a5253fe2e742a9@mail.gmail.com> <20070514082040.GB24803@ice.42.org> <bb4a86c70705141041s64b5e9dat98cf57ee3f6c3e3f@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
--NzB8fVQJ5HfG6fxh Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, On Mon, May 14, 2007 at 10:41 -0700, Maksim Yevmenkin wrote: > again, you do not really need a device. socket will do just fine. > local client(s) can connect to the bthidd and identify which hid > device it (they) will be taking to, i.e. tell hid device's bd_addr. > then client(s) simply sends hid reports to the bthidd via socket and > it will relay them the hid device via bluetooth. I have a first (rudimentary) version. The patch is below, any comments would be appreciated. It addas a new commandline option "-b" which makes bthidd listen on port 12345. I think, either the port number to listen on should be configurable, or it should perhaps better listen on a unix domain socket "/tmp/.bthidd-socket" or somesuch. It can currently only cope with one backchannel connection at a time. This could be changed, if anyone thinks keeping it that way would be too limiting. There is only one interesting command implemented: "raw BD_ADDR hexbytes" which simply sends the hexbytes to that device. I'm currently thinking about sending the device answer back over the tcp channel. At least the media pad has query functions, too. CU, Sec -- "Good people do not need laws to tell them to act responsibly, while bad people will find a way around the laws." - Plato(?) (427-347 B.C.) --NzB8fVQJ5HfG6fxh Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="bthidd_backchannel.diff" --- bthidd.c.org Mon Oct 9 23:00:17 2006 +++ bthidd.c Wed May 16 02:45:30 2007 @@ -66,14 +66,15 @@ struct sigaction sa; char const *pid_file = BTHIDD_PIDFILE; char *ep; - int32_t opt, detach, tval; + int32_t opt, detach, tval, do_backchannel; memset(&srv, 0, sizeof(srv)); memset(&srv.bdaddr, 0, sizeof(srv.bdaddr)); detach = 1; tval = 10; /* sec */ + do_backchannel=0; - while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) { + while ((opt = getopt(argc, argv, "a:bc:dH:hp:t:")) != -1) { switch (opt) { case 'a': /* BDADDR */ if (!bt_aton(optarg, &srv.bdaddr)) { @@ -85,6 +86,9 @@ memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); } break; + case 'b': /* enable backchannel */ + do_backchannel=1; + break; case 'c': /* config file */ config_file = optarg; @@ -153,6 +157,9 @@ if (read_config_file() < 0 || read_hids_file() < 0 || server_init(&srv) < 0 || write_pid_file(pid_file) < 0) + exit(1); + + if (do_backchannel && backchannel_init(&srv) < 0) exit(1); for (done = 0; !done; ) { --- bthidd.h.org Mon Oct 9 23:00:17 2006 +++ bthidd.h Tue May 15 23:29:54 2007 @@ -45,6 +45,8 @@ int32_t cons; /* /dev/consolectl */ int32_t ctrl; /* control channel (listen) */ int32_t intr; /* intr. channel (listen) */ + int32_t back; /* backchannel (listen) */ + int32_t backconn; /* backchannel (connected) */ int32_t maxfd; /* max fd in sets */ fd_set rfdset; /* read descriptor set */ fd_set wfdset; /* write descriptor set */ @@ -78,6 +80,8 @@ void server_shutdown (bthid_server_p srv); int32_t server_do (bthid_server_p srv); +int32_t backchannel_init (bthid_server_p srv); + int32_t client_rescan (bthid_server_p srv); int32_t client_connect (bthid_server_p srv, int fd); @@ -85,6 +89,7 @@ bthid_session_p session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr); bthid_session_p session_by_fd (bthid_server_p srv, int32_t fd); void session_close (bthid_session_p s); +void backchannel_close(bthid_server_p srv); int32_t hid_control (bthid_session_p s, uint8_t *data, int32_t len); int32_t hid_interrupt (bthid_session_p s, uint8_t *data, int32_t len); --- server.c.org Mon Oct 9 23:00:17 2006 +++ server.c Wed May 16 02:48:36 2007 @@ -46,6 +46,8 @@ #include "bthid_config.h" #include "bthidd.h" #include "kbd.h" +#include <netinet/in.h> +#include <arpa/inet.h> #undef max #define max(x, y) (((x) > (y))? (x) : (y)) @@ -53,6 +55,9 @@ static int32_t server_accept (bthid_server_p srv, int32_t fd); static int32_t server_process(bthid_server_p srv, int32_t fd); +static int32_t backchannel_accept (bthid_server_p srv, int32_t fd); +static int32_t backchannel_process(bthid_server_p srv, int32_t fd); + /* * Initialize server */ @@ -164,6 +169,45 @@ } /* + * Create backchannel socket + */ + +int32_t +backchannel_init(bthid_server_p srv) +{ + struct sockaddr_in sin; + bzero(&sin, sizeof (struct sockaddr_in)); + int x=1; + + sin.sin_family = AF_INET; + sin.sin_port = htons(12345); +// inet_aton("194.77.85.2",&sin.sin_addr); + + srv->back = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(srv->back<0){ + syslog(LOG_ERR, "Could not create backchannel socket. " \ + "%s (%d)", strerror(errno), errno); + return (-1); + }; + if (bind(srv->back, (struct sockaddr*)&sin, sizeof (struct sockaddr)) < 0){ + syslog(LOG_ERR, "Could not bind backchannel socket. " \ + "%s (%d)", strerror(errno), errno); + return (-1); + }; + setsockopt(srv->back,SOL_SOCKET,SO_REUSEADDR,&x,sizeof(x)); + if(listen(srv->back,1)<0){ + syslog(LOG_ERR, "Could not listen on backchannel socket. " \ + "%s (%d)", strerror(errno), errno); + return (-1); + }; + + FD_SET(srv->back, &srv->rfdset); + srv->maxfd = max(srv->back, srv->maxfd); + + return(0); +} + +/* * Do one server iteration */ @@ -201,6 +245,10 @@ if (fd == srv->ctrl || fd == srv->intr) server_accept(srv, fd); + else if (fd == srv->back) + backchannel_accept(srv, fd); + else if (fd == srv->backconn) + backchannel_process(srv, fd); else server_process(srv, fd); } else if (FD_ISSET(fd, &wfdset)) { @@ -290,6 +338,44 @@ } /* + * Accept new backchannel connection + */ + +static int32_t +backchannel_accept(bthid_server_p srv, int32_t fd) +{ + int32_t new_fd; + struct sockaddr_in addr; + socklen_t len; + const char *data="ERR: Only one connection at a time.\n"; + + len = sizeof(addr); + if ((new_fd = accept(fd, (struct sockaddr*)&addr, &len)) < 0) { + syslog(LOG_ERR, "Could not accept backchannel connection. %s (%d)", + strerror(errno), errno); + return (-1); + } + + if(srv->backconn){ + syslog(LOG_NOTICE, "Refused second backchannel connection."); + write(new_fd,data,strlen(data)); + close(new_fd); + return(-1); + }; + + FD_SET(new_fd, &srv->rfdset); + if (new_fd > srv->maxfd) + srv->maxfd = new_fd; + + srv->backconn=new_fd; + + syslog(LOG_NOTICE, "Accepted backchannel connection from %s", + inet_ntoa(addr.sin_addr)); + + return(0); +}; + +/* * Process data on the connection */ @@ -345,5 +431,134 @@ (*cb)(s, (uint8_t *) &data, len); return (0); +} + +/* + * Process command on the backchannel connection + */ + +static int32_t +backchannel_process(bthid_server_p srv, int32_t fd) +{ + uint8_t data[1024]; + int32_t len, to_read; + char *p, *word; + const char *out; + bdaddr_t bdaddr; + + to_read = sizeof(data); + + do { + len = read(fd, &data, to_read); + } while (len < 0 && errno == EINTR); + + if (len < 0) { + syslog(LOG_ERR, "Could not read data from backchannel. %s (%d)", + strerror(errno), errno); + backchannel_close(srv); + return (0); + } + + if (len == 0) { + syslog(LOG_NOTICE, "Backchannel has closed connection"); + backchannel_close(srv); + return (0); + } + + data[len]=0; + p=data; +#define OPTION(x) ( (!strncasecmp(p, x, strlen(x))) && (p += strlen(x)) ) + out=NULL; + if( OPTION("raw ")){ + bthid_session_p s; +#define MAXOUTLEN 22 + uint8_t outb[MAXOUTLEN]; + uint8_t val=0,idx=0; + char shift=0; + + word=p; + for(word=p;*p && *p!=' ';p++); + if(!*p){ + out="ERR: Missing parameter.\n"; + goto err; + }; + *p=0; + if (!bt_aton(word, &bdaddr)) { + struct hostent *he; + + if ((he = bt_gethostbyname(word)) == NULL){ + out="ERR: Can't parse BD_ADDR.\n"; + goto err; + }; + memcpy(&bdaddr, he->h_addr, sizeof(bdaddr)); + } + s=session_by_bdaddr(srv,&bdaddr); + if(s==NULL || s->intr == 0){ + out="ERR: Device not connected\n"; + goto err; + }; + for(p++;*p;p++){ + shift=4-shift; + if(*p>='0' && *p <= '9') + val=val|((*p-'0')<<shift); + else if(*p>='a' && *p <= 'f') + val=val|((*p-'a'+10)<<shift); + else if(*p>='A' && *p <= 'F') + val=val|((*p-'A'+10)<<shift); + else if(*p=='\r' || *p =='\n' || *p == ' '){ + shift=4-shift; + continue; + }else{ + out="ERR: Can't parse hexstring.\n"; + goto err; + }; + if(shift==0){ + outb[idx++]=val; + val=0; + if(idx==MAXOUTLEN){ + out="ERR: Hexstring too long.\n"; + goto err; + }; + }; + }; + if(shift!=0){ + out="ERR: odd number of hex chars.\n"; + goto err; + }; + if(idx==0){ + out="ERR: Missing parameter.\n"; + goto err; + }; + outb[idx]=0; + + printf("out: "); + for (val=0;val<idx;val++){ + printf("%02x ",outb[val]); + }; + printf("(%d)\n",idx); + + if(write(s->intr,outb,idx)<0){ + syslog(LOG_ERR, "Backchannel write failed: " \ + "%s (%d).", strerror(errno), errno); + out="ERR: Write failed.\n"; + goto err; + } + out="OK: Sent.\n"; + + }else if(OPTION("quit")){ + syslog(LOG_NOTICE, "closing backchannel connection"); + backchannel_close(srv); + return (0); + }else if(OPTION("help")){ + out="ERR: Commands:\n" + "ERR: - raw BD_ADDR hexstring.\n" + "ERR: - help\n"; + "ERR: - quit\n"; + }else{ + out="ERR: Unknown command. Try help.\n"; + }; +err: + if(out) + write(srv->backconn,out,strlen(out)); } --- session.c.org Mon Oct 9 23:00:17 2006 +++ session.c Tue May 15 23:17:53 2007 @@ -182,3 +182,15 @@ free(s); } +/* + * Close backchannel + */ + +void +backchannel_close(bthid_server_p srv) +{ + FD_CLR(srv->backconn, &srv->rfdset); + FD_CLR(srv->backconn, &srv->wfdset); + close(srv->backconn); + srv->backconn=0; +} --NzB8fVQJ5HfG6fxh--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070516210347.GC40029>