diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2004-11-22 21:34:36 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2004-11-22 21:34:36 +0000 |
commit | 466feeb938cd785f22b5a3a077f7633ec4d6b90b (patch) | |
tree | 1bd069876aeb3e67c77324675e1287857da37b57 | |
parent | 99e1be9d16fa4376571f3ec87304b4b1da516f7d (diff) |
use the filesystem based firmware loader; ok deraadt@
-rw-r--r-- | sbin/iwicontrol/iwicontrol.8 | 16 | ||||
-rw-r--r-- | sbin/iwicontrol/iwicontrol.c | 111 | ||||
-rw-r--r-- | share/man/man4/iwi.4 | 13 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 4 | ||||
-rw-r--r-- | sys/dev/pci/if_iwi.c | 208 | ||||
-rw-r--r-- | sys/dev/pci/if_iwireg.h | 8 | ||||
-rw-r--r-- | sys/dev/pci/if_iwivar.h | 17 |
7 files changed, 110 insertions, 267 deletions
diff --git a/sbin/iwicontrol/iwicontrol.8 b/sbin/iwicontrol/iwicontrol.8 index 773744176f0..7f1eca8e371 100644 --- a/sbin/iwicontrol/iwicontrol.8 +++ b/sbin/iwicontrol/iwicontrol.8 @@ -1,4 +1,4 @@ -.\" $Id: iwicontrol.8,v 1.3 2004/10/20 21:26:43 deraadt Exp $ +.\" $Id: iwicontrol.8,v 1.4 2004/11/22 21:34:28 damien Exp $ .\" .\" Copyright (c) 2004 .\" Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. @@ -34,9 +34,6 @@ .Sh SYNOPSIS .Nm .Op Ar interface -.Op Fl d Ar directory -.Op Fl m Ar bss|ibss -.Op Fl k .Op Fl r .Sh DESCRIPTION The @@ -54,17 +51,6 @@ The options are as follows: .Bl -tag -width indent .It Fl i Ar interface Displays adapter's internal statistics. -.It Fl d Ar directory -Download firmware binary image to the adapter. The image is read from the -.Ar directory -directory. -.It Fl m Ar bss|ibss -By default, the firmware binary image for BSS (aka infrastructure -mode) mode is downloaded unless the -.Fl m -flag is given. -.It Fl k -Kill the firmware and reset the adapter. .It Fl r Displays the radio transmitter state (on or off). .El diff --git a/sbin/iwicontrol/iwicontrol.c b/sbin/iwicontrol/iwicontrol.c index 993d55409b3..699837af25e 100644 --- a/sbin/iwicontrol/iwicontrol.c +++ b/sbin/iwicontrol/iwicontrol.c @@ -1,4 +1,4 @@ -/* $Id: iwicontrol.c,v 1.5 2004/10/27 21:39:05 damien Exp $ */ +/* $Id: iwicontrol.c,v 1.6 2004/11/22 21:34:28 damien Exp $ */ /*- * Copyright (c) 2004 @@ -29,9 +29,7 @@ #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/mman.h> #include <sys/socket.h> -#include <sys/stat.h> #include <net/if.h> @@ -44,41 +42,22 @@ #include <sysexits.h> #include <unistd.h> -#define SIOCSLOADFW _IOW('i', 137, struct ifreq) -#define SIOCSKILLFW _IOW('i', 138, struct ifreq) #define SIOCGRADIO _IOWR('i', 139, struct ifreq) #define SIOCGTABLE0 _IOWR('i', 140, struct ifreq) -struct firmware { - void *boot; - int boot_size; - void *ucode; - int ucode_size; - void *main; - int main_size; -}; - -struct header { - u_int32_t version; - u_int32_t mode; -} __attribute__((__packed__)); - extern char *optarg; extern int optind; static void usage(void); static int do_req(char *, unsigned long, void *); -static void mmap_file(char *, void **, size_t *); -static void load_firmware(char *, char *, char *); -static void kill_firmware(char *); static void get_radio_state(char *); static void get_statistics(char *); int main(int argc, char **argv) { - char *iface = NULL, *mode = NULL, *path = NULL; - int noflag = 1, kflag = 0, rflag = 0, ifspecified = 0; + char *iface = NULL; + int noflag = 1, rflag = 0, ifspecified = 0; int ch; iface = "iwi0"; @@ -88,7 +67,7 @@ main(int argc, char **argv) optind = 2; } - while ((ch = getopt(argc, argv, "hd:i:km:r")) != -1) { + while ((ch = getopt(argc, argv, "hi:r")) != -1) { noflag = 0; switch (ch) { case 'i': @@ -96,18 +75,6 @@ main(int argc, char **argv) iface = optarg; break; - case 'd': - path = optarg; - break; - - case 'k': - kflag = 1; - break; - - case 'm': - mode = optarg; - break; - case 'r': rflag = 1; break; @@ -121,15 +88,6 @@ main(int argc, char **argv) if (iface == NULL) usage(); - if (kflag && (path != NULL || rflag)) - usage(); - - if (kflag) - kill_firmware(iface); - - if (path != NULL) - load_firmware(iface, path, mode); - if (rflag) get_radio_state(iface); @@ -144,9 +102,7 @@ usage(void) { extern char *__progname; - fprintf(stderr, - "usage: %s [interface] [-d path] [-kr]\n", - __progname); + fprintf(stderr, "usage: %s [interface] [-r]\n", __progname); exit(EX_USAGE); } @@ -172,63 +128,6 @@ do_req(char *iface, unsigned long req, void *data) } static void -mmap_file(char *filename, void **addr, size_t *len) -{ - int fd; - struct stat st; - - if ((fd = open(filename, O_RDONLY)) == -1) - err(EX_OSERR, "%s", filename); - - if (fstat(fd, &st) == -1) - err(EX_OSERR, "Unable to stat %s", filename); - - *len = st.st_size; - - if ((*addr = mmap(NULL, st.st_size, PROT_READ, 0, fd, 0)) == NULL) - err(EX_OSERR, "Can't map %s into memory", filename); - - *(char **)addr += sizeof (struct header); - *len -= sizeof (struct header); - - (void)close(fd); -} - -static void -load_firmware(char *iface, char *path, char *opmode) -{ - char filename[FILENAME_MAX]; - char *mainfw; - struct firmware fw; - - if (opmode == NULL || strcasecmp(opmode, "bss") == 0) - mainfw = "ipw2200_bss.fw"; - else if (strcasecmp(opmode, "ibss") == 0) - mainfw = "ipw2200_ibss.fw"; - else - errx(EX_USAGE, "Unknown mode %s\n", opmode); - - (void)snprintf(filename, sizeof filename, "%s/ipw2200_boot.fw", path); - mmap_file(filename, &fw.boot, &fw.boot_size); - - (void)snprintf(filename, sizeof filename, "%s/ipw2200_ucode.fw", path); - mmap_file(filename, &fw.ucode, &fw.ucode_size); - - (void)snprintf(filename, sizeof filename, "%s/%s", path, mainfw); - mmap_file(filename, &fw.main, &fw.main_size); - - if (do_req(iface, SIOCSLOADFW, &fw) == -1) - err(EX_OSERR, "Can't load firmware to driver"); -} - -static void -kill_firmware(char *iface) -{ - if (do_req(iface, SIOCSKILLFW, NULL) == -1) - err(EX_OSERR, "Can't kill firmware"); -} - -static void get_radio_state(char *iface) { int radio; diff --git a/share/man/man4/iwi.4 b/share/man/man4/iwi.4 index 6fbc4a99713..1025d356cb3 100644 --- a/share/man/man4/iwi.4 +++ b/share/man/man4/iwi.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iwi.4,v 1.5 2004/11/08 23:05:42 deraadt Exp $ +.\" $OpenBSD: iwi.4,v 1.6 2004/11/22 21:34:32 damien Exp $ .\" .\" Copyright (c) 2004 .\" Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. @@ -50,6 +50,17 @@ This mode requires the use of an access point. .Pp For more information on configuring this device, see .Xr ifconfig 8 . +.Sh FILES +The driver needs a couple of firmware files which are loaded on demand. +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Pa /etc/firmware/iwi-license +.It Pa /etc/firmware/iwi-boot +.It Pa /etc/firmware/iwi-bss +.It Pa /etc/firmware/iwi-ibss +.It Pa /etc/firmware/iwi-monitor +.It Pa /etc/firmware/iwi-ucode +.El .Sh EXAMPLES Join an existing BSS network (ie: connect to an access point): .Pp diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 904c1fc9748..5d26b88b4ee 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.163 2004/11/22 08:01:28 deraadt Exp $ +# $OpenBSD: files.pci,v 1.164 2004/11/22 21:34:35 damien Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -426,7 +426,7 @@ attach ipw at pci file dev/pci/if_ipw.c ipw # Intel PRO/Wireless 2200BG/2915ABG -device iwi: ifnet, wlan +device iwi: ifnet, wlan, firmload attach iwi at pci file dev/pci/if_iwi.c iwi diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c index 7feb577fb4b..a1062cedeba 100644 --- a/sys/dev/pci/if_iwi.c +++ b/sys/dev/pci/if_iwi.c @@ -1,4 +1,4 @@ -/* $Id: if_iwi.c,v 1.6 2004/11/22 19:52:59 damien Exp $ */ +/* $Id: if_iwi.c,v 1.7 2004/11/22 21:34:35 damien Exp $ */ /*- * Copyright (c) 2004 @@ -43,6 +43,7 @@ #include <sys/systm.h> #include <sys/malloc.h> #include <sys/conf.h> +#include <sys/device.h> #include <machine/bus.h> #include <machine/endian.h> @@ -114,10 +115,8 @@ int iwi_init_queues(struct iwi_softc *); void iwi_free_queues(struct iwi_softc *); void iwi_stop_master(struct iwi_softc *); int iwi_reset(struct iwi_softc *); -int iwi_load_ucode(struct iwi_softc *, void *, int); -int iwi_load_firmware(struct iwi_softc *, void *, int); -int iwi_cache_firmware(struct iwi_softc *, void *); -void iwi_free_firmware(struct iwi_softc *); +int iwi_load_ucode(struct iwi_softc *, const char *); +int iwi_load_firmware(struct iwi_softc *, const char *); int iwi_config(struct iwi_softc *); int iwi_scan(struct iwi_softc *); int iwi_auth_and_assoc(struct iwi_softc *); @@ -308,9 +307,6 @@ iwi_detach(struct device* self, int flags) iwi_stop(ifp, 1); - if (sc->flags & IWI_FLAG_FW_CACHED) - iwi_free_firmware(sc); - #if NBPFILTER > 0 bpfdetach(ifp); #endif @@ -1106,24 +1102,6 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = iwi_get_radio(sc, (int *)ifr->ifr_data); break; - case SIOCSLOADFW: - /* only super-user can do that! */ - if ((error = suser(curproc, 0)) != 0) - break; - - ifr = (struct ifreq *)data; - error = iwi_cache_firmware(sc, ifr->ifr_data); - break; - - case SIOCSKILLFW: - /* only super-user can do that! */ - if ((error = suser(curproc, 0)) != 0) - break; - - iwi_stop(ifp, 1); - iwi_free_firmware(sc); - break; - case SIOCG80211AUTH: ((struct ieee80211_auth *)data)->i_authtype = sc->authmode; break; @@ -1472,10 +1450,27 @@ iwi_reset(struct iwi_softc *sc) } int -iwi_load_ucode(struct iwi_softc *sc, void *uc, int size) +iwi_load_ucode(struct iwi_softc *sc, const char *name) { + u_char *uc, *data; + size_t size; u_int16_t *w; - int ntries, i; + int error, ntries, i; + + if ((error = loadfirmware(name, &data, &size)) != 0) { + printf("%s: could not read ucode %s, error %d\n", + sc->sc_dev.dv_xname, name, error); + goto fail1; + } + + if (size < sizeof (struct iwi_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + uc = data; + uc += sizeof (struct iwi_firmware_hdr); + size -= sizeof (struct iwi_firmware_hdr); CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_STOP_MASTER); @@ -1486,7 +1481,8 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size) } if (ntries == 5) { printf("%s: timeout waiting for master\n", sc->sc_dev.dv_xname); - return EIO; + error = EIO; + goto fail2; } MEM_WRITE_4(sc, 0x3000e0, 0x80000000); @@ -1504,7 +1500,7 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size) MEM_WRITE_1(sc, 0x200000, 0x40); /* Adapter is buggy, we must set the address for each word */ - for (w = uc; size > 0; w++, size -= 2) + for (w = (u_int16_t *)uc; size > 0; w++, size -= 2) MEM_WRITE_2(sc, 0x200010, *w); MEM_WRITE_1(sc, 0x200000, 0x00); @@ -1519,7 +1515,8 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size) if (ntries == 100) { printf("%s: timeout waiting for ucode to initialize\n", sc->sc_dev.dv_xname); - return EIO; + error = EIO; + goto fail2; } /* Empty the uc queue or the firmware will not initialize properly */ @@ -1528,20 +1525,38 @@ iwi_load_ucode(struct iwi_softc *sc, void *uc, int size) MEM_WRITE_1(sc, 0x200000, 0x00); - return 0; +fail2: free(data, M_DEVBUF); +fail1: return error; } /* macro to handle unaligned little endian data in firmware image */ #define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) int -iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) +iwi_load_firmware(struct iwi_softc *sc, const char *name) { + u_char *fw, *data; + size_t size; bus_dmamap_t map; bus_dma_segment_t seg; caddr_t virtaddr; u_char *p, *end; u_int32_t sentinel, ctl, src, dst, sum, len, mlen; - int ntries, nsegs, error = 0; + int ntries, nsegs, error; + + if ((error = loadfirmware(name, &data, &size)) != 0) { + printf("%s: could not read firmware %s, error %d\n", + sc->sc_dev.dv_xname, name, error); + goto fail1; + } + + if (size < sizeof (struct iwi_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + fw = data; + fw += sizeof (struct iwi_firmware_hdr); + size -= sizeof (struct iwi_firmware_hdr); /* Allocate DMA memory for storing firmware image */ error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, @@ -1549,7 +1564,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) if (error != 0) { printf("%s: could not create fw dma map\n", sc->sc_dev.dv_xname); - goto fail1; + goto fail2; } /* @@ -1561,7 +1576,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) if (error != 0) { printf("%s: could allocate fw dma memory\n", sc->sc_dev.dv_xname); - goto fail2; + goto fail3; } error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, &virtaddr, @@ -1569,14 +1584,14 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) if (error != 0) { printf("%s: could not map fw dma memory\n", sc->sc_dev.dv_xname); - goto fail3; + goto fail4; } error = bus_dmamap_load(sc->sc_dmat, map, virtaddr, size, NULL, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not load fw dma map\n", sc->sc_dev.dv_xname); - goto fail4; + goto fail5; } /* Copy firmware image to DMA memory */ @@ -1640,7 +1655,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) if (ntries == 400) { printf("%s: timeout processing cb\n", sc->sc_dev.dv_xname); error = EIO; - goto fail5; + goto fail6; } /* We're done with command blocks processing */ @@ -1658,87 +1673,16 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size) if ((error = tsleep(sc, 0, "iwiinit", hz)) != 0) { printf("%s: timeout waiting for firmware initialization to " "complete\n", sc->sc_dev.dv_xname); - goto fail5; + goto fail6; } -fail5: bus_dmamap_unload(sc->sc_dmat, map); -fail4: bus_dmamem_unmap(sc->sc_dmat, virtaddr, size); -fail3: bus_dmamem_free(sc->sc_dmat, &seg, 1); -fail2: bus_dmamap_destroy(sc->sc_dmat, map); - -fail1: return error; -} +fail6: bus_dmamap_unload(sc->sc_dmat, map); +fail5: bus_dmamem_unmap(sc->sc_dmat, virtaddr, size); +fail4: bus_dmamem_free(sc->sc_dmat, &seg, 1); +fail3: bus_dmamap_destroy(sc->sc_dmat, map); +fail2: free(data, M_DEVBUF); -/* - * Store firmware into kernel memory so we can download it when we need to, - * e.g when the adapter wakes up from suspend mode. - */ -int -iwi_cache_firmware(struct iwi_softc *sc, void *data) -{ - struct iwi_firmware *kfw = &sc->fw; - struct iwi_firmware ufw; - int error; - - if (sc->flags & IWI_FLAG_FW_CACHED) - iwi_free_firmware(sc); - - if ((error = copyin(data, &ufw, sizeof ufw)) != 0) - goto fail1; - - kfw->boot_size = ufw.boot_size; - kfw->ucode_size = ufw.ucode_size; - kfw->main_size = ufw.main_size; - - kfw->boot = malloc(kfw->boot_size, M_DEVBUF, M_NOWAIT); - if (kfw->boot == NULL) { - error = ENOMEM; - goto fail1; - } - - kfw->ucode = malloc(kfw->ucode_size, M_DEVBUF, M_NOWAIT); - if (kfw->ucode == NULL) { - error = ENOMEM; - goto fail2; - } - - kfw->main = malloc(kfw->main_size, M_DEVBUF, M_NOWAIT); - if (kfw->main == NULL) { - error = ENOMEM; - goto fail3; - } - - if ((error = copyin(ufw.boot, kfw->boot, kfw->boot_size)) != 0) - goto fail4; - - if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0) - goto fail4; - - if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0) - goto fail4; - - DPRINTF(("Firmware cached: boot %u, ucode %u, main %u\n", - kfw->boot_size, kfw->ucode_size, kfw->main_size)); - - sc->flags |= IWI_FLAG_FW_CACHED; - - return 0; - -fail4: free(kfw->boot, M_DEVBUF); -fail3: free(kfw->ucode, M_DEVBUF); -fail2: free(kfw->main, M_DEVBUF); -fail1: - return error; -} - -void -iwi_free_firmware(struct iwi_softc *sc) -{ - free(sc->fw.boot, M_DEVBUF); - free(sc->fw.ucode, M_DEVBUF); - free(sc->fw.main, M_DEVBUF); - - sc->flags &= ~IWI_FLAG_FW_CACHED; +fail1: return error; } int @@ -1941,27 +1885,21 @@ int iwi_init(struct ifnet *ifp) { struct iwi_softc *sc = ifp->if_softc; - struct iwi_firmware *fw = &sc->fw; + const char *name; int error; - /* exit immediately if firmware has not been ioctl'd */ - if (!(sc->flags & IWI_FLAG_FW_CACHED)) { - ifp->if_flags &= ~IFF_UP; - return EIO; - } - if ((error = iwi_reset(sc)) != 0) { printf("%s: could not reset adapter\n", sc->sc_dev.dv_xname); goto fail; } - if ((error = iwi_load_firmware(sc, fw->boot, fw->boot_size)) != 0) { + if ((error = iwi_load_firmware(sc, "iwi-boot")) != 0) { printf("%s: could not load boot firmware\n", sc->sc_dev.dv_xname); goto fail; } - if ((error = iwi_load_ucode(sc, fw->ucode, fw->ucode_size)) != 0) { + if ((error = iwi_load_ucode(sc, "iwi-ucode")) != 0) { printf("%s: could not load microcode\n", sc->sc_dev.dv_xname); goto fail; } @@ -1974,7 +1912,23 @@ iwi_init(struct ifnet *ifp) goto fail; } - if ((error = iwi_load_firmware(sc, fw->main, fw->main_size)) != 0) { + switch (sc->sc_ic.ic_opmode) { + case IEEE80211_M_STA: + case IEEE80211_M_HOSTAP: + name = "iwi-bss"; + break; + + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + name = "iwi-ibss"; + break; + + case IEEE80211_M_MONITOR: + name = "iwi-monitor"; + break; + } + + if ((error = iwi_load_firmware(sc, name)) != 0) { printf("%s: could not load main firmware\n", sc->sc_dev.dv_xname); goto fail; diff --git a/sys/dev/pci/if_iwireg.h b/sys/dev/pci/if_iwireg.h index 75f7e6fbfbe..a7bddd214e1 100644 --- a/sys/dev/pci/if_iwireg.h +++ b/sys/dev/pci/if_iwireg.h @@ -1,4 +1,4 @@ -/* $Id: if_iwireg.h,v 1.2 2004/11/22 19:20:28 damien Exp $ */ +/* $Id: if_iwireg.h,v 1.3 2004/11/22 21:34:35 damien Exp $ */ /*- * Copyright (c) 2004 @@ -107,6 +107,12 @@ #define IWI_RATE_OFDM48 1 #define IWI_RATE_OFDM54 3 +/* firmware binary image header */ +struct iwi_firmware_hdr { + u_int32_t version; + u_int32_t mode; +} __attribute__((__packed__)); + struct iwi_hdr { u_int8_t type; #define IWI_HDR_TYPE_DATA 0 diff --git a/sys/dev/pci/if_iwivar.h b/sys/dev/pci/if_iwivar.h index eb5c67f68ce..699b323f4b8 100644 --- a/sys/dev/pci/if_iwivar.h +++ b/sys/dev/pci/if_iwivar.h @@ -1,4 +1,4 @@ -/* $Id: if_iwivar.h,v 1.1 2004/10/20 12:50:48 deraadt Exp $ */ +/* $Id: if_iwivar.h,v 1.2 2004/11/22 21:34:35 damien Exp $ */ /*- * Copyright (c) 2004 @@ -27,15 +27,6 @@ * SUCH DAMAGE. */ -struct iwi_firmware { - void *boot; - int boot_size; - void *ucode; - int ucode_size; - void *main; - int main_size; -}; - struct iwi_buf { struct mbuf *m; struct ieee80211_node *ni; @@ -109,10 +100,8 @@ struct iwi_softc { int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); - struct iwi_firmware fw; u_int32_t flags; -#define IWI_FLAG_FW_CACHED (1 << 0) -#define IWI_FLAG_FW_INITED (1 << 1) +#define IWI_FLAG_FW_INITED (1 << 0) struct iwi_tx_queue txqueue[5]; struct iwi_rx_queue rxqueue; @@ -156,7 +145,5 @@ struct iwi_softc { #define IWI_ASYNC_CMD (1 << 0) -#define SIOCSLOADFW _IOW('i', 137, struct ifreq) -#define SIOCSKILLFW _IOW('i', 138, struct ifreq) #define SIOCGRADIO _IOWR('i', 139, struct ifreq) #define SIOCGTABLE0 _IOWR('i', 140, struct ifreq) |