Logo Search packages:      
Sourcecode: affix version File versions  Download package

btctl.c

/* 
   Affix - Bluetooth Protocol Stack for Linux
   Copyright (C) 2001 Nokia Corporation
   Original Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   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: btctl.c,v 1.165 2004/02/19 14:15:15 kassatki Exp $

   btctl - driver control program

      Fixes:      Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
*/

#include <affix/config.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/errno.h>

#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <getopt.h>
#include <string.h>
#include <termios.h>
#include <setjmp.h>

//#include <readline/readline.h>

#include <affix/bluetooth.h>
#include <affix/btcore.h>

#include "btctl.h"

int         argc;
char        **argv;
int         argind;
char        btdev[IFNAMSIZ] = "bt0";
int         nameset;
int         ftpmode = 0;
char        confdir[80];
btdev_list  _devcache;
btdev_list  *devcache;
int         showall = 0;
int         uart_rate = -1;
char        *uart_map = "/etc/affix/device.map";
int         verbose;

int cmd_inquiry(struct btctl_command *cmd)
{
      int         fd, i;
      __u32       length;
      int         err;
      INQUIRY_ITEM      devs[20];
      __u8        num;
      
      switch (cmd->cmd) {
            case 2:
                  btdev_cache_print(devcache, DEVSTATE_ALL);
                  return 0;
            case 3:
                  btdev_cache_free(devcache);
                  btdev_cache_save(devcache);
                  return 0;
      }

      if (argv[argind]) {
            sscanf(argv[argind], "%x", &length);
      } else 
            length = 8;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      printf("Searching %d sec ...\n", length);
      err = HCI_Inquiry(fd, length, 20, devs, &num);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      printf("done.\n");
      if (num == 0) {
            printf("No devices found.\n");
      } else {
            btdev_cache_reload(devcache);
            btdev_cache_retire(devcache);
            for (i = 0; i < num; i++)
                  __btdev_cache_add(devcache, devs[i].bda, devs[i].Class_of_Device, NULL);
            btdev_cache_save(devcache);
            btdev_cache_print(devcache, DEVSTATE_RANGE);
      }
      return 0;
}

int cmd_discovery(struct btctl_command *cmd)
{
      int         fd, i;
      __u32       length;
      int         err;
      INQUIRY_ITEM      devs[20];
      char        *devnames[20];
      char        namebuf[248];
      __u8        num;

      if (argv[argind]) {
            sscanf(argv[argind], "%x", &length);
      } else 
            length = 8;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      printf("Searching %d sec ...\n", length);
      err = HCI_Inquiry(fd, length, 20, devs, &num);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      if (num == 0) {
            printf("done.\nNo devices found.\n");
      } else {
            printf("Searching done. Resolving names ...\n");
            for (i = 0; i < num; i++) {
                  devs[i].Clock_Offset |= 0x8000;
                  err = HCI_RemoteNameRequest(fd, &devs[i], namebuf);
                  if (!err)
                        devnames[i] = strdup(namebuf);
                  else 
                        devnames[i] = NULL;
            }
            printf("done.\n");
            btdev_cache_reload(devcache);
            btdev_cache_retire(devcache);
            for (i = 0; i < num; i++) {
                  __btdev_cache_add(devcache, devs[i].bda, devs[i].Class_of_Device, devnames[i]);
                  if (devnames[i])
                        free(devnames[i]);
            }
            btdev_cache_save(devcache);
            btdev_cache_print(devcache, DEVSTATE_RANGE);
      }
      return 0;
}

int cmd_bdaddr(struct btctl_command *cmd)
{
      int   err, fd;
      BD_ADDR     bda;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      err = HCI_ReadBDAddr(fd, &bda);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }

      printf("Local Address: %s\n", bda2str(&bda));
      pause();

      hci_close(fd);
      return 0;
}

int cmd_name(struct btctl_command *cmd)
{
      int   err, fd;
      char  name[248];

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      if (argv[argind] == NULL) {
            // read name
            err = HCI_ReadLocalName(fd, name);
      } else {
            strncpy(name, argv[argind], 248);
            err = HCI_ChangeLocalName(fd, name);
      }
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }

      if (argv[argind] == NULL) {
            // read name
            printf("Name: %s\n", name);
      }

      hci_close(fd);
      return 0;
}

int cmd_scan(struct btctl_command *cmd)
{
      int   err, fd, flag;
      __u8  mode = HCI_SCAN_OFF;
      char  *param;

      if (!argv[argind]) {
            printf("scan mode missed\n");
            return -1;
      }
      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      while (argv[argind]) {
            param = argv[argind];
            if (param[0] == '+') flag = 1, param++;
            else if (param[0] == '-') flag = 0, param++;
            else flag = 1;

            if (strcmp(param, "disc") == 0)
                  flag ? (mode |= HCI_SCAN_INQUIRY) : (mode &= ~HCI_SCAN_INQUIRY);
            else if (strcmp(param, "conn") == 0)
                  flag ? (mode |= HCI_SCAN_PAGE) : (mode &= ~HCI_SCAN_PAGE);

            argind++;
      }
      err = HCI_WriteScanEnable(fd, mode);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}

int cmd_pincode(struct btctl_command *cmd)
{
      int         err;
      BD_ADDR           bda;
      int         Length;
      __u8        Code[16];

      if (cmd->cmd == 1 && (argv[argind] == NULL || argv[argind+1] == NULL)) {
            printf("Parameters missed\n");
            return -1;
      }

      if (argv[argind]) {
            if (strcasecmp(argv[argind], "default") == 0)
                  memset(&bda, 0, 6);
            else {
                  err = get_bda(&bda, argv[argind]);
                  if (err) {
                        printf("Incorrect address given\n");
                        return 1;
                  }
            }
            if (cmd->cmd == 1) {
                  Length = strlen(argv[argind+1]);
                  strncpy((char*)Code, argv[argind+1], 16);
                  err = hci_add_pin(&bda, Length, Code);
            } else
                  err = hci_remove_pin(&bda);
      } else
            err = hci_remove_pin(NULL);

      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      return err;
}

int cmd_key(struct btctl_command *cmd)
{
      int         err, i;
      BD_ADDR           bda;
      btdev_struct      *btdev;

      btdev_cache_reload(devcache);
      if (argv[argind]) {
            err = get_bda(&bda, argv[argind]);
            if (err) {
                  printf("Incorrect address given\n");
                  return 1;
            }
            err = hci_remove_key(&bda);
            btdev = btdev_cache_lookup(devcache, &bda);
            if (btdev)
                  btdev->flags &= ~BTDEV_KEY;
      } else {
            err = hci_remove_key(NULL);
            /* remove all keys */
            for (i = 0; (btdev = s_list_nth_data(devcache->head, i)); i++)
                  btdev->flags &= ~BTDEV_KEY;
      }
      btdev_cache_save(devcache);
      return err;
}

int cmd_security(struct btctl_command *cmd)
{
      int   err, fd, sec_flags;
      char  buf[80];

      if (!argv[argind]) {
            print_usage(cmd);
            return 1;
      }
      argv2str(buf, &argv[argind]);
      if (!str2mask(sec_mode_map, buf, &sec_flags)) {
            printf("format error\n");
            return -1;
      }
      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      err = HCI_WriteSecurityMode(fd, sec_flags);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      close(fd);
      return 0;
}



int cmd_remotename(struct btctl_command *cmd)
{
      int         err, fd;
      BD_ADDR           bda;
      INQUIRY_ITEM      dev;
      char        Name[248];

      if (argv[argind] == NULL) {
            printf("Bluetooth address missed\n");
            return -1;
      }

      err = get_bda(&bda, argv[argind]);
      if (err) {
            printf("Wrong address format\n");
            return 1;
      }

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return fd;
      }

      dev.bda = bda;
      dev.PS_Repetition_Mode = 0x00;
      dev.PS_Mode = 0x00;
      dev.Clock_Offset = 0x00;
      err = HCI_RemoteNameRequest(fd, &dev, Name);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }

      printf("Remote name: %s\n", Name);
      return 0;
}

