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