1185743Ssam/*- 2185743Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185743Ssam * All rights reserved. 4185743Ssam * 5185743Ssam * Redistribution and use in source and binary forms, with or without 6185743Ssam * modification, are permitted provided that the following conditions 7185743Ssam * are met: 8185743Ssam * 1. Redistributions of source code must retain the above copyright 9185743Ssam * notice, this list of conditions and the following disclaimer, 10185743Ssam * without modification. 11185743Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12185743Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13185743Ssam * redistribution must be conditioned upon including a substantially 14185743Ssam * similar Disclaimer requirement for further binary redistribution. 15185743Ssam * 16185743Ssam * NO WARRANTY 17185743Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18185743Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19185743Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20185743Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21185743Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22185743Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23185743Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24185743Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25185743Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26185743Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27185743Ssam * THE POSSIBILITY OF SUCH DAMAGES. 28185743Ssam * 29185743Ssam * $FreeBSD$ 30185743Ssam */ 31185743Ssam 32185743Ssam#include "diag.h" 33185743Ssam 34185743Ssam#include "ah.h" 35185743Ssam#include "ah_internal.h" 36185743Ssam 37185743Ssam#include <string.h> 38185743Ssam#include <stdlib.h> 39185743Ssam#include <err.h> 40185743Ssam#include <ctype.h> 41185743Ssam#include <getopt.h> 42185743Ssam 43185743Ssamconst char *progname; 44185743Ssam 45185743Ssamstatic int 46185743Ssamtoint(int c) 47185743Ssam{ 48185743Ssam return isdigit(c) ? c - '0' : isupper(c) ? c - 'A' + 10 : c - 'a' + 10; 49185743Ssam} 50185743Ssam 51185743Ssamstatic int 52185743Ssamgetdata(const char *arg, u_int8_t *data, size_t maxlen) 53185743Ssam{ 54185743Ssam const char *cp = arg; 55185743Ssam int len; 56185743Ssam 57185743Ssam if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) 58185743Ssam cp += 2; 59185743Ssam len = 0; 60185743Ssam while (*cp) { 61185743Ssam int b0, b1; 62185743Ssam if (cp[0] == ':' || cp[0] == '-' || cp[0] == '.') { 63185743Ssam cp++; 64185743Ssam continue; 65185743Ssam } 66185743Ssam if (!isxdigit(cp[0])) { 67185743Ssam fprintf(stderr, "%s: invalid data value %c (not hex)\n", 68185743Ssam progname, cp[0]); 69185743Ssam exit(-1); 70185743Ssam } 71185743Ssam b0 = toint(cp[0]); 72185743Ssam if (cp[1] != '\0') { 73185743Ssam if (!isxdigit(cp[1])) { 74185743Ssam fprintf(stderr, "%s: invalid data value %c " 75185743Ssam "(not hex)\n", progname, cp[1]); 76185743Ssam exit(-1); 77185743Ssam } 78185743Ssam b1 = toint(cp[1]); 79185743Ssam cp += 2; 80185743Ssam } else { /* fake up 0<n> */ 81185743Ssam b1 = b0, b0 = 0; 82185743Ssam cp += 1; 83185743Ssam } 84185743Ssam if (len > maxlen) { 85185743Ssam fprintf(stderr, 86244963Sadrian "%s: too much data in %s, max %llu bytes\n", 87244963Sadrian progname, arg, (unsigned long long) maxlen); 88185743Ssam } 89185743Ssam data[len++] = (b0<<4) | b1; 90185743Ssam } 91185743Ssam return len; 92185743Ssam} 93185743Ssam 94185743Ssam/* XXX this assumes 5212 key types are common to 5211 and 5210 */ 95185743Ssam 96185743Ssamstatic int 97185743Ssamgetcipher(const char *name) 98185743Ssam{ 99185743Ssam#define streq(a,b) (strcasecmp(a,b) == 0) 100185743Ssam 101185743Ssam if (streq(name, "wep")) 102185743Ssam return HAL_CIPHER_WEP; 103185743Ssam if (streq(name, "tkip")) 104185743Ssam return HAL_CIPHER_TKIP; 105185743Ssam if (streq(name, "aes-ocb") || streq(name, "ocb")) 106185743Ssam return HAL_CIPHER_AES_OCB; 107185743Ssam if (streq(name, "aes-ccm") || streq(name, "ccm") || 108185743Ssam streq(name, "aes")) 109185743Ssam return HAL_CIPHER_AES_CCM; 110185743Ssam if (streq(name, "ckip")) 111185743Ssam return HAL_CIPHER_CKIP; 112185743Ssam if (streq(name, "none") || streq(name, "clr")) 113185743Ssam return HAL_CIPHER_CLR; 114185743Ssam 115185743Ssam fprintf(stderr, "%s: unknown cipher %s\n", progname, name); 116185743Ssam exit(-1); 117185743Ssam#undef streq 118185743Ssam} 119185743Ssam 120185743Ssamstatic void 121185743Ssamusage(void) 122185743Ssam{ 123185743Ssam fprintf(stderr, "usage: %s [-i device] keyix cipher keyval [mac]\n", 124185743Ssam progname); 125185743Ssam exit(-1); 126185743Ssam} 127185743Ssam 128185743Ssamint 129185743Ssammain(int argc, char *argv[]) 130185743Ssam{ 131185743Ssam const char *ifname; 132185743Ssam struct ath_diag atd; 133185743Ssam HAL_DIAG_KEYVAL setkey; 134185743Ssam const char *cp; 135185743Ssam int s, c; 136185743Ssam u_int16_t keyix; 137185743Ssam int op = HAL_DIAG_SETKEY; 138185743Ssam int xor = 0; 139185743Ssam 140185743Ssam s = socket(AF_INET, SOCK_DGRAM, 0); 141185743Ssam if (s < 0) 142185743Ssam err(1, "socket"); 143185743Ssam ifname = getenv("ATH"); 144185743Ssam if (!ifname) 145185743Ssam ifname = ATH_DEFAULT; 146185743Ssam 147185743Ssam progname = argv[0]; 148185743Ssam while ((c = getopt(argc, argv, "di:x")) != -1) 149185743Ssam switch (c) { 150185743Ssam case 'd': 151185743Ssam op = HAL_DIAG_RESETKEY; 152185743Ssam break; 153185743Ssam case 'i': 154185743Ssam ifname = optarg; 155185743Ssam break; 156185743Ssam case 'x': 157185743Ssam xor = 1; 158185743Ssam break; 159185743Ssam default: 160185743Ssam usage(); 161185743Ssam /*NOTREACHED*/ 162185743Ssam } 163185743Ssam argc -= optind; 164185743Ssam argv += optind; 165185743Ssam if (argc < 1) 166185743Ssam usage(); 167185743Ssam 168185743Ssam keyix = (u_int16_t) atoi(argv[0]); 169185743Ssam if (keyix > 127) 170185743Ssam errx(-1, "%s: invalid key index %s, must be [0..127]", 171185743Ssam progname, argv[0]); 172185743Ssam strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 173185743Ssam atd.ad_id = op | ATH_DIAG_IN | ATH_DIAG_DYN; 174185743Ssam atd.ad_out_data = NULL; 175185743Ssam atd.ad_out_size = 0; 176185743Ssam switch (op) { 177185743Ssam case HAL_DIAG_RESETKEY: 178185743Ssam atd.ad_in_data = (caddr_t) &keyix; 179185743Ssam atd.ad_in_size = sizeof(u_int16_t); 180185743Ssam if (ioctl(s, SIOCGATHDIAG, &atd) < 0) 181244963Sadrian err(1, "ioctl: %s", atd.ad_name); 182185743Ssam return 0; 183185743Ssam case HAL_DIAG_SETKEY: 184185743Ssam if (argc != 3 && argc != 4) 185185743Ssam usage(); 186185743Ssam memset(&setkey, 0, sizeof(setkey)); 187185743Ssam setkey.dk_keyix = keyix; 188185743Ssam setkey.dk_xor = xor; 189185743Ssam setkey.dk_keyval.kv_type = getcipher(argv[1]); 190185743Ssam setkey.dk_keyval.kv_len = getdata(argv[2], 191185743Ssam setkey.dk_keyval.kv_val, sizeof(setkey.dk_keyval.kv_val)); 192185743Ssam /* XXX MIC */ 193185743Ssam if (argc == 4) 194185743Ssam (void) getdata(argv[3], setkey.dk_mac, 195185743Ssam IEEE80211_ADDR_LEN); 196185743Ssam atd.ad_in_data = (caddr_t) &setkey; 197185743Ssam atd.ad_in_size = sizeof(setkey); 198185743Ssam if (ioctl(s, SIOCGATHDIAG, &atd) < 0) 199244963Sadrian err(1, "ioctl: %s", atd.ad_name); 200185743Ssam return 0; 201185743Ssam } 202185743Ssam return -1; 203185743Ssam} 204