int cmd_role(struct btctl_command *cmd)
{
      int   err, fd, role_flags = 0;
      
      if (argv[argind] == NULL) {
            print_usage(cmd);
            return -1;
      }

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      if (strcmp(argv[argind++], "deny") == 0)
            role_flags |= HCI_ROLE_DENY_SWITCH;

      if (strcmp(argv[argind++], "master") == 0)
            role_flags |= HCI_ROLE_BECOME_MASTER;

      err = hci_set_role(fd, role_flags);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}


int cmd_class(struct btctl_command *cmd)
{
      int         err, fd;
      __u32       cod;
      __u32       value;
      char        buf[80];

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      if (argv[argind] == NULL) {
            // read name
            err = HCI_ReadClassOfDevice(fd, &cod);
            if (!err) {
                  parse_cod(buf, cod);
                  printf("Class: 0x%06X, %s\n", cod, buf);
            }
      } else {
            if (strstr(argv[argind], "0x")) {
                  err = sscanf(argv[argind], "%x ", &value);
                  if (err > 0)
                        cod = value;
            } else {
                  // parse command line
                  argv2str(buf, &argv[argind]);
                  err = str2cod(buf, &cod);
                  if (err) {
                        printf("bad arguments\n");
                        return -1;
                  }
            }
            err = HCI_WriteClassOfDevice(fd, cod);
      }
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}

int cmd_auth(struct btctl_command *cmd)
{
      int         err, fd;
      int         handle;
      BD_ADDR           bda;


      if (argv[argind] == NULL) {
            print_usage(cmd);
            return -1;
      }

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      err = get_bda(&bda, argv[argind]);
      if (err) {
            printf("Wrong address format\n");
            return 1;
      }
      handle = hci_get_conn(fd, &bda);
      if (handle < 0) {
            printf("Connection not found\n");
            return 1;
      }
      err = HCI_AuthenticationRequested(fd, handle);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}

/*
 * L2CAP
 */

void print_data(__u8 *p, int len)
{
      int   i,j;
      char  buf[81];

      if (len > 100)
            return;
      for (i = 0; i < len; i++) {
            if ( ((i % 16) == 0) && i > 0)
                  printf("%s\n", buf);
            j = (i % 16) * 3;
            sprintf( &(buf[j]), "%02x ", p[i]);
      }
      if (len)
            printf("%s\n", buf);
}


int cmd_ping(struct btctl_command *cmd)
{
      int         err, fd, i;
      BD_ADDR           bda;
      struct sockaddr_affix   saddr;
      int         size;
      __u8        *data;

      if (argv[argind] == NULL || argv[argind+1] == NULL) {
            printf("parameters missing\n");
            print_usage(cmd);
            return 1;
      }

      err = get_bda(&bda, argv[argind++]);
      if (err) {
            printf("Incorrect address given\n");
            return 1;
      }
      printf("Connecting to host %s ...\n", bda2str(&bda));

      size = atoi(argv[argind++]);

      fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP);
      if (fd < 0) {
            printf("Unable to create RFCOMM socket: %d\n", PF_AFFIX);
            return 1;
      }

      saddr.bda = bda;
      saddr.port = 0;
      saddr.devnum = HCIDEV_ANY;
      err = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));
      if (err < 0) {
            printf("Unable to connect to remote side\n");
            close(fd);
            return 1;
      }

      data = (__u8*)malloc(size);
      if( data == NULL )
            return 0;

      for(i = 0; i < size; i++)
            data[i] = i;

      printf("Sending %d bytes...\n", size);
      print_data(data, size);
      if (cmd->cmd == 0) {
            err = l2cap_ping(fd, data, size);
            if (err < 0) {
                  printf("ping error\n");
                  exit(1);
            }
            printf("Received %d bytes back\n", err);
            print_data(data, err);
      } else if (cmd->cmd == 1) {
            struct timeval    tv_start, tv_end;
            long int    sec, rsec;
            long int    usec, rusec;
            double            speed;

            gettimeofday(&tv_start, NULL);
            err = l2cap_singleping(fd, data, size);
            if (err < 0) {
                  printf("ping error\n");
                  exit(1);
            }
            printf("flushing...\n");
            err = l2cap_flush(fd);
            if (err < 0) {
                  printf("flush error\n");
                  exit(1);
            }
            gettimeofday(&tv_end, NULL);              

            sec = tv_end.tv_sec - tv_start.tv_sec;
            usec = (1000000 * sec) + tv_end.tv_usec - tv_start.tv_usec;
            rsec = usec/1000000;
            rusec = (usec - (rsec * 1000000))/10000;
            speed = (double)(size)/((double)(rsec) + (double)(rusec)/100);

            printf("%d bytes sent in %ld.%ld secs (%.2f B/s)\n", size, rsec, rusec, speed);
      }

      close(fd);
      return 0;
}

void sig_handler(int sig)
{
}

int cmd_periodic_inquiry(struct btctl_command *cmd)
{
      int         fd;
      unsigned char     buf[HCI_MAX_EVENT_SIZE];
      unsigned int      max_period_len, min_period_len, length;
      int         err;
      __u8        num;
      struct Inquiry_Result_Event   *ir = (void*)buf;
      struct Inquiry_Complete_Event *ic = (void*)buf;

      /* Default values */
      length = 3;
      min_period_len = 4;
      max_period_len = 5;

      if (cmd->cmd == 0) {
            if (argv[argind]) {
                  sscanf(argv[argind++], "%d", &max_period_len);
                  if(argv[argind]) {
                              sscanf(argv[argind++], "%d", &min_period_len);
                              if(argv[argind]) {
                                    sscanf(argv[argind++], "%d", &length);
                              }
                  }
            }
      }

      num=0; /* Unlimited */
      
      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      switch (cmd->cmd) {
            case 1:
                  {
                        err = HCI_ExitPeriodicInquiryMode(fd);
                        if (err) {
                              fprintf(stderr, "%s\n", hci_error(err));
                              exit(1);
                        }
                        return 0;
                  }
      }

      err = HCI_PeriodicInquiryMode(fd, max_period_len, min_period_len, length, num);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }

      hci_event_mask(fd, COMMAND_STATUS_MASK|INQUIRY_RESULT_MASK|INQUIRY_COMPLETE_MASK);
      
      signal(SIGINT, sig_handler);
      signal(SIGTERM, sig_handler);
      signal(SIGABRT, sig_handler);
      signal(SIGQUIT, sig_handler);

      do {
            err = hci_recv_event(fd, buf, sizeof(buf), 20);
            if (err < 0) {
                  fprintf(stderr, "%s\n", hci_error(err));
                  fprintf(stderr, "Exit from Periodic Inquire Mode ...\n");
                  HCI_ExitPeriodicInquiryMode(fd);
                  exit(1);
            }
            
            if (ir->hdr.EventCode == HCI_E_INQUIRY_RESULT) {
                  int   i;
                  for (i = 0; i < ir->Num_Responses; i++) {
                        printf("Found bda: %s\n", bda2str(&ir->Results[i].bda)); 
                        
                  }
            }
      } while (1);//ic->hdr.EventCode != HCI_E_INQUIRY_COMPLETE);
      return ic->Status;
}

