]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/uathload/uathload.c
Fix ftpd privilege escalation via ftpchroot.
[FreeBSD/FreeBSD.git] / usr.sbin / uathload / uathload.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Sam Leffler, Errno Consulting
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15  *    redistribution must be conditioned upon including a substantially
16  *    similar Disclaimer requirement for further binary redistribution.
17  *
18  * NO WARRANTY
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGES.
30  *
31  * $FreeBSD$
32  */
33
34 /*
35  * Atheros AR5523 USB Station Firmware downloader.
36  *
37  *    uathload -d ugen-device [firmware-file]
38  *
39  * Intended to be called from devd on device discovery.
40  */
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/endian.h>
44 #include <sys/mman.h>
45
46 #include <sys/ioctl.h>
47 #include <dev/usb/usb.h>
48 #include <dev/usb/usb_ioctl.h>
49
50 #include <err.h>
51 #include <fcntl.h>
52 #include <libgen.h>
53 #include <paths.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <strings.h>
57 #include <unistd.h>
58
59 /* all fields are big endian */
60 struct uath_fwmsg {
61         uint32_t        flags;
62 #define UATH_WRITE_BLOCK        (1 << 4)
63
64         uint32_t        len;
65 #define UATH_MAX_FWBLOCK_SIZE   2048
66
67         uint32_t        total;
68         uint32_t        remain;
69         uint32_t        rxtotal;
70         uint32_t        pad[123];
71 } __packed;
72
73 #define UATH_DATA_TIMEOUT       10000
74 #define UATH_CMD_TIMEOUT        1000
75
76 #define VERBOSE(_fmt, ...) do {                 \
77         if (verbose) {                          \
78                 printf(_fmt, __VA_ARGS__);      \
79                 fflush(stdout);                 \
80         }                                       \
81 } while (0)
82
83 extern  uint8_t _binary_ar5523_bin_start;
84 extern  uint8_t _binary_ar5523_bin_end;
85
86 static int
87 getdevname(const char *devname, char *msgdev, char *datadev)
88 {
89         char *bn, *dn;
90
91         dn = dirname(devname);
92         if (dn == NULL)
93                 return (-1);
94         bn = basename(devname);
95         if (bn == NULL || strncmp(bn, "ugen", 4))
96                 return (-1);
97         bn += 4;
98
99         /* NB: pipes are hardcoded */
100         snprintf(msgdev, 256, "%s/usb/%s.1", dn, bn);
101         snprintf(datadev, 256, "%s/usb/%s.2", dn, bn);
102         return (0);
103 }
104
105 static void
106 usage(void)
107 {
108         errx(-1, "usage: uathload [-v] -d devname [firmware]");
109 }
110
111 int
112 main(int argc, char *argv[])
113 {
114         const char *fwname, *devname;
115         char msgdev[256], datadev[256];
116         struct uath_fwmsg txmsg, rxmsg;
117         char *txdata;
118         struct stat sb;
119         int msg, data, fw, timeout, b, c;
120         int bufsize = 512, verbose = 0;
121         ssize_t len;
122
123         devname = NULL;
124         while ((c = getopt(argc, argv, "d:v")) != -1) {
125                 switch (c) {
126                 case 'd':
127                         devname = optarg;
128                         break;
129                 case 'v':
130                         verbose = 1;
131                         break;
132                 default:
133                         usage();
134                         /*NOTREACHED*/
135                 }
136         }
137         argc -= optind;
138         argv += optind;
139
140         if (devname == NULL)
141                 errx(-1, "No device name; use -d to specify the ugen device");
142         if (argc > 1)
143                 usage();
144
145         if (argc == 1)
146                 fwname = argv[0];
147         else
148                 fwname = _PATH_FIRMWARE "/ar5523.bin";
149         fw = open(fwname, O_RDONLY, 0);
150         if (fw < 0)
151                 err(-1, "open(%s)", fwname);
152         if (fstat(fw, &sb) < 0)
153                 err(-1, "fstat(%s)", fwname);
154         txdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fw, 0);
155         if (txdata == MAP_FAILED)
156                 err(-1, "mmap(%s)", fwname);
157         len = sb.st_size;
158         /* XXX verify device is an AR5005 part */
159         if (getdevname(devname, msgdev, datadev))
160                 err(-1, "getdevname error");
161
162         msg = open(msgdev, O_RDWR, 0);
163         if (msg < 0)
164                 err(-1, "open(%s)", msgdev);
165         timeout = UATH_DATA_TIMEOUT;
166         if (ioctl(msg, USB_SET_RX_TIMEOUT, &timeout) < 0)
167                 err(-1, "%s: USB_SET_RX_TIMEOUT(%u)", msgdev, UATH_DATA_TIMEOUT);
168         if (ioctl(msg, USB_SET_RX_BUFFER_SIZE, &bufsize) < 0)
169                 err(-1, "%s: USB_SET_RX_BUFFER_SIZE(%u)", msgdev, bufsize);
170
171         data = open(datadev, O_WRONLY, 0);
172         if (data < 0)
173                 err(-1, "open(%s)", datadev);
174         timeout = UATH_DATA_TIMEOUT;
175         if (ioctl(data, USB_SET_TX_TIMEOUT, &timeout) < 0)
176                 err(-1, "%s: USB_SET_TX_TIMEOUT(%u)", datadev,
177                     UATH_DATA_TIMEOUT);
178
179         VERBOSE("Load firmware %s to %s\n", fwname, devname);
180
181         bzero(&txmsg, sizeof (struct uath_fwmsg));
182         txmsg.flags = htobe32(UATH_WRITE_BLOCK);
183         txmsg.total = htobe32(len);
184
185         b = 0;
186         while (len > 0) {
187                 int mlen;
188
189                 mlen = len;
190                 if (mlen > UATH_MAX_FWBLOCK_SIZE)
191                         mlen = UATH_MAX_FWBLOCK_SIZE;
192                 txmsg.remain = htobe32(len - mlen);
193                 txmsg.len = htobe32(mlen);
194
195                 /* send firmware block meta-data */
196                 VERBOSE("send block %2u: %zd bytes remaining", b, len - mlen);
197                 if (write(msg, &txmsg, sizeof(txmsg)) != sizeof(txmsg)) {
198                         VERBOSE("%s", "\n");
199                         err(-1, "error sending msg (%s)", msgdev);
200                         break;
201                 }
202
203                 /* send firmware block data */
204                 VERBOSE("%s", "\n             : data...");
205                 if (write(data, txdata, mlen) != mlen) {
206                         VERBOSE("%s", "\n");
207                         err(-1, "error sending data (%s)", datadev);
208                         break;
209                 }
210
211                 /* wait for ack from firmware */
212                 VERBOSE("%s", "\n             : wait for ack...");
213                 bzero(&rxmsg, sizeof(rxmsg));
214                 if (read(msg, &rxmsg, sizeof(rxmsg)) != sizeof(rxmsg)) {
215                         VERBOSE("%s", "\n");
216                         err(-1, "error reading msg (%s)", msgdev);
217                         break;
218                 }
219
220                 VERBOSE("flags=0x%x total=%d\n",
221                     be32toh(rxmsg.flags), be32toh(rxmsg.rxtotal));
222                 len -= mlen;
223                 txdata += mlen;
224                 b++;
225         }
226         sleep(1);
227         close(fw);
228         close(msg);
229         close(data);
230         return 0;
231 }