1 /* 2 * l2control.c 3 * 4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: l2control.c,v 1.5 2002/09/04 21:30:40 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <bitstring.h> 35 #include <assert.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <ng_hci.h> 39 #include <ng_l2cap.h> 40 #include <ng_btsocket.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include "l2control.h" 46 47 /* Prototypes */ 48 static int do_l2cap_command (bdaddr_p, int, char **); 49 static struct l2cap_command * find_l2cap_command (char const *, 50 struct l2cap_command *); 51 static void print_l2cap_command (struct l2cap_command *); 52 static void usage (void); 53 54 /* Main */ 55 int 56 main(int argc, char *argv[]) 57 { 58 int n; 59 bdaddr_t bdaddr; 60 61 memset(&bdaddr, 0, sizeof(bdaddr)); 62 63 /* Process command line arguments */ 64 while ((n = getopt(argc, argv, "a:")) != -1) { 65 switch (n) { 66 case 'a': { 67 int a0, a1, a2, a3, a4, a5; 68 69 if (sscanf(optarg, "%x:%x:%x:%x:%x:%x", 70 &a5, &a4, &a3, &a2, &a1, &a0) != 6) { 71 usage(); 72 break; 73 } 74 75 bdaddr.b[0] = (a0 & 0xff); 76 bdaddr.b[1] = (a1 & 0xff); 77 bdaddr.b[2] = (a2 & 0xff); 78 bdaddr.b[3] = (a3 & 0xff); 79 bdaddr.b[4] = (a4 & 0xff); 80 bdaddr.b[5] = (a5 & 0xff); 81 } break; 82 83 default: 84 usage(); 85 break; 86 } 87 } 88 89 argc -= optind; 90 argv += optind; 91 92 if (*argv == NULL) 93 usage(); 94 95 return (do_l2cap_command(&bdaddr, argc, argv)); 96 } /* main */ 97 98 /* Execute commands */ 99 static int 100 do_l2cap_command(bdaddr_p bdaddr, int argc, char **argv) 101 { 102 char *cmd = argv[0]; 103 struct l2cap_command *c = NULL; 104 struct sockaddr_l2cap sa; 105 int s, e, help; 106 107 help = 0; 108 if (strcasecmp(cmd, "help") == 0) { 109 argc --; 110 argv ++; 111 112 if (argc <= 0) { 113 fprintf(stdout, "Supported commands:\n"); 114 print_l2cap_command(l2cap_commands); 115 fprintf(stdout, "\nFor more information use " \ 116 "'help command'\n"); 117 118 return (OK); 119 } 120 121 help = 1; 122 cmd = argv[0]; 123 } 124 125 c = find_l2cap_command(cmd, l2cap_commands); 126 if (c == NULL) { 127 fprintf(stdout, "Unknown command: \"%s\"\n", cmd); 128 return (ERROR); 129 } 130 131 if (!help) { 132 if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0) 133 usage(); 134 135 memset(&sa, 0, sizeof(sa)); 136 sa.l2cap_len = sizeof(sa); 137 sa.l2cap_family = AF_BLUETOOTH; 138 memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr)); 139 140 s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP); 141 if (s < 0) 142 err(1, "Could not create socket"); 143 144 if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) 145 err(2, 146 "Could not bind socket, bdaddr=%x:%x:%x:%x:%x:%x", 147 sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4], 148 sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2], 149 sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]); 150 151 if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) 152 err(2, 153 "Could not connect socket, bdaddr=%x:%x:%x:%x:%x:%x", 154 sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4], 155 sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2], 156 sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]); 157 158 e = 0x0ffff; 159 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0) 160 err(3, "Coult not setsockopt(RCVBUF, %d)", e); 161 162 e = (c->handler)(s, -- argc, ++ argv); 163 164 close(s); 165 } else 166 e = USAGE; 167 168 switch (e) { 169 case OK: 170 case FAILED: 171 break; 172 173 case ERROR: 174 fprintf(stdout, "Could not execute command \"%s\". %s\n", 175 cmd, strerror(errno)); 176 break; 177 178 case USAGE: 179 fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); 180 break; 181 182 default: assert(0); break; 183 } 184 185 return (e); 186 } /* do_l2cap_command */ 187 188 /* Try to find command in specified category */ 189 static struct l2cap_command * 190 find_l2cap_command(char const *command, struct l2cap_command *category) 191 { 192 struct l2cap_command *c = NULL; 193 194 for (c = category; c->command != NULL; c++) { 195 char *c_end = strchr(c->command, ' '); 196 197 if (c_end != NULL) { 198 int len = c_end - c->command; 199 200 if (strncasecmp(command, c->command, len) == 0) 201 return (c); 202 } else if (strcasecmp(command, c->command) == 0) 203 return (c); 204 } 205 206 return (NULL); 207 } /* find_l2cap_command */ 208 209 /* Try to find command in specified category */ 210 static void 211 print_l2cap_command(struct l2cap_command *category) 212 { 213 struct l2cap_command *c = NULL; 214 215 for (c = category; c->command != NULL; c++) 216 fprintf(stdout, "\t%s\n", c->command); 217 } /* print_l2cap_command */ 218 219 /* Usage */ 220 static void 221 usage(void) 222 { 223 fprintf(stdout, "Usage: l2control -a BD_ADDR cmd [p1] [..]]\n"); 224 exit(255); 225 } /* usage */ 226 227