int cmd_link_info(struct btctl_command *cmd)
{
      int         err, fd, interval;
      BD_ADDR           bda;
      __u8        lq;
      __s8        RSSI;
      __s8        cpl;
      int         handle;

      if (argv[argind] == NULL) {
            printf("parameters missing\n");
            print_usage(cmd);
            return 1;
      }

      err = get_bda(&bda, argv[argind++]);
      if (err) {
            printf("Incorrect address given\n");
            return 1;
      }

      interval = 0; /* No loop */

      if (cmd->cmd == 3) {
            if (argv[argind] != NULL) {
                  sscanf(argv[argind], "%d", &interval);
                  if (interval <= 0 || interval > 100) {
                        printf("Interval value 1 - 100\n");
                        exit(1);
                  }
            }
      }

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      handle = hci_get_conn(fd, &bda);
      if (handle < 0) {
            printf("Connection not found\n");
            return 1;
      }

      switch (cmd->cmd) {
            case 0: /* lq */
                  {
                        err = HCI_GetLinkQuality(fd, handle, &lq);
                        if (err) {
                              fprintf(stderr, "%s\n", hci_error(err));
                              exit(1);
                        }
                        printf("Link quality: %d\n", lq);
                        break;
                  }
            case 1: /* RSSI  dBm = 10*log(P/Pref) Pref = 1 milliwatt */
                  {
                        err = HCI_ReadRSSI(fd, handle, &RSSI);
                        if (err) {
                              fprintf(stderr, "%s\n", hci_error(err));
                              exit(1);
                        }
                        printf("RSSI: %d\n", RSSI);
                        break;
                  }

            case 2: /* Transmit Power Level */
                  {
                        err = HCI_ReadTransmitPowerLevel(fd, handle, 0, &cpl);
                        /* 0 means current transmit power level */
                        if (err) {
                              fprintf(stderr, "%s\n", hci_error(err));
                              exit(1);
                        }
                        printf("Current Transmit Power Level: %d\n", cpl);
                        break;
                  }


            case 3: /* All HCI info parameters */
                  {
                        do {
                              err = HCI_ReadRSSI(fd, handle, &RSSI);
                              if (err) {
                                    fprintf(stderr, "%s\n", hci_error(err));
                                    exit(1);
                              }

                              err = HCI_GetLinkQuality(fd, handle, &lq);
                              if (err) {
                                    fprintf(stderr, "%s\n", hci_error(err));
                                    exit(1);
                              }
                              
                              err = HCI_ReadTransmitPowerLevel(fd, handle, 0, &cpl);
                              /* 0 means current transmit power level */
                              if (err) {
                                    fprintf(stderr, "%s\n", hci_error(err));
                                    exit(1);
                              }

                              printf("RSSI: %d, LQ: %d, CTPL: %d\n", RSSI, lq, cpl);
                              sleep(interval);
                        } while (interval);
                        break;
                  }


      }

      //pause();

      hci_close(fd);
      return 0;
}

int get_port(char *svc, struct sockaddr_affix *saddr)
{
#if defined(CONFIG_AFFIX_SDP)
      int         sch, err;
      uint16_t    ServiceID;
      uint16_t    count;
      slist_t           *searchList = NULL;
      slist_t           *attrList = NULL;
      slist_t           *svcList = NULL;
      sdpsvc_t    *svcRec;

      if (strncasecmp(svc, "SERial", 3) == 0)
            ServiceID = SDP_UUID_SERIAL_PORT; 
      else if (strncasecmp(svc, "DUN", 3) == 0)
            ServiceID = SDP_UUID_DUN;
      else if (strncasecmp(svc, "FAX", 3) == 0)
            ServiceID = SDP_UUID_FAX;
      else if (strncasecmp(svc, "LAN", 3) == 0)
            ServiceID = SDP_UUID_LAN;
      else if (strncasecmp(svc, "HEAdset", 3) == 0)
            ServiceID = SDP_UUID_HEADSET;
      else if (strncasecmp(svc, "AUDio", 3) == 0)
            ServiceID = SDP_UUID_HANDSFREE_AG;
      else {
            fprintf(stderr, "unknown service: %s\n", svc);
            return 1;
      }

      /* search for service ServiceID */
      s_list_append_uuid16(&searchList, ServiceID);
      /* set attributes to find */
      s_list_append_uint(&attrList, SDP_ATTR_SERVICE_RECORD_HANDLE);
      s_list_append_uint(&attrList, SDP_ATTR_PROTO_DESC_LIST);

      err = __sdp_search_attr_req(saddr, searchList, 
                  IndividualAttributes, attrList, 0xffff, &svcList, &count);
      s_list_destroy(&searchList);
      s_list_free(&attrList);
      if (err) {
            fprintf(stderr, "%s\n", sdp_error(err));
            return -1;
      }
      if (count == 0) {
            printf("no services found\n");
            return -1;
      }
      svcRec = s_list_dequeue(&svcList);  // get first
      sdp_free_svclist(&svcList);
      sch = sdp_get_rfcomm_port(svcRec);
      sdp_free_svc(svcRec);
      if (sch > 0) {
            printf("Service found on channel: %d\n", sch);
            return sch;
      } else if (sch == 0) {
            printf("Service is not available\n");
            return -1;
      } else {
            printf("Unable to get service channel\n");
            return -2;
      }
#endif
      return -1;
}

/*
 * RFCOMM stuff
 */
int cmd_connect(struct btctl_command *cmd)
{
      int         err, fd;
      BD_ADDR           bda;
      int         sch;
      int         line = RFCOMM_BTY_ANY;
      struct sockaddr_affix   saddr;

      if (argc - argind < 2) {
            printf("Parameters missing\n");
            print_usage(cmd);
            return 1;
      }

      err = get_bda(&bda, argv[argind++]);
      if (err) {
            printf("Incorrect address given\n");
            return 1;
      }
      if (cmd->cmd != 2)
            printf("Connecting to host %s ...\n", bda2str(&bda));

      saddr.family = PF_AFFIX;
      saddr.bda = bda;
      saddr.devnum = hci_devnum(btdev);//HCIDEV_ANY;

      err = sscanf(argv[argind++], "%d", &sch);

      if (argv[argind]) {
            // bty line number
            line = atoi(argv[argind]);
      }

      if (err > 0)
            goto found;

      if (!sdpmode) {
            fprintf(stderr, "SDP disabled\n");
            return 1;
      } else {
            sch = get_port(argv[argind - 1], &saddr);
            if (sch < 0)
                  return sch;
      }

found:
      if (cmd->cmd == 0)      // just sdp request for port
            return 0;

      saddr.port = sch;

      if (cmd->cmd != 2)
            printf("Connecting to channel %d ...\n", sch);

      fd = socket(PF_AFFIX, SOCK_STREAM, BTPROTO_RFCOMM);
      if (fd < 0) {
            printf("Unable to create RFCOMM socket: %d\n", PF_AFFIX);
            return 1;
      }

      if (cmd->cmd == 1) {
            // connect

            err = rfcomm_set_type(fd, RFCOMM_TYPE_BTY);
            if (err < 0) {
                  BTERROR("Unable to set RFCOMM interface type to tty");
                  close(fd);
                  return 1;
            }

            err = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));
            if (err < 0) {
                  fprintf(stderr, "Unable to connect to remote side: %s\n", strerror(errno));
                  close(fd);
                  return 1;
            }
            line = rfcomm_open_tty(fd, line);
            if (line < 0) {
                  printf("Unable to bind a port to the socket\n");
                  close(fd);
                  return 1;
            }

            printf("Connected. Bound to line %d [/dev/bty%d].\n", line, line);

      } else if (cmd->cmd == 2) {
            // bind
            line = rfcomm_bind_tty(fd, &saddr, line);
            if (line < 0) {
                  fprintf(stderr, "Unable to bind a port to the socket: %s\n", strerror(errno));
                  close(fd);
                  return 1;
            }

            printf("Bound to bda: %s, channel: %d, line %d [/dev/bty%d].\n", bda2str(&bda), sch, line, line);
      }

      close(fd);
      return 0;
}

