mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2025-01-23 04:43:35 +08:00
Add the dund utility
This commit is contained in:
parent
965c347ab1
commit
bc4cb70ddb
@ -2,7 +2,7 @@
|
||||
# $Id$
|
||||
#
|
||||
|
||||
SUBDIRS := hcid tools rfcomm sdpd pand test scripts pcmcia
|
||||
SUBDIRS := hcid tools rfcomm sdpd dund pand test scripts pcmcia
|
||||
|
||||
DISTCLEANFILES = conftest.c conftest
|
||||
|
||||
|
@ -25,4 +25,4 @@ AC_PATH_BLUEZ
|
||||
|
||||
AC_PATH_DBUS
|
||||
|
||||
AC_OUTPUT(Makefile hcid/Makefile tools/Makefile rfcomm/Makefile sdpd/Makefile pand/Makefile test/Makefile scripts/Makefile pcmcia/Makefile)
|
||||
AC_OUTPUT(Makefile hcid/Makefile tools/Makefile rfcomm/Makefile sdpd/Makefile dund/Makefile pand/Makefile test/Makefile scripts/Makefile pcmcia/Makefile)
|
||||
|
15
dund/Makefile.am
Normal file
15
dund/Makefile.am
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
bin_PROGRAMS = dund
|
||||
|
||||
dund_SOURCES = main.c dun.c dund.h sdp.c lib.h msdun.c
|
||||
|
||||
LDFLAGS = @BLUEZ_LIBS@
|
||||
|
||||
INCLUDES = @BLUEZ_INCLUDES@
|
||||
|
||||
man_MANS = dund.1
|
||||
|
||||
EXTRA_DIST = $(man_MANS)
|
308
dund/dun.c
Normal file
308
dund/dun.c
Normal file
@ -0,0 +1,308 @@
|
||||
/*
|
||||
dund - Bluetooth LAN/DUN daemon for BlueZ
|
||||
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/rfcomm.h>
|
||||
|
||||
#include "dund.h"
|
||||
#include "lib.h"
|
||||
|
||||
#define PROC_BASE "/proc"
|
||||
|
||||
static int for_each_port(int (*func)(struct rfcomm_dev_info *, unsigned long), unsigned long arg)
|
||||
{
|
||||
struct rfcomm_dev_list_req *dl;
|
||||
struct rfcomm_dev_info *di;
|
||||
long r = 0;
|
||||
int sk, i;
|
||||
|
||||
sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
|
||||
if (sk < 0 ) {
|
||||
perror("Can't open RFCOMM control socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
|
||||
if (!dl) {
|
||||
perror("Can't allocate request memory");
|
||||
close(sk);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dl->dev_num = RFCOMM_MAX_DEV;
|
||||
di = dl->dev_info;
|
||||
|
||||
if (ioctl(sk, RFCOMMGETDEVLIST, (void *) dl) < 0) {
|
||||
perror("Can't get device list");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < dl->dev_num; i++) {
|
||||
r = func(di + i, arg);
|
||||
if (r) break;
|
||||
}
|
||||
|
||||
close(sk);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int uses_rfcomm(char *path, char *dev)
|
||||
{
|
||||
struct dirent *de;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return 0;
|
||||
chdir(path);
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
char link[PATH_MAX + 1];
|
||||
int len = readlink(de->d_name, link, sizeof(link));
|
||||
if (len > 0) {
|
||||
link[len] = 0;
|
||||
if (strstr(link, dev))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_pppd(int id, pid_t *pid)
|
||||
{
|
||||
struct dirent *de;
|
||||
char path[PATH_MAX + 1];
|
||||
char dev[10];
|
||||
int empty = 1;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(PROC_BASE);
|
||||
if (!dir) {
|
||||
perror(PROC_BASE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(dev, "rfcomm%d", id);
|
||||
|
||||
*pid = 0;
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
empty = 0;
|
||||
if (isdigit(de->d_name[0])) {
|
||||
sprintf(path, "%s/%s/fd", PROC_BASE, de->d_name);
|
||||
if (uses_rfcomm(path, dev)) {
|
||||
*pid = atoi(de->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (empty)
|
||||
fprintf(stderr, "%s is empty (not mounted ?)\n", PROC_BASE);
|
||||
|
||||
return *pid != 0;
|
||||
}
|
||||
|
||||
static int dun_exec(char *tty, char *prog, char **args)
|
||||
{
|
||||
int pid = fork();
|
||||
int fd;
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return -1;
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
return pid;
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
/* Close all FDs */
|
||||
for (fd=3; fd < 20; fd++)
|
||||
close(fd);
|
||||
|
||||
execvp(prog, args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int dun_create_tty(int sk, char *tty, int size)
|
||||
{
|
||||
struct sockaddr_rc sa;
|
||||
struct stat st;
|
||||
int id, alen;
|
||||
|
||||
struct rfcomm_dev_req req = {
|
||||
flags: (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP),
|
||||
dev_id: -1
|
||||
};
|
||||
|
||||
alen = sizeof(sa);
|
||||
if (getpeername(sk, (struct sockaddr *) &sa, &alen) < 0)
|
||||
return -1;
|
||||
bacpy(&req.dst, &sa.rc_bdaddr);
|
||||
|
||||
alen = sizeof(sa);
|
||||
if (getsockname(sk, (struct sockaddr *) &sa, &alen) < 0)
|
||||
return -1;
|
||||
bacpy(&req.src, &sa.rc_bdaddr);
|
||||
req.channel = sa.rc_channel;
|
||||
|
||||
id = ioctl(sk, RFCOMMCREATEDEV, &req);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
snprintf(tty, size, "/dev/rfcomm%d", id);
|
||||
if (stat(tty, &st) < 0) {
|
||||
snprintf(tty, size, "/dev/bluetooth/rfcomm/%d", id);
|
||||
if (stat(tty, &st) < 0) {
|
||||
snprintf(tty, size, "/dev/rfcomm%d", id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int dun_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_cleanup(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_conn(struct rfcomm_dev_info *di, unsigned long arg)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (di->state == BT_CONNECTED &&
|
||||
(di->flags & (1<<RFCOMM_REUSE_DLC)) &&
|
||||
(di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
|
||||
(di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
|
||||
|
||||
if (find_pppd(di->id, &pid)) {
|
||||
char dst[18];
|
||||
ba2str(&di->dst, dst);
|
||||
|
||||
printf("rfcomm%d: %s channel %d pppd pid %d\n",
|
||||
di->id, dst, di->channel, pid);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kill_conn(struct rfcomm_dev_info *di, unsigned long arg)
|
||||
{
|
||||
bdaddr_t *dst = (bdaddr_t *) arg;
|
||||
pid_t pid;
|
||||
|
||||
if (di->state == BT_CONNECTED &&
|
||||
(di->flags & (1<<RFCOMM_REUSE_DLC)) &&
|
||||
(di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
|
||||
(di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
|
||||
|
||||
if (dst && bacmp(&di->dst, dst))
|
||||
return 0;
|
||||
|
||||
if (find_pppd(di->id, &pid)) {
|
||||
if (kill(pid, SIGINT) < 0)
|
||||
perror("Kill");
|
||||
|
||||
if (!dst)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_show_connections(void)
|
||||
{
|
||||
for_each_port(show_conn, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_kill_connection(uint8_t *dst)
|
||||
{
|
||||
for_each_port(kill_conn, (unsigned long) dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_kill_all_connections(void)
|
||||
{
|
||||
for_each_port(kill_conn, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_open_connection(int sk, char *pppd, char **args, int wait)
|
||||
{
|
||||
char tty[100];
|
||||
int pid;
|
||||
|
||||
if (dun_create_tty(sk, tty, sizeof(tty) - 1) < 0) {
|
||||
syslog(LOG_ERR, "RFCOMM TTY creation failed. %s(%d)", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[0] = "pppd";
|
||||
args[1] = tty;
|
||||
args[2] = "nodetach";
|
||||
|
||||
pid = dun_exec(tty, pppd, args);
|
||||
if (pid < 0) {
|
||||
syslog(LOG_ERR, "Exec failed. %s(%d)", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
/* FIXME: Check for waitpid errors */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
49
dund/dund.1
Normal file
49
dund/dund.1
Normal file
@ -0,0 +1,49 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29.
|
||||
.TH BlueZ "1" "February 2003" "DUN daemon" "User Commands"
|
||||
.SH NAME
|
||||
dund \- BlueZ Bluetooth dial-up networking daemon
|
||||
.SH DESCRIPTION
|
||||
DUN daemon
|
||||
.SH SYNOPSIS
|
||||
dund <options>
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR
|
||||
Show active DUN connections
|
||||
.TP
|
||||
\fB\-\-listen\fR \fB\-s\fR
|
||||
Listen for DUN connections
|
||||
.TP
|
||||
\fB\-\-connect\fR \fB\-c\fR <bdaddr>
|
||||
Create DUN connection
|
||||
.TP
|
||||
\fB\-\-search\fR \fB\-Q[duration]\fR
|
||||
Search and connect
|
||||
.TP
|
||||
\fB\-\-kill\fR \fB\-k\fR <bdaddr>
|
||||
Kill DUN connection
|
||||
.TP
|
||||
\fB\-\-killall\fR \fB\-K\fR
|
||||
Kill all DUN connections
|
||||
.TP
|
||||
\fB\-\-channel\fR \fB\-C\fR <channel>
|
||||
RFCOMM channel
|
||||
.TP
|
||||
\fB\-\-source\fR \fB\-S\fR <bdaddr>
|
||||
Source bdaddr
|
||||
.TP
|
||||
\fB\-\-sdp\fR \fB\-D\fR
|
||||
Enable SDP
|
||||
.TP
|
||||
\fB\-\-encrypt\fR \fB\-E\fR
|
||||
Enable encryption
|
||||
.TP
|
||||
\fB\-\-master\fR \fB\-M\fR
|
||||
Become the master of a piconet
|
||||
.TP
|
||||
\fB\-\-nodetach\fR \fB\-n\fR
|
||||
Do not become a daemon
|
||||
.TP
|
||||
\fB\-\-persist\fR \fB\-p[interval]\fR
|
||||
Persist mode
|
||||
|
44
dund/dund.h
Normal file
44
dund/dund.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
dund - Bluetooth LAN/DUN daemon for BlueZ
|
||||
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* DUN scripts & commands */
|
||||
#define DUN_CONFIG_DIR "/etc/bluetooth/dun"
|
||||
|
||||
#define DUN_DEFAULT_CHANNEL 1
|
||||
|
||||
#define DUN_MAX_PPP_OPTS 40
|
||||
|
||||
/* DUN functions */
|
||||
int dun_init(void);
|
||||
int dun_cleanup(void);
|
||||
|
||||
int dun_show_connections(void);
|
||||
int dun_kill_connection(uint8_t *dst);
|
||||
int dun_kill_all_connections(void);
|
||||
|
||||
int dun_open_connection(int sk, char *pppd, char **pppd_opts, int wait);
|
||||
|
||||
/* SDP functions */
|
||||
int dun_sdp_register(uint8_t channel);
|
||||
void dun_sdp_unregister(void);
|
||||
int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel);
|
||||
|
95
dund/lib.h
Normal file
95
dund/lib.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
RFCOMMd - RFCOMM daemon.
|
||||
Copyright (C) 2001 Qualcomm Incorporated
|
||||
|
||||
Written 2001 by Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation;
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM,
|
||||
OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
|
||||
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
|
||||
USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS,
|
||||
TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
#ifndef _DUND_LIB_H
|
||||
#define _DUND_LIB_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ( (a)<(b) ? (a):(b) )
|
||||
#endif
|
||||
|
||||
/* IO cancelation */
|
||||
extern volatile sig_atomic_t __io_canceled;
|
||||
|
||||
static inline void io_init(void)
|
||||
{
|
||||
__io_canceled = 0;
|
||||
}
|
||||
|
||||
static inline void io_cancel(void)
|
||||
{
|
||||
__io_canceled = 1;
|
||||
}
|
||||
|
||||
/* Read exactly len bytes (Signal safe)*/
|
||||
static inline int read_n(int fd, char *buf, int len)
|
||||
{
|
||||
register int t = 0, w;
|
||||
|
||||
while (!__io_canceled && len > 0) {
|
||||
if ((w = read(fd, buf, len)) < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
if (!w)
|
||||
return 0;
|
||||
len -= w;
|
||||
buf += w;
|
||||
t += w;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Write exactly len bytes (Signal safe)*/
|
||||
static inline int write_n(int fd, char *buf, int len)
|
||||
{
|
||||
register int t = 0, w;
|
||||
|
||||
while (!__io_canceled && len > 0) {
|
||||
if ((w = write(fd, buf, len)) < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
if (!w)
|
||||
return 0;
|
||||
len -= w;
|
||||
buf += w;
|
||||
t += w;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int ms_dun(int fd, int server, int timeo);
|
||||
|
||||
#endif /* _DUND_LIB_H */
|
558
dund/main.c
Normal file
558
dund/main.c
Normal file
@ -0,0 +1,558 @@
|
||||
/*
|
||||
dund - Bluetooth LAN/DUN daemon for BlueZ
|
||||
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/rfcomm.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/hci_lib.h>
|
||||
|
||||
#include "dund.h"
|
||||
#include "lib.h"
|
||||
|
||||
volatile sig_atomic_t __io_canceled;
|
||||
|
||||
/* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */
|
||||
static int msdun = 0;
|
||||
|
||||
static char *pppd = "/usr/sbin/pppd";
|
||||
static char *pppd_opts[DUN_MAX_PPP_OPTS] =
|
||||
{
|
||||
/* First 3 are reserved */
|
||||
"", "", "",
|
||||
"noauth",
|
||||
"noipdefault",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int detach = 1;
|
||||
static int persist;
|
||||
static int use_sdp = 1;
|
||||
static int encrypt;
|
||||
static int master;
|
||||
static int search_duration = 10;
|
||||
static uint use_cache;
|
||||
|
||||
static int channel;
|
||||
|
||||
static struct {
|
||||
uint valid;
|
||||
char dst[40];
|
||||
bdaddr_t bdaddr;
|
||||
int channel;
|
||||
} cache;
|
||||
|
||||
static bdaddr_t src_addr = *BDADDR_ANY;
|
||||
static int src_dev = -1;
|
||||
|
||||
volatile int terminate;
|
||||
|
||||
enum {
|
||||
NONE,
|
||||
SHOW,
|
||||
LISTEN,
|
||||
CONNECT,
|
||||
KILL
|
||||
} modes;
|
||||
|
||||
static int do_listen(void)
|
||||
{
|
||||
struct sockaddr_rc sa;
|
||||
int sk;
|
||||
|
||||
if (!channel)
|
||||
channel = DUN_DEFAULT_CHANNEL;
|
||||
|
||||
if (use_sdp)
|
||||
dun_sdp_register(channel);
|
||||
|
||||
// Create RFCOMM socket
|
||||
sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
||||
if (sk < 0) {
|
||||
syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sa.rc_family = AF_BLUETOOTH;
|
||||
sa.rc_channel = channel;
|
||||
sa.rc_bdaddr = src_addr;
|
||||
|
||||
if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
|
||||
syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(sk, 10);
|
||||
|
||||
while (!terminate) {
|
||||
int alen = sizeof(sa), nsk;
|
||||
char ba[40];
|
||||
char ch[10];
|
||||
|
||||
nsk = accept(sk, (struct sockaddr *) &sa, &alen);
|
||||
if (nsk < 0) {
|
||||
syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (fork()) {
|
||||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno);
|
||||
default:
|
||||
close(nsk);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msdun && ms_dun(nsk, 1, msdun) < 0) {
|
||||
syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ba2str(&sa.rc_bdaddr, ba);
|
||||
sprintf(ch, "%d", channel);
|
||||
|
||||
/* Setup environment */
|
||||
setenv("DUN_BDADDR", ba, 1);
|
||||
setenv("DUN_CHANNEL", ch, 1);
|
||||
|
||||
if (!dun_open_connection(nsk, pppd, pppd_opts, 0))
|
||||
syslog(LOG_INFO, "New connection from %s", ba);
|
||||
|
||||
close(nsk);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (use_sdp)
|
||||
dun_sdp_unregister();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Connect and initiate RFCOMM session
|
||||
* Returns:
|
||||
* -1 - critical error (exit persist mode)
|
||||
* 1 - non critical error
|
||||
* 0 - success
|
||||
*/
|
||||
static int create_connection(char *dst, bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sockaddr_rc sa;
|
||||
int sk, err = 0, ch;
|
||||
|
||||
if (use_cache && cache.valid && cache.channel) {
|
||||
/* Use cached channel */
|
||||
ch = cache.channel;
|
||||
|
||||
} else if (!channel) {
|
||||
syslog(LOG_INFO, "Searching for %s on %s", "LAP", dst);
|
||||
|
||||
if (dun_sdp_search(&src_addr, bdaddr, &ch) <= 0)
|
||||
return 0;
|
||||
} else
|
||||
ch = channel;
|
||||
|
||||
syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch);
|
||||
|
||||
sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
||||
if (sk < 0) {
|
||||
syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sa.rc_family = AF_BLUETOOTH;
|
||||
sa.rc_channel = 0;
|
||||
sa.rc_bdaddr = src_addr;
|
||||
|
||||
if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
|
||||
syslog(LOG_ERR, "Bind failed. %s(%d)",
|
||||
strerror(errno), errno);
|
||||
|
||||
sa.rc_channel = ch;
|
||||
sa.rc_bdaddr = *bdaddr;
|
||||
|
||||
if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) {
|
||||
syslog(LOG_INFO, "Connection established");
|
||||
|
||||
if (msdun && ms_dun(sk, 0, msdun) < 0) {
|
||||
syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
|
||||
err = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0)))
|
||||
err = 0;
|
||||
else
|
||||
err = 1;
|
||||
} else {
|
||||
syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
|
||||
dst, strerror(errno), errno);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
out:
|
||||
if (use_cache) {
|
||||
if (!err) {
|
||||
/* Succesesful connection, validate cache */
|
||||
strcpy(cache.dst, dst);
|
||||
bacpy(&cache.bdaddr, bdaddr);
|
||||
cache.channel = ch;
|
||||
cache.valid = use_cache;
|
||||
} else {
|
||||
cache.channel = 0;
|
||||
cache.valid--;
|
||||
}
|
||||
}
|
||||
|
||||
close(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Search and connect
|
||||
* Returns:
|
||||
* -1 - critical error (exit persist mode)
|
||||
* 1 - non critical error
|
||||
* 0 - success
|
||||
*/
|
||||
static int do_connect(void)
|
||||
{
|
||||
inquiry_info *ii;
|
||||
int reconnect = 0;
|
||||
int i, n, r = 0;
|
||||
|
||||
do {
|
||||
if (reconnect)
|
||||
sleep(persist);
|
||||
reconnect = 1;
|
||||
|
||||
if (cache.valid) {
|
||||
/* Use cached bdaddr */
|
||||
r = create_connection(cache.dst, &cache.bdaddr);
|
||||
if (r < 0) {
|
||||
terminate = 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "Inquiring");
|
||||
|
||||
/* FIXME: Should we use non general LAP here ? */
|
||||
|
||||
ii = NULL;
|
||||
n = hci_inquiry(src_dev, search_duration, 10, NULL, &ii, 0);
|
||||
if (n < 0) {
|
||||
syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
char dst[40];
|
||||
ba2str(&ii[i].bdaddr, dst);
|
||||
|
||||
r = create_connection(dst, &ii[i].bdaddr);
|
||||
if (r < 0) {
|
||||
terminate = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(ii);
|
||||
} while (!terminate && persist);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void do_show(void)
|
||||
{
|
||||
dun_show_connections();
|
||||
}
|
||||
|
||||
static void do_kill(char *dst)
|
||||
{
|
||||
if (dst) {
|
||||
bdaddr_t ba;
|
||||
str2ba(dst, &ba);
|
||||
dun_kill_connection((void *) &ba);
|
||||
} else
|
||||
dun_kill_all_connections();
|
||||
}
|
||||
|
||||
void sig_hup(int sig)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
io_cancel();
|
||||
terminate = 1;
|
||||
}
|
||||
|
||||
static struct option main_lopts[] = {
|
||||
{ "help", 0, 0, 'h' },
|
||||
{ "listen", 0, 0, 's' },
|
||||
{ "connect", 1, 0, 'c' },
|
||||
{ "search", 2, 0, 'Q' },
|
||||
{ "kill", 1, 0, 'k' },
|
||||
{ "killall", 0, 0, 'K' },
|
||||
{ "channel", 1, 0, 'P' },
|
||||
{ "source", 1, 0, 'S' },
|
||||
{ "nosdp", 0, 0, 'D' },
|
||||
{ "list", 0, 0, 'l' },
|
||||
{ "show", 0, 0, 'l' },
|
||||
{ "nodetach", 0, 0, 'n' },
|
||||
{ "persist", 2, 0, 'p' },
|
||||
{ "encrypt", 0, 0, 'E' },
|
||||
{ "master", 0, 0, 'M' },
|
||||
{ "cache", 0, 0, 'C' },
|
||||
{ "pppd", 1, 0, 'd' },
|
||||
{ "msdun", 2, 0, 'X' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static char main_sopts[] = "hsc:k:Kr:S:lnp::DQ::EMP:C::P:X";
|
||||
|
||||
static char main_help[] =
|
||||
"LAP (LAN Access over PPP) daemon version " VERSION " \n"
|
||||
"Usage:\n"
|
||||
"\tdund <options> [pppd options]\n"
|
||||
"Options:\n"
|
||||
"\t--show --list -l Show active LAP connections\n"
|
||||
"\t--listen -s Listen for LAP connections\n"
|
||||
"\t--connect -c <bdaddr> Create LAP connection\n"
|
||||
"\t--search -Q[duration] Search and connect\n"
|
||||
"\t--kill -k <bdaddr> Kill LAP connection\n"
|
||||
"\t--killall -K Kill all LAP connections\n"
|
||||
"\t--channel -P <channel> RFCOMM channel\n"
|
||||
"\t--source -S <bdaddr> Source bdaddr\n"
|
||||
"\t--nosdp -D Disable SDP\n"
|
||||
"\t--nodetach -n Do not become a daemon\n"
|
||||
"\t--persist -p[interval] Persist mode\n"
|
||||
"\t--pppd -d <pppd> Location of the PPP daemon (pppd)\n"
|
||||
"\t--msdun -X[timeo] Enable Microsoft dialup networking support\n"
|
||||
"\t--cache -C[valid] Enable addess cache\n";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *dst = NULL, *src = NULL;
|
||||
struct sigaction sa;
|
||||
int mode = NONE;
|
||||
int opt;
|
||||
|
||||
while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
|
||||
switch(opt) {
|
||||
case 'l':
|
||||
mode = SHOW;
|
||||
detach = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
mode = LISTEN;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
mode = CONNECT;
|
||||
dst = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
mode = CONNECT;
|
||||
dst = NULL;
|
||||
if (optarg)
|
||||
search_duration = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
mode = KILL;
|
||||
detach = 0;
|
||||
dst = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
mode = KILL;
|
||||
detach = 0;
|
||||
dst = NULL;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
channel = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
src = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
use_sdp = 0;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
encrypt = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
master = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
detach = 0;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (optarg)
|
||||
persist = atoi(optarg);
|
||||
else
|
||||
persist = 5;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (optarg)
|
||||
use_cache = atoi(optarg);
|
||||
else
|
||||
use_cache = 2;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
pppd = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
if (optarg)
|
||||
msdun = atoi(optarg);
|
||||
else
|
||||
msdun = 10;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
printf(main_help);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* The rest is pppd options */
|
||||
if (argc > 0) {
|
||||
for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS; argc--, opt++)
|
||||
pppd_opts[opt] = *argv++;
|
||||
pppd_opts[opt] = NULL;
|
||||
}
|
||||
|
||||
io_init();
|
||||
|
||||
if (dun_init())
|
||||
return -1;
|
||||
|
||||
/* Check non daemon modes first */
|
||||
switch (mode) {
|
||||
case SHOW:
|
||||
do_show();
|
||||
return 0;
|
||||
|
||||
case KILL:
|
||||
do_kill(dst);
|
||||
return 0;
|
||||
|
||||
case NONE:
|
||||
printf(main_help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize signals */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_flags = SA_NOCLDSTOP;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sig_term;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sig_hup;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
if (detach) {
|
||||
int fd;
|
||||
|
||||
if (fork()) exit(0);
|
||||
|
||||
/* Direct stdin,stdout,stderr to '/dev/null' */
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
|
||||
close(fd);
|
||||
|
||||
setsid();
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
|
||||
syslog(LOG_INFO, "DUN daemon ver %s", VERSION);
|
||||
|
||||
if (src) {
|
||||
src_dev = hci_devid(src);
|
||||
if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
|
||||
syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst) {
|
||||
strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
|
||||
str2ba(dst, &cache.bdaddr);
|
||||
|
||||
/* Disable cache invalidation */
|
||||
use_cache = cache.valid = ~0;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CONNECT:
|
||||
do_connect();
|
||||
break;
|
||||
|
||||
case LISTEN:
|
||||
do_listen();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
145
dund/msdun.c
Normal file
145
dund/msdun.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
dund - Bluetooth LAN/DUN daemon for BlueZ
|
||||
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define MS_PPP 2
|
||||
#define MS_SUCCESS 1
|
||||
#define MS_FAILED -1
|
||||
#define MS_TIMEOUT -2
|
||||
|
||||
static sigjmp_buf jmp;
|
||||
static int retry;
|
||||
static int timeout;
|
||||
|
||||
static void sig_alarm(int sig)
|
||||
{
|
||||
siglongjmp(jmp, MS_TIMEOUT);
|
||||
}
|
||||
|
||||
static int w4_str(int fd, char *str)
|
||||
{
|
||||
char buf[40];
|
||||
int r, len = 0;
|
||||
|
||||
while (1) {
|
||||
r = read(fd, buf + len, sizeof(buf) - len - 1);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!r)
|
||||
break;
|
||||
|
||||
len += r;
|
||||
|
||||
if (len < strlen(str))
|
||||
continue;
|
||||
buf[len] = 0;
|
||||
|
||||
if (strstr(buf, str))
|
||||
return MS_SUCCESS;
|
||||
|
||||
/* Detect PPP */
|
||||
if (strchr(buf, '~'))
|
||||
return MS_PPP;
|
||||
}
|
||||
return MS_FAILED;
|
||||
}
|
||||
|
||||
static int ms_server(int fd)
|
||||
{
|
||||
switch (w4_str(fd, "CLIENT")) {
|
||||
case MS_SUCCESS:
|
||||
write_n(fd, "CLIENTSERVER", 12);
|
||||
case MS_PPP:
|
||||
return MS_SUCCESS;
|
||||
default:
|
||||
return MS_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static int ms_client(int fd)
|
||||
{
|
||||
write_n(fd, "CLIENT", 6);
|
||||
return w4_str(fd, "CLIENTSERVER");
|
||||
}
|
||||
|
||||
int ms_dun(int fd, int server, int timeo)
|
||||
{
|
||||
sig_t osig;
|
||||
|
||||
retry = 4;
|
||||
timeout = timeo;
|
||||
|
||||
if (!server)
|
||||
timeout /= retry;
|
||||
|
||||
osig = signal(SIGALRM, sig_alarm);
|
||||
|
||||
while (1) {
|
||||
int r = sigsetjmp(jmp, 1);
|
||||
if (r) {
|
||||
if (r == MS_TIMEOUT && !server && --retry)
|
||||
continue;
|
||||
|
||||
alarm(0);
|
||||
signal(SIGALRM, osig);
|
||||
|
||||
switch (r) {
|
||||
case MS_SUCCESS:
|
||||
case MS_PPP:
|
||||
errno = 0;
|
||||
return 0;
|
||||
|
||||
case MS_FAILED:
|
||||
errno = EPROTO;
|
||||
break;
|
||||
|
||||
case MS_TIMEOUT:
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
alarm(timeout);
|
||||
|
||||
if (server)
|
||||
r = ms_server(fd);
|
||||
else
|
||||
r = ms_client(fd);
|
||||
|
||||
siglongjmp(jmp, r);
|
||||
}
|
||||
}
|
146
dund/sdp.c
Normal file
146
dund/sdp.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
dund - Bluetooth LAN/DUN daemon for BlueZ
|
||||
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/sdp.h>
|
||||
#include <bluetooth/sdp_lib.h>
|
||||
|
||||
#include "dund.h"
|
||||
|
||||
static sdp_record_t *record;
|
||||
static sdp_session_t *session;
|
||||
|
||||
void dun_sdp_unregister(void)
|
||||
{
|
||||
if (record && sdp_record_unregister(session, record))
|
||||
syslog(LOG_ERR, "Service record unregistration failed.");
|
||||
sdp_close(session);
|
||||
}
|
||||
|
||||
int dun_sdp_register(uint8_t channel)
|
||||
{
|
||||
sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
|
||||
uuid_t root_uuid, l2cap, rfcomm, dun;
|
||||
sdp_profile_desc_t profile[1];
|
||||
sdp_list_t *proto[2];
|
||||
int status;
|
||||
|
||||
session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
|
||||
if (!session) {
|
||||
syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
record = sdp_record_alloc();
|
||||
if (!record) {
|
||||
syslog(LOG_ERR, "Failed to alloc service record");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
|
||||
root = sdp_list_append(NULL, &root_uuid);
|
||||
sdp_set_browse_groups(record, root);
|
||||
|
||||
sdp_uuid16_create(&l2cap, L2CAP_UUID);
|
||||
proto[0] = sdp_list_append(NULL, &l2cap);
|
||||
apseq = sdp_list_append(NULL, proto[0]);
|
||||
|
||||
sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
|
||||
proto[1] = sdp_list_append(NULL, &rfcomm);
|
||||
proto[1] = sdp_list_append(proto[1], sdp_data_alloc(SDP_UINT8, &channel));
|
||||
apseq = sdp_list_append(apseq, proto[1]);
|
||||
|
||||
aproto = sdp_list_append(NULL, apseq);
|
||||
sdp_set_access_protos(record, aproto);
|
||||
|
||||
sdp_uuid16_create(&dun, LAN_ACCESS_SVCLASS_ID);
|
||||
svclass = sdp_list_append(NULL, &dun);
|
||||
sdp_set_service_classes(record, svclass);
|
||||
|
||||
sdp_uuid16_create(&profile[0].uuid, LAN_ACCESS_PROFILE_ID);
|
||||
profile[0].version = 0x0100;
|
||||
pfseq = sdp_list_append(NULL, &profile[0]);
|
||||
sdp_set_profile_descs(record, pfseq);
|
||||
|
||||
sdp_set_info_attr(record, "LAN Access Point", NULL, NULL);
|
||||
|
||||
status = sdp_record_register(session, record, 0);
|
||||
if (status) {
|
||||
syslog(LOG_ERR, "SDP registration failed.");
|
||||
sdp_record_free(record); record = NULL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel)
|
||||
{
|
||||
sdp_session_t *s;
|
||||
sdp_list_t *srch, *attrs, *rsp;
|
||||
uuid_t svclass;
|
||||
uint16_t attr;
|
||||
int err;
|
||||
|
||||
s = sdp_connect(src, dst, 0);
|
||||
if (!s) {
|
||||
syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdp_uuid16_create(&svclass, LAN_ACCESS_SVCLASS_ID);
|
||||
srch = sdp_list_append(NULL, &svclass);
|
||||
|
||||
attr = SDP_ATTR_PROTO_DESC_LIST;
|
||||
attrs = sdp_list_append(NULL, &attr);
|
||||
|
||||
err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
|
||||
|
||||
sdp_close(s);
|
||||
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
for(; rsp; rsp = rsp->next) {
|
||||
sdp_record_t *rec = (sdp_record_t *) rsp->data;
|
||||
sdp_list_t *protos;
|
||||
|
||||
if (!sdp_get_access_protos(rec, &protos)) {
|
||||
int ch = sdp_get_proto_port(protos, RFCOMM_UUID);
|
||||
if (ch > 0) {
|
||||
*channel = ch;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user