1/* 2 * 3 * Copyright 2010 Haiku Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Many parts 7 * 8 * Copyright 2001 The Aerospace Corporation. 9 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 10 * All rights reserved. 11 * Distributed under the terms of the 2-clause BSD license. 12 * 13 * Authors: 14 * Alex Botero-Lowry, alex.boterolowry@gmail.com 15 */ 16 17#include <ctype.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <strings.h> 21#include <string.h> 22 23#include <sys/ioctl.h> 24#include <sys/kernel.h> 25#include <sys/sockio.h> 26#include <sys/types.h> 27#include <sys/socket.h> 28 29#include <net/if.h> 30 31#include <net80211/ieee80211_ioctl.h> 32#include <net80211/ieee80211_haiku.h> 33 34 35extern const char* __progname; 36 37 38static const char* 39get_string(const char* val, const char* sep, u_int8_t* buf, int* lenp) 40{ 41 int len; 42 int hexstr; 43 u_int8_t* p; 44 45 len = *lenp; 46 p = buf; 47 hexstr = (val[0] == '0' && tolower((u_char) val[1]) == 'x'); 48 if (hexstr) 49 val += 2; 50 for (;;) { 51 if (*val == '\0') 52 break; 53 if (sep != NULL && strchr(sep, *val) != NULL) { 54 val++; 55 break; 56 } 57 if (hexstr) { 58 if (!isxdigit((u_char) val[0])) { 59 printf("%s: bad hexadecimal digits", __func__); 60 return NULL; 61 } 62 if (!isxdigit((u_char) val[1])) { 63 printf("%s: odd count hexadecimal digits", __func__); 64 return NULL; 65 } 66 } 67 if (p >= buf + len) { 68 if (hexstr) 69 printf("%s: hexadecimal digits too long", __func__); 70 else 71 printf("%s: string too long", __func__); 72 return NULL; 73 } 74 if (hexstr) { 75#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 76 *p++ = (tohex((u_char) val[0]) << 4) 77 | tohex((u_char) val[1]); 78#undef tohex 79 val += 2; 80 } else 81 *p++ = *val++; 82 } 83 len = p - buf; 84 /* The string "-" is treated as the empty string. */ 85 if (!hexstr && len == 1 && buf[0] == '-') { 86 len = 0; 87 memset(buf, 0, *lenp); 88 } else if (len < *lenp) 89 memset(p, 0, *lenp - len); 90 91 *lenp = len; 92 return val; 93} 94 95 96static void 97set80211(int s, const char* dev, int type, int val, int len, void* data) 98{ 99 struct ieee80211req ireq; 100 101 (void)memset(&ireq, 0, sizeof(ireq)); 102 (void)strncpy(ireq.i_name, dev, sizeof(ireq.i_name)); 103 ireq.i_type = type; 104 ireq.i_val = val; 105 ireq.i_len = len; 106 ireq.i_data = data; 107 if (ioctl(s, SIOCS80211, &ireq, sizeof(struct ieee80211req)) < 0) { 108 fprintf(stderr, "%s: error in handling SIOCS80211 (type %d): %s\n", 109 __progname, type, strerror(errno)); 110 } 111} 112 113 114static void 115set80211ssid(const char* dev, const char* val, int s) 116{ 117 int ssid; 118 int len; 119 u_int8_t data[IEEE80211_NWID_LEN]; 120 121 ssid = 0; 122 len = strlen(val); 123 if (len > 2 && isdigit((int)val[0]) && val[1] == ':') { 124 ssid = atoi(val) - 1; 125 val += 2; 126 } 127 bzero(data, sizeof(data)); 128 len = sizeof(data); 129 if (get_string(val, NULL, data, &len) == NULL) 130 exit(1); 131 132 set80211(s, dev, IEEE80211_IOC_SSID, ssid, len, data); 133} 134 135 136static void 137set80211nwkey(const char* dev, const char* val, int s) 138{ 139 int txkey; 140 int i; 141 int len; 142 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 143 144 set80211(s, dev, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 145 146 if (isdigit((int)val[0]) && val[1] == ':') { 147 txkey = val[0] - '0' - 1; 148 val += 2; 149 150 for (i = 0; i < 4; i++) { 151 bzero(data, sizeof(data)); 152 len = sizeof(data); 153 val = get_string(val, ",", data, &len); 154 if (val == NULL) 155 exit(1); 156 157 set80211(s, dev, IEEE80211_IOC_WEPKEY, i, len, data); 158 } 159 } else { 160 bzero(data, sizeof(data)); 161 len = sizeof(data); 162 get_string(val, NULL, data, &len); 163 txkey = 0; 164 165 set80211(s, dev, IEEE80211_IOC_WEPKEY, 0, len, data); 166 167 bzero(data, sizeof(data)); 168 for (i = 1; i < 4; i++) 169 set80211(s, dev, IEEE80211_IOC_WEPKEY, i, 0, data); 170 } 171 172 set80211(s, dev, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 173} 174 175 176static int 177get80211val(int s, const char* dev, int type, int* val) 178{ 179 struct ieee80211req ireq; 180 181 (void) memset(&ireq, 0, sizeof(ireq)); 182 (void) strncpy(ireq.i_name, dev, sizeof(ireq.i_name)); 183 ireq.i_type = type; 184 if (ioctl(s, SIOCG80211, &ireq) < 0) 185 return -1; 186 *val = ireq.i_val; 187 return 0; 188} 189 190 191static int 192getid(int s, const char* dev, int ix, void* data, size_t len, int* plen, 193 int mesh) 194{ 195 struct ieee80211req ireq; 196 197 (void)memset(&ireq, 0, sizeof(ireq)); 198 (void)strncpy(ireq.i_name, dev, sizeof(ireq.i_name)); 199 ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID; 200 ireq.i_val = ix; 201 ireq.i_data = data; 202 ireq.i_len = len; 203 if (ioctl(s, SIOCG80211, &ireq) < 0) 204 return -1; 205 *plen = ireq.i_len; 206 return 0; 207} 208 209 210static void 211print_string(const u_int8_t* buf, int len) 212{ 213 int i; 214 int hasspc; 215 216 i = 0; 217 hasspc = 0; 218 for (; i < len; i++) { 219 if (!isprint(buf[i]) && buf[i] != '\0') 220 break; 221 if (isspace(buf[i])) 222 hasspc++; 223 } 224 if (i == len) { 225 if (hasspc || len == 0 || buf[0] == '\0') 226 printf("\"%.*s\"", len, buf); 227 else 228 printf("%.*s", len, buf); 229 } else { 230 printf("0x"); 231 for (i = 0; i < len; i++) 232 printf("%02x", buf[i]); 233 } 234} 235 236 237static void 238show_status(const char* dev, int s) 239{ 240 int len; 241 int i; 242 int num; 243 uint8_t data[32]; 244 245 if (getid(s, dev, -1, data, sizeof(data), &len, 0) < 0) { 246 fprintf(stderr, "error: not a wifi device\n"); 247 exit(1); 248 } 249 250 if (get80211val(s, dev, IEEE80211_IOC_NUMSSIDS, &num) < 0) 251 num = 0; 252 printf("ssid "); 253 if (num > 1) { 254 for (i = 0; i < num; i++) { 255 if (getid(s, dev, i, data, sizeof(data), &len, 0) >= 0 256 && len > 0) { 257 printf(" %d:", i + 1); 258 print_string(data, len); 259 } 260 } 261 } else 262 print_string(data, len); 263 264 printf("\n"); 265} 266 267 268static void 269usage() 270{ 271 fprintf(stderr, "usage: setwep device_path [ssid] [key]\n"); 272 exit(1); 273} 274 275 276int 277main(int argc, char** argv) 278{ 279 int s = socket(AF_INET, SOCK_DGRAM, 0); 280 281 if (argc < 2) 282 usage(); 283 284 if (argc == 2) 285 show_status(argv[1], s); 286 287 if (argc > 3) 288 set80211ssid(argv[1], argv[2], s); 289 290 if (argc == 4) 291 set80211nwkey(argv[1], argv[3], s); 292 293 return 0; 294} 295