int cmd_disconnect(struct btctl_command *cmd)
{
      int   line = -1, err;

      if (argv[argind] == NULL) {
            printf("disconnect all\n");
      } else {
            line = atoi(argv[argind]);
            printf("Disconnecting line %d [/dev/bty%d]\n", line, line);
      }
      // Disconnect here
      err = rfcomm_close_tty(line);
      if (err < 0) {
            printf("Unable to disconnect line: %d\n", line);
            return 1;
      }
      return 0;
}

int cmd_switch(struct btctl_command *cmd)
{
      int   err, fd;
      int   role;
      BD_ADDR     bda;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      err = get_bda(&bda, argv[argind++]);
      if (err) {
            printf("Incorrect address given\n");
            return 1;
      }

      if (cmd->cmd == 1) {
            /* policy */
            int   handle;
            int   policy;
            
            handle = hci_get_conn(fd, &bda);
            if (handle < 0) {
                  printf("Connection not found\n");
                  return 1;
            }
            if (argv[argind]) {
                  err = sscanf(argv[argind++], "%x", &policy);
                  if (err <= 0)
                        policy = 0x0001;
            } else
                  policy = 0x0001;

            err = HCI_WriteLinkPolicySettings(fd, handle, policy);
      } else {
            role = atoi(argv[argind++]);
            err = HCI_SwitchRole(fd, &bda, role);
      }

      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}

int cmd_status(struct btctl_command *cmd)
{
      struct rfcomm_port      info[10];
      int         count;

      count = rfcomm_get_ports(info, 10);
      if (count < 0) {
            printf("Unable to get portinfo\n");
            return 1;
      }
      if (count == 0)
            printf("No connected lines\n");
      else {
            int   i;
            struct rfcomm_port      *port = info;

            printf("Connected lines:\n");
            for (i=0; i < count; i++, port++) {
                  printf("line: %d [/dev/bty%d], bda: %s, channel: %d, flags: %s %s\n",
                              port->line, port->line, bda2str(&port->addr.bda), port->addr.port,
                              (port->flags & RFCOMM_SOCK_BOUND) ? "bound" : "\b",
                              (port->flags & RFCOMM_SOCK_CONNECTED) ? "connected" : "\b"
                              );
            }
      }
      return 0;
}


int cmd_pkttype(struct btctl_command *cmd)
{
      int   err, value, fd;
      char  buf[128];
      
      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      if (argv[argind] == NULL)
            value = 0; //set default
      else {
            if (argv[argind][0] == '0')
                  err = sscanf(argv[argind], "%x", &value);
            else {
                  argv2str(buf, &argv[argind]);
                  str2mask(pkt_type_map, buf, &value);
            }
      }

      err = hci_set_pkttype(fd, value);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;

}

int cmd_control(struct btctl_command *cmd)
{
      int   err = 0, fd;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      switch (cmd->cmd) {
            case 0:     /* page_to */
                  {
                        __u16 timeo;

                        if (argv[argind] == NULL) {
                              // read name
                              err = HCI_ReadPageTimeout(fd, &timeo);
                        } else {
                              sscanf(argv[argind], "%hu", &timeo);
                              printf("Timeo: %u\n", timeo);
                              err = HCI_WritePageTimeout(fd, timeo);
                        }
                        if (!err && argv[argind] == NULL) {
                              // read name
                              printf("Timeo: %u\n", timeo);
                        }
                  }
                  break;

            case 1:     /* hdisc */
                  {
                        struct sockaddr_affix   sa;;

                        if (argv[argind] == NULL) {
                              printf("Bluetooth address missed\n");
                              return -1;
                        }
      
                        if (strstr(argv[argind], "0x")) {
                              err = sscanf(argv[argind++], "%hx", &sa.port);
                              if (err <= 0) {
                                    printf("format error\n");
                                    return 1;
                              }
                        } else {
                              err = get_bda(&sa.bda, argv[argind++]);
                              if (err) {
                                    printf("Incorrect address given\n");
                                    return 1;
                              }
                        }
                        printf("Disconnecting %s ...\n", bda2str(&sa.bda));
                        err = hci_disconnect(&sa);
                  }
                  break;

            case 2:     /* hconnect */
                  {
                        int               err, sock;
                        struct sockaddr_affix   sa;
      
                        if (argv[argind] == NULL) {
                              printf("Bluetooth address missed\n");
                              return -1;
                        }
            
                        err = get_bda(&sa.bda, argv[argind++]);
                        if (err) {
                              printf("Incorrect address given\n");
                              return -1;
                        }

                        sock = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_HCIACL);
                        if (sock < 0) {
                              printf("unable to create affix socket\n");
                              return -1;
                        }
                        sa.family = PF_AFFIX;
                        sa.devnum = HCIDEV_ANY;
      
                        err = connect(sock, (struct sockaddr*)&sa, sizeof(sa));
                        if (err) {
                              printf("unable to create connection\n");
                              return -1;
                        }

                        return 0;

                        /*
                        INQUIRY_ITEM      dev;
                        
                        err = get_bda(&dev.bda, argv[argind++]);
                        if (err) {
                              printf("Incorrect address given\n");
                              return 1;
                        }
                        dev.PS_Repetition_Mode = 0x00;
                        dev.PS_Mode = 0x00;
                        dev.Clock_Offset = 0x00;
                        err = __HCI_CreateConnection(fd, &dev, 
                                    HCI_PT_DM1|HCI_PT_DH1|HCI_PT_DM3|HCI_PT_DH3|HCI_PT_DM5|HCI_PT_DH5, 0); */
                  }
                  break;
            case 3:     /* hpkt_type */
                  {
                        int   handle, type;
                        BD_ADDR     bda;

                        if (strstr(argv[argind], "0x")) {
                              err = sscanf(argv[argind++], "%x", &handle);
                              if (err <= 0) {
                                    printf("format error\n");
                                    return 1;
                              }
                        } else {
                              err = get_bda(&bda, argv[argind++]);
                              if (err) {
                                    printf("Incorrect address given\n");
                                    return 1;
                              }
                              handle = hci_get_conn(fd, &bda);
                              if (handle < 0) {
                                    printf("Connection not found\n");
                                    return 1;
                              }
                        }
                        if (argv[argind]) {
                              err = sscanf(argv[argind++], "%x", &type);
                              if (err <= 0)
                                    type = HCI_PT_DM1|HCI_PT_DH1|HCI_PT_DM3|HCI_PT_DH3|HCI_PT_DM5|HCI_PT_DH5;
                        } else
                              type = HCI_PT_DM1|HCI_PT_DH1|HCI_PT_DM3|HCI_PT_DH3|HCI_PT_DM5|HCI_PT_DH5;
                              
                        printf("Changing pkt_type, handle %#hx ...\n", handle);
                        err = HCI_ChangeConnectionPacketType(fd, handle, type);
                  }
            case 4:     /* read broadcast retransmissions */
                  {
                        __u8 Num;

                        err = HCI_Read_Num_Broadcast_Retransmissions(fd,&Num);
                        printf("\nRetransmissions : %d\n", Num);
                  }
                  break;
            case 5:     /* write broadcast retransmissions */
                  {
                        int num = 0;

                        if (strstr(argv[argind], "0x")) {
                              err = sscanf(argv[argind++], "%x", &num);
                              if (err <= 0) {
                                    printf("format error\n");
                                    return 1;
                              }
                        }
                        err = HCI_Write_Num_Broadcast_Retransmissions(fd,num);
                  }
                  break;
            default:
                  break;
      }
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}

