Use .Nm properly and streamline the wording a bit.
[dragonfly/port-amd64.git] / usr.sbin / acxcontrol / acxcontrol.c
blobf08305b70adc6559c8c83660ee53504e18201b1d
1 /*
2 * Copyright (c) 2006 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com> and
6 * Sascha Wildner <swildner@gmail.com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * $DragonFly: src/usr.sbin/acxcontrol/acxcontrol.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
40 #include <sys/mman.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/sysctl.h>
45 #include <net/if.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <libgen.h>
51 #include <limits.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sysexits.h>
56 #include <unistd.h>
58 #define SIOCSLOADFW _IOW('i', 137, struct ifreq) /* load firmware */
59 #define SIOCGRADIO _IOW('i', 138, struct ifreq) /* get radio type */
60 #define SIOCGSTATS _IOW('i', 139, struct ifreq) /* get acx stats */
61 #define SIOCSKILLFW _IOW('i', 140, struct ifreq) /* free firmware */
62 #define SIOCGFWVER _IOW('i', 141, struct ifreq) /* get firmware ver */
63 #define SIOCGHWID _IOW('i', 142, struct ifreq) /* get hardware id */
65 #define RADIO_FW_FMT "radio%02x"
67 static int do_req(const char *, unsigned long, void *);
68 static void get_statistics(const char *);
69 static void kill_firmware(const char *);
70 static void load_firmware(const char *, const char *, int);
71 static void mmap_file(const char *, uint8_t **, int *);
72 static void usage(void);
74 struct firmware {
75 uint8_t *base_fw;
76 int base_fw_len;
77 uint8_t *radio_fw;
78 int radio_fw_len;
81 struct firmware_head {
82 uint32_t fwh_cksum;
83 uint32_t fwh_len;
86 struct statistic {
87 int index;
88 const char *desc;
91 static const struct statistic tbl[] = {
92 { 1, "Invalid param in TX description" },
93 { 2, "No WEP key exists" },
94 { 3, "MSDU timeouts" },
95 { 4, "Excessive TX retries" },
96 { 5, "Buffer overflows" },
97 { 6, "DMA errors" },
98 { 7, "Unknown errors" },
99 { -1, NULL }
102 static int
103 do_req(const char *iface, unsigned long req, void *data)
105 int s;
106 struct ifreq ifr;
107 int error;
109 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
110 err(EX_OSERR, "Can't create socket");
112 memset(&ifr, 0, sizeof(ifr));
113 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
114 ifr.ifr_data = data;
115 error = ioctl(s, req, &ifr);
117 close(s);
119 return error;
122 static void
123 get_statistics(const char *iface)
125 uint32_t i;
126 uint64_t stats[16];
127 const struct statistic *stt;
129 if (do_req(iface, SIOCGHWID, &i) == -1)
130 err(EX_OSERR, "Can't get hardware ID");
131 printf("Hardware ID 0x%x\n", i);
133 if (do_req(iface, SIOCGFWVER, &i) == -1)
134 err(EX_OSERR, "Can't get firmware version");
135 printf("Firmware Version 0x%x\n", i);
137 if (do_req(iface, SIOCGSTATS, &stats) == -1)
138 err(EX_OSERR, "Can't get statistics");
140 for (stt = tbl; stt->index != -1; stt++)
141 printf("%-30s %qd\n", stt->desc, stats[stt->index]);
144 static void
145 kill_firmware(const char *iface)
147 if (do_req(iface, SIOCSKILLFW, NULL) == -1)
148 err(EX_OSERR, "Can't kill firmware");
151 static void
152 load_firmware(const char *iface, const char *filename, int uncombined)
154 char radio_name[FILENAME_MAX];
155 struct firmware fw;
157 memset(&fw, 0, sizeof(fw));
158 mmap_file(filename, &fw.base_fw, &fw.base_fw_len);
160 if (uncombined) {
161 uint8_t radio_type;
163 if (do_req(iface, SIOCGRADIO, &radio_type) == -1)
164 err(EX_OSERR, "Can't get radio type");
165 snprintf(radio_name, FILENAME_MAX, "%s/" RADIO_FW_FMT ".bin",
166 dirname(filename), radio_type);
167 mmap_file(radio_name, &fw.radio_fw, &fw.radio_fw_len);
170 do_req(iface, SIOCSLOADFW, &fw);
173 static void
174 mmap_file(const char *filename, uint8_t **addr, int *len)
176 struct stat st;
177 struct firmware_head *fwh;
178 uint32_t cksum;
179 uint8_t *p;
180 int i, fd;
182 fd = open(filename, O_RDONLY);
183 if (fd < 0)
184 err(EX_OSERR, "Can't open %s", filename);
186 if (fstat(fd, &st) < 0)
187 err(EX_OSERR, "Can't stat %s", filename);
189 if (st.st_size <= sizeof(struct firmware_head))
190 err(EX_SOFTWARE, "%s is too short", filename);
192 fwh = mmap(NULL, st.st_size, PROT_READ, 0, fd, 0);
193 if (fwh == NULL)
194 err(EX_OSERR, "Can't map %s into memory", filename);
196 if (fwh->fwh_len != st.st_size - sizeof(struct firmware_head))
197 err(EX_SOFTWARE, "%s length mismatch", filename);
199 cksum = 0;
200 for (i = 0, p = (uint8_t *)&fwh->fwh_len;
201 i < st.st_size - sizeof(fwh->fwh_cksum);
202 ++i, ++p)
203 cksum += *p;
204 if (cksum != fwh->fwh_cksum)
205 err(EX_SOFTWARE, "%s checksum mismatch", filename);
207 *addr = (uint8_t *)(fwh + 1);
208 *len = st.st_size - sizeof(struct firmware_head);
210 close(fd);
213 static void
214 usage(void)
216 fprintf(stderr, "usage: acxcontrol iface\n"
217 " acxcontrol iface -f file [-r]\n"
218 " acxcontrol iface -k\n");
219 exit(EX_USAGE);
223 main(int argc, char *argv[])
225 int c;
226 int noflag = 1, kflag = 0, rflag = 0;
227 const char *iface = NULL, *path = NULL;
229 if (argc > 1 && argv[1][0] != '-') {
230 iface = argv[1];
231 optind++;
234 while ((c = getopt(argc, argv, "f:i:kr")) != -1) {
235 if (c != 'i')
236 noflag = 0;
238 switch (c) {
239 case 'f':
240 path = optarg;
241 break;
242 case 'i':
243 iface = optarg;
244 break;
245 case 'k':
246 kflag = 1;
247 break;
248 case 'r':
249 rflag = 1;
250 break;
251 default:
252 usage();
256 if (iface == NULL)
257 usage();
259 if (kflag && ((path != NULL) || rflag))
260 usage();
262 if (kflag)
263 kill_firmware(iface);
265 if (path != NULL)
266 load_firmware(iface, path, rflag);
268 if (noflag)
269 get_statistics(iface);
271 return EX_OK;