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.3 2003/04/27 19:45:34 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:h")) != -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 case 'h': 84 default: 85 usage(); 86 break; 87 } 88 } 89 90 argc -= optind; 91 argv += optind; 92 93 if (*argv == NULL) 94 usage(); 95 96 return (do_l2cap_command(&bdaddr, argc, argv)); 97 } /* main */ 98 99 /* Execute commands */ 100 static int 101 do_l2cap_command(bdaddr_p bdaddr, int argc, char **argv) 102 { 103 char *cmd = argv[0]; 104 struct l2cap_command *c = NULL; 105 struct sockaddr_l2cap sa; 106 int s, e, help; 107 108 help = 0; 109 if (strcasecmp(cmd, "help") == 0) { 110 argc --; 111 argv ++; 112 113 if (argc <= 0) { 114 fprintf(stdout, "Supported commands:\n"); 115 print_l2cap_command(l2cap_commands); 116 fprintf(stdout, "\nFor more information use " \ 117 "'help command'\n"); 118 119 return (OK); 120 } 121 122 help = 1; 123 cmd = argv[0]; 124 } 125 126 c = find_l2cap_command(cmd, l2cap_commands); 127 if (c == NULL) { 128 fprintf(stdout, "Unknown command: \"%s\"\n", cmd); 129 return (ERROR); 130 } 131 132 if (!help) { 133 if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0) 134 usage(); 135 136 memset(&sa, 0, sizeof(sa)); 137 sa.l2cap_len = sizeof(sa); 138 sa.l2cap_family = AF_BLUETOOTH; 139 memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr)); 140 141 s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP); 142 if (s < 0) 143 err(1, "Could not create socket"); 144 145 if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) 146 err(2, 147 "Could not bind socket, bdaddr=%x:%x:%x:%x:%x:%x", 148 sa.l2cap_bdaddr.b[5], sa.l2cap_bdaddr.b[4], 149 sa.l2cap_bdaddr.b[3], sa.l2cap_bdaddr.b[2], 150 sa.l2cap_bdaddr.b[1], sa.l2cap_bdaddr.b[0]); 151 152 e = 0x0ffff; 153 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0) 154 err(3, "Coult not setsockopt(RCVBUF, %d)", e); 155 156 e = (c->handler)(s, -- argc, ++ argv); 157 158 close(s); 159 } else 160 e = USAGE; 161 162 switch (e) { 163 case OK: 164 case FAILED: 165 break; 166 167 case ERROR: 168 fprintf(stdout, "Could not execute command \"%s\". %s\n", 169 cmd, strerror(errno)); 170 break; 171 172 case USAGE: 173 fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); 174 break; 175 176 default: assert(0); break; 177 } 178 179 return (e); 180 } /* do_l2cap_command */ 181 182 /* Try to find command in specified category */ 183 static struct l2cap_command * 184 find_l2cap_command(char const *command, struct l2cap_command *category) 185 { 186 struct l2cap_command *c = NULL; 187 188 for (c = category; c->command != NULL; c++) { 189 char *c_end = strchr(c->command, ' '); 190 191 if (c_end != NULL) { 192 int len = c_end - c->command; 193 194 if (strncasecmp(command, c->command, len) == 0) 195 return (c); 196 } else if (strcasecmp(command, c->command) == 0) 197 return (c); 198 } 199 200 return (NULL); 201 } /* find_l2cap_command */ 202 203 /* Try to find command in specified category */ 204 static void 205 print_l2cap_command(struct l2cap_command *category) 206 { 207 struct l2cap_command *c = NULL; 208 209 for (c = category; c->command != NULL; c++) 210 fprintf(stdout, "\t%s\n", c->command); 211 } /* print_l2cap_command */ 212 213 /* Usage */ 214 static void 215 usage(void) 216 { 217 fprintf(stdout, "Usage: l2control -a BD_ADDR [-h] cmd [p1] [..]]\n"); 218 exit(255); 219 } /* usage */ 220 221