int cmd_pair(struct btctl_command *cmd)
{
      int               err, fd, sock;
      struct sockaddr_affix   sa;
      int               handle;

      err = get_bda(&sa.bda, argv[argind++]);
      if (err) {
            printf("Incorrect address given\n");
            return 1;
      }

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }

      sock = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_HCIACL);
      if (sock < 0) {
            printf("unable to create affix socket\n");
            return -1;
      }
      sa.family = PF_AFFIX;
      sa.devnum = HCIDEV_ANY;
      
      err = connect(sock, (struct sockaddr*)&sa, sizeof(sa));
      if (err) {
            printf("unable to create connection\n");
            return -1;
      }

      handle = hci_get_conn(fd, &sa.bda);
      if (handle < 0) {
            printf("Connection not found\n");
            return 1;
      }
      hci_remove_key(&sa.bda);
      err = HCI_AuthenticationRequested(fd, handle);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      printf("Pairing completed: %s\n", err?"error":"successful");
      close(sock);
      hci_close(fd);

      return 0;
}


int cmd_reset(struct btctl_command *cmd)
{
      int   fd, err;

      fd = hci_open(btdev);
      if (fd < 0) {
            printf("Unable to open device %s: %s\n", btdev, strerror(errno));
            return -1;
      }
      err = HCI_Reset(fd);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      hci_close(fd);
      return 0;
}


int cmd_debug(struct btctl_command *cmd)
{
      int   err, flag, i, addmod;
      __u32 dbmask;
      char  *param;

      err = hci_get_dbmask(&dbmask);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      addmod = dbmask;
      while (argv[argind]) {
            param = argv[argind];
            if (param[0] == '+') flag = 1, param++;
            else if (param[0] == '-') flag = 0, param++;
            else flag = 1;

            for (i = 0; debug_flags_map[i].match; i++) {
                  if (strcasecmp(param, debug_flags_map[i].match) == 0)
                        break;
            }
            if (!debug_flags_map[i].match) {
                  fprintf(stderr, "invalid argument: %s\n", param);
                  return 1;
            }
            flag?(dbmask|=debug_flags_map[i].value):(dbmask&=~debug_flags_map[i].value);
            if (!addmod && flag == 1 && (dbmask & DBALLMOD)) {
                  dbmask |= DBALLDETAIL;
                  addmod = 1;
            }
            argind++;
      }
      err = hci_set_dbmask(dbmask);
      if (err) {
            fprintf(stderr, "%s\n", hci_error(err));
            exit(1);
      }
      return 0;
}

int print_devinfo(char *dev)
{
      int         err = 0, fd;
      char        name[248], buf[80];
      __u32       cod;
      __u8        val;
      __u8        hci_version, lmp_version;
      __u16       hci_revision, manf_name, lmp_subversion;
      __u64       lmp_features;
      __u16       acl_len, acl_num, sco_num;
      __u8        sco_len;
      struct hci_dev_attr     da;


      err = hci_get_attr(dev, &da);
      if (err < 0) {
            printf("Unable to get attr: %s\n", dev);
            return err;
      }

      printf("%s\t%s\n", da.name, bda2str(&da.bda));
      if (!verbose) {
            printf("\tFlags: %s %s %s\n", 
                        (da.flags & HCI_FLAGS_UP)?"UP":"DOWN", 
                        (da.flags & HCI_FLAGS_SCAN_INQUIRY)?"DISC":"\b",
                        (da.flags & HCI_FLAGS_SCAN_PAGE)?"CONN":"\b");
            printf("\tRX: acl:%lu sco:%lu event:%lu bytes:%lu errors:%lu dropped:%lu\n",
                        da.stats.rx_acl, da.stats.rx_sco, da.stats.rx_event, da.stats.rx_bytes,
                        da.stats.rx_errors, da.stats.rx_dropped);
            printf("\tTX: acl:%lu sco:%lu cmd:%lu bytes:%lu errors:%lu dropped:%lu\n",
                        da.stats.tx_acl, da.stats.tx_sco, da.stats.tx_cmd, da.stats.tx_bytes, 
                        da.stats.tx_errors, da.stats.tx_dropped);
            mask2str(sec_mode_map, buf, da.flags & ~(HCI_SECURITY_AUTH|HCI_SECURITY_ENCRYPT));
            printf("\tSecurity: %s [%cauth, %cencrypt]\n", buf, 
                        (da.flags & HCI_SECURITY_AUTH)?'+':'-',
                        (da.flags & HCI_SECURITY_ENCRYPT)?'+':'-'); 
            mask2str(pkt_type_map, buf, da.pkt_type);
            printf("\tPackets: %s\n", buf);

            printf("\tRole: %s, ", (da.flags & HCI_ROLE_DENY_SWITCH)?"deny switch":"allow switch");
            printf("%s\n", (da.flags & HCI_ROLE_BECOME_MASTER)?"become master":"remain slave");
            printf("\n");
            return 0;
      }

      if (!(da.flags & HCI_FLAGS_UP)) {
            printf("\tDevice is down\n\n");
            return 0;
      }

      fd = hci_open(dev);
      if (fd < 0) {
            printf("Unable to open: %s\n\n", dev);
            return 0;
      }

      err = HCI_ReadLocalName(fd, name);
      if (err)
            goto exit;
      printf("\tName: \"%s\"\n", name);

      err = HCI_ReadClassOfDevice(fd, &cod);
      if (err)
            goto exit;
      parse_cod(buf, cod); 
      printf("\tClass: 0x%06X, %s\n", cod, buf);

      err = HCI_ReadScanEnable(fd, &val);
      if (err)
            goto exit;
      printf("\tScan Mode: %s, %s\n", (val&0x01)?"discoverable":"non-discoverable",
                  (val&0x02)?"connectable":"non-connectable");

      mask2str(sec_mode_map, buf, da.flags & ~(HCI_SECURITY_AUTH|HCI_SECURITY_ENCRYPT));
      printf("\tSecurity: %s [%cauth, %cencrypt]\n", buf, 
                  (da.flags & HCI_SECURITY_AUTH)?'+':'-',
                  (da.flags & HCI_SECURITY_ENCRYPT)?'+':'-'); 
      
      mask2str(pkt_type_map, buf, da.pkt_type);
      printf("\tPackets: %s\n", buf);

      printf("\tRole: %s, ", (da.flags & HCI_ROLE_DENY_SWITCH)?"deny switch":"allow switch");
      printf("%s\n", (da.flags & HCI_ROLE_BECOME_MASTER)?"become master":"remain slave");

      err = HCI_ReadLocalVersionInformation(fd, &hci_version, &hci_revision, &lmp_version,
                  &manf_name, &lmp_subversion);
      if (err)
            goto exit;
      printf("\tBaseband:\n\t\tManufacture: %s, id: %d\n\t", 
                  (manf_name<NUM_LMPCOMPID)?lmp_compid[manf_name]:"Unknown", manf_name);
      printf("\tFeatures: %s compliant\n", lmp_version?"1.1":"1.0");
      
      // Read buffer information
      err = HCI_ReadBufferSize(fd, &acl_len, &sco_len, &acl_num, &sco_num);
      if (err)
            goto exit;
      printf("\tBuffers:\n");
      printf("\t\tACL: %d x %d bytes\n", acl_num, acl_len);
      printf("\t\tSCO: %d x %d bytes\n", sco_num, sco_len);

      // Read Supported Features
      err = HCI_ReadLocalSupportedFeatures(fd, &lmp_features);
      if (err)
            goto exit;
      
      printf("\tSuported features:");
      
      mask2str_comma(packets_features_map, buf, lmp_features);
      printf("\n\t\tPacket types: %s", (lmp_features&HCI_LF_PACKETS)?buf:"none");

      mask2str_comma(radio_features_map, buf, lmp_features);
      printf("\n\t\tRadio features: %s", (lmp_features&HCI_LF_RADIO)?buf:"none");

      mask2str_comma(policy_features_map, buf, lmp_features);
      printf("\n\t\tPolicy: %s", (lmp_features&HCI_LF_POLICY)?buf:"not supported");

      printf("\n\t\tEncryption: %s", (lmp_features&HCI_LF_ENCRYPTION)?"supported":"not supported");

      mask2str_comma(timing_features_map, buf, lmp_features);
      printf("\n\t\tClock modes: %s", (lmp_features&HCI_LF_TIMING)?buf:"none");

      mask2str_comma(audio_features_map, buf, lmp_features);
      printf("\n\t\tAudio: %s", (lmp_features&HCI_LF_AUDIO)?buf:"not supported");
      
      printf("\n\t\tPower Control: %s", (lmp_features&HCI_LF_POWER_CONTROL)?"supported":"not supported");
exit:
      printf("\n\n");
      close(fd);
      if (err){
            fprintf(stderr, "%s\n", hci_error(err));
            return 1;
      }
      return 0;
}

