diff options
Diffstat (limited to 'usr.bin/bluetooth')
-rw-r--r-- | usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 | 61 | ||||
-rw-r--r-- | usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c | 132 |
2 files changed, 153 insertions, 40 deletions
diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 index 2f7d3f5328a1..4af70943f6df 100644 --- a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 +++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 @@ -25,7 +25,7 @@ .\" $Id: rfcomm_sppd.1,v 1.3 2003/09/07 18:15:55 max Exp $ .\" $FreeBSD$ .\" -.Dd April 26, 2003 +.Dd January 24, 2007 .Dt RFCOMM_SPPD 1 .Os .Sh NAME @@ -33,7 +33,7 @@ .Nd RFCOMM Serial Port Profile daemon .Sh SYNOPSIS .Nm -.Op Fl bh +.Op Fl bhS .Fl a Ar address .Fl c Ar channel .Op Fl t Ar tty @@ -41,7 +41,11 @@ The .Nm utility is a Serial Port Profile daemon. -It opens RFCOMM connection to the specified +It can operate in two modes: client and server. +.Pp +In client mode, +.Nm +opens RFCOMM connection to the specified .Ar address server and .Ar channel . @@ -54,6 +58,27 @@ interface if .Fl t option was specified. .Pp +If the +.Fl S +option is specified, +.Nm +will operate in server mode and act as RFCOMM server, +listening on +.Dv ANY +address and advertising a virtual serial port +via the +.Xr sdpd 8 +daemon. +The +.Fl t +option must be specified; +the server side of the virtual serial port is attached to the pseudo-terminal +.Ar tty . +.Nm +should be run as root in order to communicate with +.Xr sdp 8 +in this case. +.Pp The .Nm utility opens both master and slave pseudo terminals. @@ -71,17 +96,31 @@ port. The options are as follows: .Bl -tag -width indent .It Fl a Ar address -This required option specifies the address of the remote RFCOMM server. +In client mode, +this required option specifies the address of the remote RFCOMM server. +If this option is specified in server mode, +.Nm +will only accept connections from the +.Tn Bluetooth +device with address +.Ar address . The address can be specified as BD_ADDR or name. -If name was specified then the +If name was specified then .Nm utility will attempt to resolve the name via .Xr bt_gethostbyname 3 . .It Fl b Detach from the controlling terminal, i.e., run in background. .It Fl c Ar channel -This option specifies RFCOMM channel to connect to. -RFCOMM channel could either be a number between 1 and 30 or a service name. +In both client and server mode, +this required option specifies the RFCOMM channel to connect to or listen on. +In server mode, +the channel should be a number between 1 and 30. +If not specified, +.Nm +will try to allocate RFCOMM channel number based on process ID. +In client mode, +the channel could either be a number between 1 and 30 or a service name. Supported service names are: .Cm DUN (for DialUp Networking service), @@ -97,11 +136,16 @@ utility will try to obtain RFCOMM channel for Serial Port service via Service Discovery Protocol from the server. .It Fl h Display usage message and exit. +.It Fl S +Server mode; see +.Sx DESCRIPTION . .It Fl t Ar tty Slave pseudo tty name. If not set stdin/stdout will be used. This option is required if .Fl b +or +.Fl S option was specified. .El .Sh FILES @@ -129,7 +173,8 @@ can be used to talk to the remote serial port on the server. .Xr bluetooth 3 , .Xr ng_btsocket 4 , .Xr pty 4 , -.Xr rfcomm_pppd 8 +.Xr rfcomm_pppd 8 , +.Xr sdpd 8 .Sh AUTHORS .An Maksim Yevmenkin Aq m_evmenkin@yahoo.com .Sh BUGS diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c index 4ce893da22c5..4c37d5f073e4 100644 --- a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c +++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c @@ -72,16 +72,17 @@ main(int argc, char *argv[]) struct sockaddr_rfcomm ra; bdaddr_t addr; int n, background, channel, service, - s, amaster, aslave, fd; + s, amaster, aslave, fd, doserver; fd_set rfd; char *tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE]; memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); background = channel = 0; service = SDP_SERVICE_CLASS_SERIAL_PORT; + doserver = 0; /* Parse command line options */ - while ((n = getopt(argc, argv, "a:bc:t:h")) != -1) { + while ((n = getopt(argc, argv, "a:bc:t:hS")) != -1) { switch (n) { case 'a': /* BDADDR */ if (!bt_aton(optarg, &addr)) { @@ -134,6 +135,10 @@ main(int argc, char *argv[]) tty = optarg; break; + case 'S': + doserver = 1; + break; + case 'h': default: usage(); @@ -142,7 +147,7 @@ main(int argc, char *argv[]) } /* Check if we have everything we need */ - if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) + if (!doserver && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) usage(); /* NOT REACHED */ @@ -165,17 +170,9 @@ main(int argc, char *argv[]) if (sigaction(SIGCHLD, &sa, NULL) < 0) err(1, "Could not sigaction(SIGCHLD)"); - /* Check channel, if was not set then obtain it via SDP */ - if (channel == 0 && service != 0) - if (rfcomm_channel_lookup(NULL, &addr, - service, &channel, &n) != 0) - errc(1, n, "Could not obtain RFCOMM channel"); - if (channel <= 0 || channel > 30) - errx(1, "Invalid RFCOMM channel number %d", channel); - /* Open TTYs */ if (tty == NULL) { - if (background) + if (background || doserver) usage(); amaster = STDIN_FILENO; @@ -187,24 +184,95 @@ main(int argc, char *argv[]) fd = amaster; } - /* Open RFCOMM connection */ - memset(&ra, 0, sizeof(ra)); - ra.rfcomm_len = sizeof(ra); - ra.rfcomm_family = AF_BLUETOOTH; - s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); - if (s < 0) - err(1, "Could not create socket"); - - if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0) - err(1, "Could not bind socket"); - - memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr)); - ra.rfcomm_channel = channel; + if (doserver) { + struct sockaddr_rfcomm ma; + bdaddr_t bt_addr_any; + sdp_lan_profile_t lan; + void *ss; + uint32_t sdp_handle; + int acceptsock, aaddrlen; + + if (channel == 0) { + /* XXX: should check if selected channel is unused */ + channel = (getpid() % 30) + 1; + } + acceptsock = socket(PF_BLUETOOTH, SOCK_STREAM, + BLUETOOTH_PROTO_RFCOMM); + if (acceptsock < 0) + err(1, "Could not create socket"); + + memset(&ma, 0, sizeof(ma)); + ma.rfcomm_len = sizeof(ma); + ma.rfcomm_family = AF_BLUETOOTH; + ma.rfcomm_channel = channel; + + if (bind(acceptsock, (struct sockaddr *)&ma, sizeof(ma)) < 0) + err(1, "Could not bind socket -- channel %d in use?", + channel); + listen(acceptsock, 10); + + ss = sdp_open_local(NULL); + if (ss == NULL) + errx(1, "Unable to create local SDP session"); + if (sdp_error(ss) != 0) + errx(1, "Unable to open local SDP session. %s (%d)", + strerror(sdp_error(ss)), sdp_error(ss)); + memset(&lan, 0, sizeof(lan)); + lan.server_channel = channel; + + memcpy(&bt_addr_any, NG_HCI_BDADDR_ANY, sizeof(bt_addr_any)); + if (sdp_register_service(ss, service, &bt_addr_any, + (void *)&lan, sizeof(lan), &sdp_handle) != 0) { + errx(1, "Unable to register LAN service with " + "local SDP daemon. %s (%d)", + strerror(sdp_error(ss)), sdp_error(ss)); + } - if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0) - err(1, "Could not connect socket"); + s = -1; + while (s < 0) { + aaddrlen = sizeof(ra); + s = accept(acceptsock, (struct sockaddr *)&ra, + &aaddrlen); + if (s < 0) + err(1, "Unable to accept()"); + if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) && + memcmp(&addr, &ra.rfcomm_bdaddr, sizeof(addr))) { + warnx("Connect from wrong client"); + close(s); + s = -1; + } + } + sdp_unregister_service(ss, sdp_handle); + sdp_close(ss); + close(acceptsock); + } else { + /* Check channel, if was not set then obtain it via SDP */ + if (channel == 0 && service != 0) + if (rfcomm_channel_lookup(NULL, &addr, + service, &channel, &n) != 0) + errc(1, n, "Could not obtain RFCOMM channel"); + if (channel <= 0 || channel > 30) + errx(1, "Invalid RFCOMM channel number %d", channel); + + s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); + if (s < 0) + err(1, "Could not create socket"); + + memset(&ra, 0, sizeof(ra)); + ra.rfcomm_len = sizeof(ra); + ra.rfcomm_family = AF_BLUETOOTH; + + if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0) + err(1, "Could not bind socket"); + + memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr)); + ra.rfcomm_channel = channel; + + if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0) + err(1, "Could not connect socket"); + } /* Became daemon if required */ if (background) { @@ -346,7 +414,7 @@ sppd_ttys_open(char const *tty, int *amaster, int *aslave) ttygid = -1; (void) chown(tty, getuid(), ttygid); - (void) chmod(tty, S_IRUSR|S_IWUSR|S_IWGRP); + (void) chmod(tty, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); (void) revoke(tty); if ((*aslave = open(tty, O_RDWR, 0)) < 0) { @@ -433,12 +501,12 @@ usage(void) fprintf(stdout, "Usage: %s options\n" \ "Where options are:\n" \ -"\t-a address Address to connect to (required)\n" \ +"\t-a address Peer address (required in client mode)\n" \ "\t-b Run in background\n" \ -"\t-c channel RFCOMM channel to connect to\n" \ -"\t-t tty TTY name (required in background mode)\n" \ +"\t-c channel RFCOMM channel to connect to or listen on\n" \ +"\t-t tty TTY name (required in background or server mode)\n" \ +"\t-S Server mode\n" \ "\t-h Display this message\n", SPPD_IDENT); - exit(255); } /* usage */ |