xref: /freebsd/tools/tools/ath/athkey/athkey.c (revision 61e21613)
1 /*-
2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include "diag.h"
31 
32 #include "ah.h"
33 #include "ah_internal.h"
34 
35 #include <string.h>
36 #include <stdlib.h>
37 #include <err.h>
38 #include <ctype.h>
39 #include <getopt.h>
40 
41 const char *progname;
42 
43 static int
44 toint(int c)
45 {
46 	return isdigit(c) ? c - '0' : isupper(c) ? c - 'A' + 10 : c - 'a' + 10;
47 }
48 
49 static int
50 getdata(const char *arg, u_int8_t *data, size_t maxlen)
51 {
52 	const char *cp = arg;
53 	int len;
54 
55 	if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))
56 		cp += 2;
57 	len = 0;
58 	while (*cp) {
59 		int b0, b1;
60 		if (cp[0] == ':' || cp[0] == '-' || cp[0] == '.') {
61 			cp++;
62 			continue;
63 		}
64 		if (!isxdigit(cp[0])) {
65 			fprintf(stderr, "%s: invalid data value %c (not hex)\n",
66 				progname, cp[0]);
67 			exit(-1);
68 		}
69 		b0 = toint(cp[0]);
70 		if (cp[1] != '\0') {
71 			if (!isxdigit(cp[1])) {
72 				fprintf(stderr, "%s: invalid data value %c "
73 					"(not hex)\n", progname, cp[1]);
74 				exit(-1);
75 			}
76 			b1 = toint(cp[1]);
77 			cp += 2;
78 		} else {			/* fake up 0<n> */
79 			b1 = b0, b0 = 0;
80 			cp += 1;
81 		}
82 		if (len > maxlen) {
83 			fprintf(stderr,
84 				"%s: too much data in %s, max %llu bytes\n",
85 				progname, arg, (unsigned long long) maxlen);
86 		}
87 		data[len++] = (b0<<4) | b1;
88 	}
89 	return len;
90 }
91 
92 /* XXX this assumes 5212 key types are common to 5211 and 5210 */
93 
94 static int
95 getcipher(const char *name)
96 {
97 #define	streq(a,b)	(strcasecmp(a,b) == 0)
98 
99 	if (streq(name, "wep"))
100 		return HAL_CIPHER_WEP;
101 	if (streq(name, "tkip"))
102 		return HAL_CIPHER_TKIP;
103 	if (streq(name, "aes-ocb") || streq(name, "ocb"))
104 		return HAL_CIPHER_AES_OCB;
105 	if (streq(name, "aes-ccm") || streq(name, "ccm") ||
106 	    streq(name, "aes"))
107 		return HAL_CIPHER_AES_CCM;
108 	if (streq(name, "ckip"))
109 		return HAL_CIPHER_CKIP;
110 	if (streq(name, "none") || streq(name, "clr"))
111 		return HAL_CIPHER_CLR;
112 
113 	fprintf(stderr, "%s: unknown cipher %s\n", progname, name);
114 	exit(-1);
115 #undef streq
116 }
117 
118 static void
119 usage(void)
120 {
121 	fprintf(stderr, "usage: %s [-i device] keyix cipher keyval [mac]\n",
122 		progname);
123 	exit(-1);
124 }
125 
126 int
127 main(int argc, char *argv[])
128 {
129 	const char *ifname;
130 	struct ath_diag atd;
131 	HAL_DIAG_KEYVAL setkey;
132 	const char *cp;
133 	int s, c;
134 	u_int16_t keyix;
135 	int op = HAL_DIAG_SETKEY;
136 	int xor = 0;
137 
138 	s = socket(AF_INET, SOCK_DGRAM, 0);
139 	if (s < 0)
140 		err(1, "socket");
141 	ifname = getenv("ATH");
142 	if (!ifname)
143 		ifname = ATH_DEFAULT;
144 
145 	progname = argv[0];
146 	while ((c = getopt(argc, argv, "di:x")) != -1)
147 		switch (c) {
148 		case 'd':
149 			op = HAL_DIAG_RESETKEY;
150 			break;
151 		case 'i':
152 			ifname = optarg;
153 			break;
154 		case 'x':
155 			xor = 1;
156 			break;
157 		default:
158 			usage();
159 			/*NOTREACHED*/
160 		}
161 	argc -= optind;
162 	argv += optind;
163 	if (argc < 1)
164 		usage();
165 
166 	keyix = (u_int16_t) atoi(argv[0]);
167 	if (keyix > 127)
168 		errx(-1, "%s: invalid key index %s, must be [0..127]",
169 			progname, argv[0]);
170 	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
171 	atd.ad_id = op | ATH_DIAG_IN | ATH_DIAG_DYN;
172 	atd.ad_out_data = NULL;
173 	atd.ad_out_size = 0;
174 	switch (op) {
175 	case HAL_DIAG_RESETKEY:
176 		atd.ad_in_data = (caddr_t) &keyix;
177 		atd.ad_in_size = sizeof(u_int16_t);
178 		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
179 			err(1, "ioctl: %s", atd.ad_name);
180 		return 0;
181 	case HAL_DIAG_SETKEY:
182 		if (argc != 3 && argc != 4)
183 			usage();
184 		memset(&setkey, 0, sizeof(setkey));
185 		setkey.dk_keyix = keyix;
186 		setkey.dk_xor = xor;
187 		setkey.dk_keyval.kv_type = getcipher(argv[1]);
188 		setkey.dk_keyval.kv_len = getdata(argv[2],
189 		    setkey.dk_keyval.kv_val, sizeof(setkey.dk_keyval.kv_val));
190 		/* XXX MIC */
191 		if (argc == 4)
192 			(void) getdata(argv[3], setkey.dk_mac,
193 				IEEE80211_ADDR_LEN);
194 		atd.ad_in_data = (caddr_t) &setkey;
195 		atd.ad_in_size = sizeof(setkey);
196 		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
197 			err(1, "ioctl: %s", atd.ad_name);
198 		return 0;
199 	}
200 	return -1;
201 }
202