int devinfo(void)
{
      int         err = 0;
      int         i, num;
      struct hci_dev_attr     da;
      int         devs[HCI_MAX_DEVS];

      if (nameset)
            return print_devinfo(btdev);

      num = hci_get_devs(devs);
      if (num < 0) {
            fprintf(stderr, "%s\n", hci_error(num));
            exit(1);
            return num;
      }
      if (num == 0) {
            printf("No Bluetooth Adapters found\n");
            return 0;
      }
      for (i = 0; i < num; i++) {
            err = hci_get_attr_id(devs[i], &da);
            if (err < 0) {
                  printf("Unable to get attr: %d\n", devs[i]);
                  continue;
            }
            err = print_devinfo(da.name);
            if (err)
                  return err;
      }
      return 0;
}

int cmd_test(struct btctl_command *cmd)
{
#if 0
      {
            struct Write_Current_IAC_LAP  cmd;
            struct Inquiry                event;
            INQUIRY_ITEM                  Item;
            printf("sizeof(lap) = %d, sizeof(cmd) = %d, sizeof(event) = %d, sizeof(Item) = %d\n",
                        sizeof(cmd.IAC_LAP[0]), sizeof(cmd), sizeof(event), sizeof(Item));
            printf("bda: %p, cod: %p\n", &Item.bda, &Item.bda+1);
            return 0;
      
      }
#endif
      return 0;
}

int cmd_disabled(int cmd)
{
      printf("\n-->> Command disabled at compilation time. Enable certain configuration options. <<--\n\n");
      return 0;
}

struct btctl_command cmds[] = {
      {0, 0, 0, 0, "---->>>> General commands <<<<----\n"},
      {"help", cmd_help, 0, "<command name>"},
      {"debug", cmd_debug, 0, "[+|-][<module>|<detail>|all]",
            "\tmodule:\thcicore|afhci|hcisched|hcimgr|hcilib|hci|\n"
            "\t\tpl2cap|afl2cap|l2cap|\n"
            "\t\tprfcomm|afrfcomm|bty|rfcomm|\n"
            "\t\tpan|\n"
            "\t\tdrv|\n"
            "\t\tallmod\n"
            "\tdetail: ctrl|dump|chardump|parse|fname|func|alldetail\n"
      },
      {"initdev", cmd_initdev, CMD_INITDEV, "<type> [params...]",
      },
      {"up", cmd_initdev, CMD_UPDEV, "", "brings interface up\n"},
      {"down", cmd_initdev, CMD_DOWNDEV, "", "brings interface down\n"},
      {"capture", cmd_capture, 0, "<file> | -", 
            "capture traffic on a HCI interface\n"
            "examples: btctl capture mylog.log\n"
            "          btctl capture - | ethereal -i - -k\n"
      },
      {"list", cmd_inquiry, 2, "", "shows know/found devices\n"
      },
      {"flush", cmd_inquiry, 3, "", "removes all know devices from the cache\n"
      },
      {"prompt", cmd_prompt, 0, "", "enter interactive mode\n"},
      /* security */
      {0, 0, 0, 0, "---->>>> Security commands <<<<----\n"},
      {"security", cmd_security, 0, "<mode>",
            "mode: <open|link|service> [auth] [encrypt]\n",
      },
      {"addpin", cmd_pincode, 1, "[<address>|default] <pin>",
            "add pin code to the driver (used when no btsrv or AFE run)\n"},
            
      {"rmpin", cmd_pincode, 0, "[<address>|default]",
            "remove pin code from the driver\n"},
            
      {"unbond", cmd_key, 0, "[<address>]",
            "remove link key from the driver\n",
      },
      {"pair", cmd_pair, 0, "<address>", "start paring with remote device\n"},
      /* HCI */
      {0, 0, 0, 0, "---->>>> HCI commands <<<<----\n"},
      {"inquiry", cmd_inquiry, 1, "[length]",
            "search for the device\n"
      },
      {"discovery", cmd_discovery, 1, "[length]",
            "search for the devices and resolve their names\n"
      },
      {"bdaddr", cmd_bdaddr, 1, "", "read device address\n"
      },
      {"name", cmd_name, 1, "[<name>]",
            "get or set device name\n"
      },
      {"scan", cmd_scan, 1, "[+|-][disc|conn]"
      },
      {"remotename", cmd_remotename, 1, "<bda>", "resolve remote device name\n"
      },
      {"role", cmd_role, 1, "<allow|deny> <master|slave>"
      },
      {"class", cmd_class, 1, "[<class> | <major> <minor> <service1> ... <servicen>]",
            "\tmajor:\tcomputer|phone|audio\n"
            "\tminor:\tdesktop|laptop|hand|server|lap\n"
            "\tservice:\tnetworking,information,rendring,capturing,audio,transfer,telephony\n"
      },
      {"auth", cmd_auth, 0, "<address>",
            "authenticate remote device\n"
      },
      {"pkt_type", cmd_pkttype, 0, "[<0xXXX> | <mnemonic>]",
            "\tmnemonic: DM1 DH1 DM3 DH3 DM5 DH5 HV1 HV2 HV3>]\n"
      },
      {"page_to", cmd_control, 0, "[to]",
            "get/set page timeout\n"
      },
      {"hdisc", cmd_control, 1, "<handle | address>", "disconnect ACL/SCO link\n"
      },
      {"hconnect", cmd_control, 2, "<address>", "create ACL connection\n"
      },
      {"hpkt", cmd_control, 3, "<address> [pkt_type]", "change pkt_type\n"
      },
      {"readbroad", cmd_control, 4, "", "Read Broadcast Retransmissions\n"
      },
      {"writebroad", cmd_control, 5, "", "Write Broadcast Retransmissions\n"
      },
      {"reset", cmd_reset, 0, "", "reset device\n"
      },
      {"ping", cmd_ping, 0, "<bda> <size>",
            "Send ping packet to remote device\n"
      },
      {"lq", cmd_link_info, 0, "<bda>",
            "Show link quality\n"
      },
      {"rssi", cmd_link_info, 1, "<bda>",
            "Show Received Signal Strength Indication (RSSI)\n"
      },
      {"cpl", cmd_link_info, 2, "<bda>",
            "Show Current Transmit Power Level (CTPL)\n"
      },
      {"linkinfo", cmd_link_info, 3, "<bda> [<interval>]",
            "Show HCI debug dump\n"
      },
      {"pinq_start", cmd_periodic_inquiry, 0, 
            "<length> [<max_period_len> <min_period_len> <len>]",
            "Start periodic inquiry mode\n"
      },
      {"pinq_stop", cmd_periodic_inquiry, 1, "<length>",
            "Stop periodic inquiry mode start\n"
      },
      {"speed", cmd_ping, 1,
      },
      /* UART */
#if defined(CONFIG_AFFIX_UART)
      {0, 0, 0, 0, "---->>>> UART commands <<<<----\n"},
      {"init_uart", cmd_uart, CMD_INIT_UART, "<name> <vendor> [speed] [flags]",
            "open UART interface\n"
            "\tvendor: any|csr|ericsson|...]\n"
      },
      {"open_uart", cmd_uart, CMD_OPEN_UART, "<name> <vendor> [speed] [flags]",
            "open UART interface\n"
            "\tvendor: any|csr|ericsson|...]\n"
      },
      {"close_uart", cmd_uart, CMD_CLOSE_UART, "<name>"
      },
#else
#endif
      /* AUDIO */
#if defined(CONFIG_AFFIX_AUDIO)
      {0, 0, 0, 0, "---->>>> AUDIO commands <<<<----\n"},
      {"path", cmd_audio, 0, "0x00 | 0x01", "set Ericsson SCO data path"
      },
      {"audio", cmd_audio, 1, "on|off [sync | async] [setting <SCO setting>]",
            "enable/disable audio (SCO) support\n"
      },
      {"scoflow", cmd_audio, 2,
      },
      {"addsco", cmd_addsco, 0,
      },
      {"play", cmd_play, 0, "<bda> [<file> | -]",
            "send an audio stream from a file or stdin to remote device\n"
      },
      {"record", cmd_record, 0, "<bda> [<file> | -]",
            "store an audio stream in a file or stdout received from remote device\n"
      },
#else
#endif
      /* RFCOMM */
#if defined(CONFIG_AFFIX_RFCOMM) || defined(CONFIG_AFFIX_RFCOMM_MOD)
      {0, 0, 0, 0, "---->>>> RFCOMM commands <<<<----\n"},
      {"port", cmd_connect, 0, "<address> [channel | service]", 
            "Make SDP request to get RFCOMM server channel for a service"
      },
      {"connect", cmd_connect, 1, "<address> [channel | service] [line number]",
            "create RFCOMM connection.\n"
            "\tservice_type: SERial | DUN | FAX | LAN | HEAdset.\n"
      },
      {"bind", cmd_connect, 2, "<address> [channel | service] [line number]",
            "bind RFCOMM connection.\n"
      },
      {"disconnect", cmd_disconnect, 1, "[line]",
            "disconnect RFCOMM port\n"
      },
      {"status", cmd_status, 1, "", "shows connected lines\n"
      },
#else
#endif
      /* SDP */
#if defined(CONFIG_AFFIX_SDP)
      {0, 0, 0, 0, "---->>>> SDP commands <<<<----\n"},
      {"browse", cmd_browse, 0, "<address>",
            "browse for services on remote device\n"
      },
      {"search", cmd_search, 0, "<address>",
            "search for services on remote device\n"
            "notes: used if browse does not find anything, because\n"
            "some devices does not suport browseing\n"
      },
#else
#endif
      /* OBEX */
#if defined(CONFIG_AFFIX_OBEX)
      {0, 0, 0, 0, "---->>>> OBEX commands <<<<----\n"},
      {"ftp", cmd_prompt, 0, "", "enter interactive mode\n"
      },
      {"open", cmd_open, 0, "<address> [<channel>]",
            "open connection to obex ftp server\n"
      },
      {"close", cmd_close, 0, "", "close connection to obex ftp server\n"
      },
      {"ls", cmd_ls, 0, "[<address> [<channel>]]"
      },
      {"put", cmd_put, 0, "[<address> [<channel>]] <local-file> [remote-file]"
      },
      {"get", cmd_get, 0, "[<address> [<channel>]] <remote-file> [local-file]"
      },
      {"push", cmd_push, 0, "<address> [<channel>] <local-file> [remote-file]"
      },
      {"rm", cmd_rm, 0, "[<address> [<channel>]] <remote-file>"
      },
      {"cd", cmd_cd, 0, "<dir name>"
      },
      {"mkdir", cmd_mkdir, 0, "<dir name>"
      },
#else
#endif
      /* PAN */
#if defined(CONFIG_AFFIX_PAN) || defined(CONFIG_AFFIX_PAN_MOD)
      {0, 0, 0, 0, "---->>>> PAN commands <<<<----\n"},
      {"paninit", cmd_pan_init, CMD_PAN_INIT, "[role] [flags]",
            "\tinitialize PAN\n"
            "\trole: panu, nap, gn\n"
      },
      {"panstop", cmd_pan_init, CMD_PAN_STOP, "",
            "\tstop PAN\n"
      },
      {"pandiscovery", cmd_pan_discovery, 0, "[service]",
            "discover PAN device.\n"
            "service: panu, nap, gn\n"
      },
      {"panconnect", cmd_pan_connect, 0, "<address> [service]",
            "connects to the NAP service.\n"
            "service: nap, gn\n"
      },
      {"pandisconnect", cmd_pan_disconnect, 0, "",
            "close connection to connected service.\n"
      },
      {"panctl", cmd_panctl, 2, "<interface> [m (start_addr stop_addr)* ] [p (range_start range_stop)* ]",
            "Examples:\n"
            "\t1. lists all filters of PAN device pan0:\n"
            "\t   panctl pan0\n"
            "\t2. set multicast filter to 03:00:00:20:00:00 only:\n"
            "\t   panctl pan0 m 03:00:00:20:00:00 03:00:00:20:00:00\n"
            "\t3. set protocol filter to range 0x800 - 0x801 and 0x806\n"
            "\t   panctl pan0 p 0x800 0x801 0x806 0x806\n"
            "\t4. reset protocol filter\n"
            "\t   panctl pan0 p\n"
      },
#else
#endif
      {0, 0, 0, 0, "---->>>> Testing commands <<<<----\n"},
      {"test", cmd_test, 0, },
      {"switch", cmd_switch, 0, },
      {"policy", cmd_switch, 1, },
      {0, 0, 0, NULL}
};

int cmdnum = sizeof(cmds)/sizeof(cmds[0]);

void print_help(struct btctl_command *cmd)
{
      if (cmd->name)
            printf("usage: %s %s\n", cmd->name, cmd->arg?cmd->arg:"");
      if (cmd->msg)
            printf("description:\n%s", cmd->msg);

}

void print_usage(struct btctl_command *cmd)
{
      printf("usage: %s %s\n", cmd->name, cmd->arg?cmd->arg:"");
}

int cmd_help(struct btctl_command *cmd)
{
      int   i;

      if (!argv[argind]) {
            print_usage(cmd);
            exit(0);
      }

      for (i = 0; i < cmdnum; i++) {
            if (cmds[i].name)
                  if (strcmp(cmds[i].name, argv[argind]) == 0) {
                        print_help(&cmds[i]);
                        return 0;
                  }
      }
      printf("invalid command: %s\n", argv[argind]);
      return      0;
}

void usage(void)
{
      int   i;
      
      printf("Usage: btctl [-i <name>] [-a] [--nosdp | -s] [<command> [parameters..]>\n");

      for (i = 0; i < cmdnum; i++) {
            if (cmds[i].name && cmds[i].arg)
                  printf("%s %s\n", cmds[i].name, cmds[i].arg);
            else if (cmds[i].msg)
                  printf("%s", cmds[i].msg);
      }

      printf("\n"
            "Notes:\n"
            "\t1. *address* argument can be replaced by cache entry number (btctl list)\n"
            "\t2. *--nosdp* option required to manually define server channel\n"
            "\t3. use *search* command if *browse* returns nothing\n"
            "\t4. argument *channel* is not used in SDP mode\n"
            "\t5. arguments *address* and *channel* are not used with\n"
            "\t   commands: *ls*, *get*, *put*, *rm* in FTP (prompt) mode\n"
            "\n"
            );
}

/* Command line mode */
static inline int white_space(char c)
{
      return (c == ' ' || c == '\t');
}
static inline int end_line(char c)
{
      return (c == '\n' || c == '\0');
}

static inline char *find_non_white(char *str)
{
      while (white_space(*str))
            str++;
      return (!end_line(*str)?str:NULL);
}

static inline char *find_white(char *str)
{
      while (!end_line(*str) && !white_space(*str))
            str++;
      return str;
}

static inline char *find_char(char *str, char c)
{
      while (*str && *str != c)
            str++;
      return (*str?str:NULL);
}

char *get_string(char **str)
{
      char  *first, *next;
      int   quotes = 0;

      if (*str == NULL)
            return NULL;
      first = find_non_white(*str);
      if (first == NULL)
            return NULL;

      if (*first == '"') {
            quotes = 1;
            first++;
      }
      next = first;
      if (quotes) {
            next = find_char(next, '"');
            if (!next) {
                  printf("parse error\n");
                  return NULL;
            }
            *next = '\0';
            next++;
      } else {
            next = find_white(next);
            if (*next) {
                  *next = '\0';
                  next++;
            }
      }

      if (*next)
            next = find_non_white(next);

      *str = next;
      return first;
}


char **parse_command_line(char *str)
{
      static char *_argv[32]; // for 32 arguments
      char  *arg;
      int   i;

      _argv[0] = argv[0];
      for (i = 1; (arg = get_string(&str)) ; i++) {
            _argv[i] = arg;
            //printf("argv[%d]: %s\n", i, arg);
      }
      _argv[i] = NULL;

      return (i>1)?_argv:NULL;
}

sigjmp_buf  sigj;

void signal_handler(int sig)
{
      if (sig == SIGINT) {
            printf("\n");
            siglongjmp(sigj, 0);
      }
      BTINFO("Sig handler : %d", sig);
#if defined(CONFIG_AFFIX_OBEX)
      cmd_close(0);
#endif
      printf("Terminating on signal (%d) ...\n", sig);
      exit(0);
}

int cmd_prompt(struct btctl_command *_cmd)
{
      char  cmd_line[80], *str, **cmd;
      int   err;

      affix_logmask |= 0xffff;//BTDEBUG_MODULE_OBEX;
      ftpmode = 1;

      /* install signal handlers to unregister services from SDP */
      signal(SIGCHLD, SIG_IGN);
      signal(SIGINT, signal_handler);           // CTRL-C
      signal(SIGTERM, signal_handler);
      signal(SIGABRT, signal_handler);
      signal(SIGQUIT, signal_handler);

      printf("Affix version: %s\n", affix_version);
      printf("Wellcome to OBEX ftp. Type ? for help.\n");
      printf("Mode: %s\n", linkmode == PF_INET ? "TCP" : "Bluetooth");
      printf("SDP: %s\n", sdpmode?"yes":"no");
      for (;;) {
            sigsetjmp(sigj, 1);
            printf("ftp> ");
            // get a line
            str = fgets(cmd_line, 80, stdin);
            //str = readline("ftp> ");
            if (str == NULL) {
                  //printf("\n");
                  break;
            }
            //printf("got: %s, len: %d\n", str, strlen(str));
            cmd = parse_command_line(str);
            if (cmd == NULL)
                  continue;
            argv = cmd++;
            argind = 2;
            if (strcasecmp(*cmd, "quit") == 0) {
                  printf("Bye!!!\n");
                  break;
            } else if (strcasecmp(*cmd, "mode") == 0) {
                  if (argv[argind]) {
                        if (strcasecmp(argv[argind], "tcp") == 0)
                              linkmode = PF_INET;
                        else
                              linkmode = PF_AFFIX;
                  }
                  printf("Mode: %s\n", linkmode == PF_INET ? "TCP" : "Bluetooth");
            } else if (strcasecmp(*cmd, "lls") == 0) {
                  system("ls");
            } else if (strcasecmp(*cmd, "lcd") == 0) {
                  char  *name;

                  if (argv[argind] == NULL) {
                        printf("No dir name.\n");
                        continue;
                  }
                  name = argv[argind];
                  chdir(name);
            } else if (strcasecmp(*cmd, "debug") == 0) {
                  affix_logmask |= 0xffff;//BTDEBUG_MODULE_OBEX;
            } else if (strcasecmp(*cmd, "?") == 0 || strcasecmp(*cmd, "help") == 0) {
                  usage();
            } else if (strcasecmp(*cmd, "sdp") == 0) {
                  sdpmode = !sdpmode;
                  printf("sdp: %s\n", sdpmode?"yes":"no");
            } else {
                  int   i;
                  for (i = 0; i < cmdnum || (printf("Invalid command.\n") && 0); i++)
                        if (cmds[i].name)
                              if (strcmp(cmds[i].name, *cmd) == 0) {
                                    err = cmds[i].func(&cmds[i]);
                                    break;
                              }
            }
      }

#if defined(CONFIG_AFFIX_OBEX)
      cmd_close(0);
#endif
      printf("Terminating ...\n");
      ftpmode = 0;
      return 0;
}


int main(int _argc, char **_argv)
{
      int   c, lind, i, err = 0;
      char  cachefile[80];

      struct option     opts[] = {
            {"help", 0, 0, 'h'},
            {"tcp", 0, 0, 't'},
            {"nosdp", 0, 0, 's'},
            {"speed", 1, 0, 'r'},
            {"version", 0, 0, 'V'},
            {0, 0, 0, 0}
      };
      
      if (affix_init()) {
            fprintf(stderr, "Affix initialization failed\n");
            return 1;
      }

      /* set environment */
      argc = _argc;
      argv = _argv;

      openlog(_argv[0], LOG_PERROR, LOG_USER);
      
      if (getuid() == 0) {
            /* root -> put the stuff to /var/spool/affix */
            sprintf(confdir, "/var/spool/affix");
      } else
            sprintf(confdir, "%s/.bluetooth", getenv("HOME"));
      err = rmkdir(confdir, 0700);
      if (err < 0) {
            perror("Unable to create dir\n");
            return 1;
      }
      sprintf(cachefile, "%s/devcache", confdir);
      devcache = &_devcache;
      btdev_cache_load(cachefile, devcache);

#if defined(CONFIG_AFFIX_SDP)
      sdpmode = 1;
#else
      sdpmode = 0;
#endif

      for (;;) {
            c = getopt_long(argc, argv, "+htrvsVam:i:r:", opts, &lind);
            if (c == -1)
                  break;
            switch (c) {
                  case 'h':
                        usage();
                        return 0;
                        break;
                  case 'v':
                        verbose = 1;
                        break;
                  case 'i':
                        strncpy(btdev, optarg, IFNAMSIZ);
                        break;
                  case 't':
                        linkmode = PF_INET;
                        break;
                  case 's':
                        sdpmode = 0;
                        break;
                  case 'a':
                        showall = 1;
                        break;
                  case 'r':
                        uart_rate = atoi(optarg);
                        break;
                  case 'm':
                        uart_map = optarg;
                        break;
                  case 'V':
                        printf("Affix version: %s\n", affix_version);
                        return 0;
                        break;
                  case ':':
                        printf("Missing parameters for option: %c\n", optopt);
                        return 1;
                        break;
                  case '?':
                        printf("Unknown option: %c\n", optopt);
                        return 1;
                        break;
            }
      }
      affix_logmask = 0xffff;
      argind = optind;
      if (argv[argind] && sscanf(argv[argind], "bt%d", &i) > 0) {
            /* interface name */
            sprintf(btdev, "bt%d", i);
            argind++;
            nameset = 1;
      }
      if (strcmp(argv[0], "btftp") == 0) {
            err = cmd_prompt(NULL);
            goto exit;
      }
      if (argv[argind] == NULL) {
            err = devinfo();
            goto exit;
      }
      for (i = 0; i < cmdnum; i++) {
            if (cmds[i].name)
                  if (strcmp(cmds[i].name, argv[argind]) == 0) {
                        argind++;
                        err = cmds[i].func(&cmds[i]);
                        break;
                  }
      }
      if (i == cmdnum)
            printf("Invalid command: %s\n", argv[argind]);
exit:
      btdev_cache_free(devcache);
      return err;
}



Generated by  Doxygen 1.6.0   Back to index