├── 80211ping.c ├── Makefile ├── README.md └── endian.h /80211ping.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 80211ping - "ping" 802.11 stations by sending data frames and wait for ack 3 | * 4 | * Copyright (C) 2012 Till Wollenberg 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "endian.h" 33 | 34 | /* uclibc's pcap.h misses this definition */ 35 | #ifndef PCAP_NETMASK_UNKNOWN 36 | #define PCAP_NETMASK_UNKNOWN 0xffffffff 37 | #endif 38 | 39 | typedef struct { 40 | uint8_t b[6]; 41 | } __attribute__((packed)) mac_t; 42 | 43 | /* Fixed length part of the radiotap header */ 44 | typedef struct { 45 | uint8_t version; 46 | uint8_t padding; 47 | uint16_t length; 48 | #define RADIOTAP_PRESENT_RATE 0x00000004 49 | #define RADIOTAP_PRESENT_RETRY 0x00020000 50 | uint32_t present; 51 | } __attribute__((packed)) hdrrt_t; 52 | 53 | typedef struct { 54 | #define TYPE_DATA_NULL 0x48 55 | #define TYPE_CTRL_RTS 0xb4 56 | uint8_t type_subtype; 57 | #define FLAG_MOREDATA 0x20 58 | uint8_t flags; 59 | uint16_t duration; 60 | mac_t dest; 61 | mac_t src; 62 | mac_t bssid; 63 | uint16_t seq; 64 | } __attribute__((packed)) hdr80211_t; 65 | 66 | static int terminated; 67 | static pcap_t *pcap; 68 | 69 | 70 | /* 71 | * Test if str is a valid MAC address 72 | * (code taken from BlueZ's lib/bluetooth.c) 73 | */ 74 | static int check_mac(const char *str) 75 | { 76 | if (!str) 77 | return -1; 78 | 79 | if (strlen(str) != 17) 80 | return -1; 81 | 82 | while (*str) { 83 | if (!isxdigit(*str++)) 84 | return -1; 85 | 86 | if (!isxdigit(*str++)) 87 | return -1; 88 | 89 | if (*str == 0) 90 | break; 91 | 92 | if (*str++ != ':') 93 | return -1; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | /* 100 | * Convert MAC address given as string to byte array. 101 | * (code based on BlueZ's lib/bluetooth.c) 102 | */ 103 | static int strtomac(const char *str, mac_t *mac) 104 | { 105 | int i; 106 | 107 | if (check_mac(str) < 0) { 108 | memset(mac, 0, sizeof(mac_t)); 109 | return -1; 110 | } 111 | 112 | for (i = 0; i < 6; i++, str += 3) { 113 | mac->b[i] = strtol(str, NULL, 16); 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | static void sigint(int sig) 120 | { 121 | terminated = 1; 122 | pcap_breakloop(pcap); 123 | } 124 | 125 | static void print_usage() 126 | { 127 | #define STRINGIFY_HELPER(x) #x 128 | #define STRINGIFY(x) STRINGIFY_HELPER(x) 129 | fprintf(stderr, 130 | "80211ping " STRINGIFY(VERSION) "\n" 131 | "Usage:\n" 132 | " 80211ping \n" 133 | " -I device to use (mandatory, device must be in monitor mode)\n" 134 | " -c stop after sending packets (default: don't stop)\n" 135 | " -i send packet each ms (default: 1000 ms)\n" 136 | " -r specify data rate (in Mbit/s, not supported by all drivers)\n" 137 | " -m set \"more data\" flag\n" 138 | ); 139 | } 140 | 141 | static void packet_handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *packet) 142 | { 143 | int *acks = (int*)user; 144 | (*acks)++; 145 | } 146 | 147 | static void sigalrm(int sig) 148 | { 149 | pcap_breakloop(pcap); 150 | } 151 | 152 | int main (int argc, char *argv[]) 153 | { 154 | char ifname[IFNAMSIZ]; 155 | int count; 156 | int interval; 157 | int rate; 158 | int moredata; 159 | mac_t source; 160 | mac_t dest; 161 | char dest_str[18]; 162 | int c; 163 | char errbuf[PCAP_ERRBUF_SIZE]; 164 | char filter[256]; 165 | struct bpf_program fp; 166 | int linktype; 167 | uint8_t packet[256]; 168 | int packet_length; 169 | hdrrt_t* const hdrrt = (hdrrt_t*)packet; 170 | uint32_t present; 171 | int rtlen; 172 | hdr80211_t *hdr80211; 173 | struct itimerval itv; 174 | volatile int acks; 175 | int packets_sent; 176 | int packets_acked; 177 | struct timeval tv; 178 | 179 | gettimeofday(&tv, NULL); 180 | srand(tv.tv_usec * tv.tv_sec); 181 | 182 | /* 183 | * Default values 184 | */ 185 | ifname[0] = '\0'; 186 | count = -1; /* -1 == infinite loop */ 187 | interval = 1000000; /* microseconds */ 188 | rate = -1; /* -1 == don't specify rate to mac80211 */ 189 | moredata = 0; 190 | 191 | 192 | /* 193 | * Parse command line arguments 194 | */ 195 | opterr = 0; 196 | while ((c = getopt(argc, argv, ":I:c:i:r:m")) != -1) { 197 | switch (c) { 198 | case 'I': 199 | if (strlen(optarg) < IFNAMSIZ) { 200 | strncpy(ifname, optarg, IFNAMSIZ); 201 | } 202 | else { 203 | fprintf(stderr, "'%s' is not a valid interface name\n", optarg); 204 | return -1; 205 | } 206 | break; 207 | 208 | case 'i': 209 | interval = (strtof(optarg, NULL) * 1000000); 210 | if (interval <= 0) { 211 | fprintf(stderr, "Interval must be greater than 0.\n"); 212 | return -1; 213 | } 214 | break; 215 | 216 | case 'c': 217 | count = strtol(optarg, NULL, 10); 218 | if (count <= 0) { 219 | fprintf(stderr, "Count must be greater than 0.\n"); 220 | return -1; 221 | } 222 | break; 223 | 224 | case 'r': 225 | rate = (strtof(optarg, NULL) * 2); 226 | if (rate <= 2) { 227 | fprintf(stderr, "Data rate must be greater than 1 Mbit/s.\n"); 228 | return -1; 229 | } 230 | break; 231 | 232 | case 'm': 233 | moredata = 1; 234 | break; 235 | 236 | case ':': 237 | fprintf(stderr, "Option -%c requires an argument.\n", optopt); 238 | print_usage(); 239 | return -1; 240 | 241 | case '?': 242 | fprintf(stderr, "Invalid option: -%c\n", optopt); 243 | print_usage(); 244 | return -1; 245 | 246 | default: 247 | abort(); 248 | } 249 | } 250 | 251 | if (optind < argc) { 252 | if (strtomac(argv[optind], &dest) < 0) { 253 | fprintf(stderr, "'%s' is not a valid MAC address.\n", argv[optind]); 254 | return -1; 255 | } 256 | } 257 | else { 258 | fprintf(stderr, "No destination specified.\n"); 259 | print_usage(); 260 | return -1; 261 | } 262 | 263 | if (strlen(ifname) == 0) { 264 | fprintf(stderr, "You have to specify which interface to use (see -I option).\n"); 265 | return -1; 266 | } 267 | 268 | sprintf(dest_str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", 269 | dest.b[0], dest.b[1], dest.b[2], dest.b[3], dest.b[4], dest.b[5]); 270 | 271 | /* 272 | * Create random source MAC address 273 | */ 274 | 275 | /* TODO: Maybe deriving the source MAC address from the actual MAC address of the 276 | device used would be better. */ 277 | 278 | source.b[0] = (rand() & 0xFE) | 0x02; /* unicast + locally administered */ 279 | source.b[1] = rand(); 280 | source.b[2] = rand(); 281 | source.b[3] = rand(); 282 | source.b[4] = rand(); 283 | source.b[5] = rand(); 284 | 285 | 286 | /* 287 | * PCAP initialization 288 | */ 289 | errbuf[0] = '\0'; 290 | pcap = pcap_open_live(ifname, 80, 1, 0, errbuf); 291 | if (pcap == NULL) { 292 | fprintf(stderr, "Unable to open interface: %s\n", errbuf); 293 | return 1; 294 | } 295 | 296 | linktype = pcap_datalink(pcap); 297 | if (linktype != DLT_IEEE802_11_RADIO) { 298 | fprintf(stderr, "Unsupported link type (%s) on %s, terminating.\n", 299 | pcap_datalink_val_to_name(linktype), ifname); 300 | pcap_close(pcap); 301 | return 1; 302 | } 303 | 304 | /* Build filter that matches only ACKs sent to our fake address */ 305 | snprintf(filter, sizeof(filter), "link[0]=0xd4 and link[4]=0x%2.2x and " 306 | "link[5]=0x%2.2x and link[6]=0x%2.2x and link[7]=0x%2.2x and " 307 | "link[8]=0x%2.2x and link[9]=0x%2.2x", source.b[0], source.b[1], 308 | source.b[2], source.b[3], source.b[4], source.b[5]); 309 | 310 | if (pcap_compile(pcap, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) < 0) { 311 | fprintf(stderr, "Error compiling the pcap filter: %s.\n", pcap_geterr(pcap)); 312 | return 1; 313 | } 314 | 315 | if (pcap_setfilter(pcap, &fp) < 0) { 316 | fprintf(stderr, "Error setting pcap filter: %s.\n", pcap_geterr(pcap)); 317 | return 1; 318 | } 319 | 320 | /* 321 | * Craft "ping" frame (acutally a 802.11 NULL DATA frame) 322 | */ 323 | 324 | /* set-up basic radiotap header */ 325 | rtlen = 8; 326 | hdrrt->version = 0; 327 | hdrrt->padding = 0; 328 | present = 0; 329 | 330 | /* Add fields to radiotap header: data rate field (if requested by user) */ 331 | if (rate != -1) { 332 | packet[rtlen] = rate; 333 | present |= RADIOTAP_PRESENT_RATE; 334 | rtlen++; 335 | } 336 | 337 | /* Add fields to radiotap header: retry count */ 338 | packet[rtlen] = 0; 339 | present |= RADIOTAP_PRESENT_RETRY; 340 | rtlen++; 341 | 342 | /* Finalize radiotap header and build 802.11 frame header */ 343 | hdrrt->length = htole16(rtlen); 344 | hdrrt->present = htole32(present); 345 | hdr80211 = (hdr80211_t*)&packet[rtlen]; 346 | 347 | hdr80211->type_subtype = TYPE_DATA_NULL; 348 | hdr80211->flags = 0; 349 | if (moredata) { 350 | hdr80211->flags |= FLAG_MOREDATA; 351 | } 352 | hdr80211->duration = 0; 353 | memcpy(&hdr80211->dest, &dest, sizeof(dest)); 354 | memcpy(&hdr80211->src, &source.b, 6); 355 | memcpy(&hdr80211->bssid, &source.b, 6); 356 | 357 | /* "ping" frame complete */ 358 | packet_length = sizeof(hdr80211_t) + rtlen; 359 | 360 | 361 | /* 362 | * Main loop: periodically send crafted frame and watch out for ACKs 363 | */ 364 | printf("Sending null data frames from %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X " 365 | "to %s every %.2fs", source.b[0], source.b[1], source.b[2], 366 | source.b[3], source.b[4], source.b[5], dest_str, interval / 1000000.0); 367 | if (rate != -1) { 368 | printf(" at %.1fMbit/s", rate / 2.0); 369 | } 370 | if (moredata) { 371 | printf(" (with \"more data\" flag set)"); 372 | } 373 | printf("...\n"); 374 | 375 | terminated = 0; 376 | signal(SIGINT, sigint); 377 | 378 | signal(SIGALRM, sigalrm); 379 | 380 | itv.it_value.tv_sec = (interval / 1000000); 381 | itv.it_value.tv_usec = (interval % 1000000); 382 | itv.it_interval.tv_sec = 0; /* no automatic restart of timer upon */ 383 | itv.it_interval.tv_usec = 0; /* expiration, we restart it manually */ 384 | 385 | packets_sent = 0; 386 | packets_acked = 0; 387 | 388 | while (!terminated) { 389 | printf("Sending frame to %s: ", dest_str); 390 | fflush(stdout); 391 | 392 | if (setitimer(ITIMER_REAL, &itv, NULL) != 0) { 393 | fprintf(stderr, "setitimer() failed (%s)\n", strerror(errno)); 394 | return -1; 395 | } 396 | 397 | if (pcap_inject(pcap, packet, packet_length) >= 0) { 398 | packets_sent++; 399 | 400 | /* Soak in all ACK frames until timeout occurs (pcap_loop is 401 | interrupted by calling pcap_breakloop in sigalrm() */ 402 | acks = 0; 403 | 404 | if (pcap_loop(pcap, 0, packet_handler, (u_char*)&acks) != -2) { 405 | printf("pcap_loop() error\n"); 406 | break; 407 | } 408 | 409 | if (acks == 0) { 410 | printf("no reply.\n"); 411 | } else { 412 | packets_acked++; 413 | if (acks == 1) { 414 | printf("reply received!\n"); 415 | } 416 | else { 417 | printf("reply received! (%d duplicate ACKs)\n", acks - 1); 418 | } 419 | } 420 | } 421 | else { 422 | printf("frame injection failed (%s).\n", pcap_geterr(pcap)); 423 | pause(); 424 | } 425 | 426 | if (count == packets_sent) { 427 | break; 428 | } 429 | } 430 | 431 | printf("%d packets sent, %d packets acknowledged (%.1f%%)\n", 432 | packets_sent, packets_acked, (packets_sent > 0)? 433 | ((packets_acked / (float)packets_sent) * 100) : 0); 434 | pcap_close(pcap); 435 | 436 | return 0; 437 | } 438 | 439 | 440 | #if 0 441 | 442 | /* Example frame structure */ 443 | static u8 packet[] = { 444 | /* Radiotap header */ 445 | 0x00, /* version */ 446 | 0x00, /* padding */ 447 | 0x0a, 0x00, /* length, little endian */ 448 | 0x04, 0x00, 0x02, 0x00, /* present flags (data rate, retry count) */ 449 | 0x30, /* rate (12 mbit/s) */ 450 | 0x01, /* retries (1) */ 451 | 452 | /* 802.11 header */ 453 | 0x48, 0x00, /* NULL data type (0x2c), flags all 0 */ 454 | 0x00, 0x00, /* duration */ 455 | 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, /* destination address */ 456 | 0xYY, 0xYY, 0xYY, 0xYY, 0xYY, 0xYY, /* source address */ 457 | 0xZZ, 0xZZ, 0xZZ, 0xZZ, 0xZZ, 0xZZ, /* BSSID */ 458 | 459 | 0x00, 0x00, /* sequence number, usually overwritten by 802.11 stack or hardware */ 460 | 0x00, 0x00, 0x00, 0x00 /* FCS, overwritten by 802.11 stack or hardware */ 461 | }; 462 | 463 | #endif 464 | 465 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE = 80211ping 2 | VERSION = 0.1 3 | 4 | override CFLAGS += -O0 -std=gnu99 -Wall -g -pedantic -DVERSION="$(VERSION)" 5 | override LFLAGS += 6 | LIBS = -lpcap 7 | BINARY = $(PACKAGE) 8 | OBJS = 80211ping.o 9 | DEPS = 10 | 11 | .PHONY: all strip install clean tar 12 | 13 | all: $(BINARY) 14 | 15 | $(BINARY): $(OBJS) 16 | $(CC) $(LFLAGS) $(OBJS) -o $(BINARY) $(LIBS) 17 | 18 | %.o: %.c $(DEPS) 19 | $(CC) -c $(CFLAGS) $< 20 | 21 | strip: $(BINARY) 22 | strip -s $(BINARY) 23 | 24 | clean: 25 | rm -f $(OBJS) $(BINARY) 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 80211ping 2 | ========= 3 | 4 | What is it? 5 | ----------- 6 | 7 | 80211ping is a small Linux command-line tool to "ping" 802.11 stations (e.g. any WiFi device). 8 | 9 | 10 | What can it be used for? 11 | ------------------------ 12 | 13 | * To test for the presence of a particular WiFi device. 14 | * To prevent power save mode of a particular device device (try the -m option.) 15 | * To test the link quality (by sending "pings" with at different data rates.) 16 | 17 | The most important advantage over a normal "ping" is that 80211ping works on the link layer. Hence, you don't need to be associated to the same wireless network as the target, in fact, both devices don't need to be associated at all. Firewalls blocking ICMP, wrong IP addresses etc. do not matter since they are all on network layer. 18 | 19 | 20 | How to use? 21 | ----------- 22 | 23 | ### In general 24 | 80211ping 0.1 25 | Usage: 26 | 80211ping 27 | -I device to use (mandatory, device must be in monitor mode) 28 | -c stop after sending packets (default: don't stop) 29 | -i send packet each ms (default: 1000 ms) 30 | -r specify data rate (in Mbit/s, not supported by all drivers) 31 | -m set "more data" flag 32 | 33 | ### Example 34 | $ sudo ./80211ping -I mon0 -c 10 XX:XX:XX:XX:XX:XX 35 | Sending null data frames from AE:24:BC:89:AF:9F to XX:XX:XX:XX:XX:XX every 1.00s... 36 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! (1 duplicate ACKs) 37 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! 38 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! (2 duplicate ACKs) 39 | Sending frame to XX:XX:XX:XX:XX:XX: no reply. 40 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! (4 duplicate ACKs) 41 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! (1 duplicate ACKs) 42 | Sending frame to XX:XX:XX:XX:XX:XX: no reply. 43 | Sending frame to XX:XX:XX:XX:XX:XX: no reply. 44 | Sending frame to XX:XX:XX:XX:XX:XX: no reply. 45 | Sending frame to XX:XX:XX:XX:XX:XX: reply received! 46 | 10 packets sent, 6 packets acknowledged (60.0%) 47 | 48 | 80211ping needs a network device in monitor mode that uses Radiotap headers. So far I tested 80211ping with MadWiFi and iwlwifi, but any mac80211 based wireless LAN driver should work as long as it does support frame injection. To use 80211ping, you can create a monitor mode device in parallel to another device. 49 | 50 | ### For iwlwifi (or other mac80211 based drivers): 51 | # iw dev wlan0 interface add mon0 type monitor 52 | # ifconfig mon0 up 53 | # ./80211ping -I mon0 xx:xx:xx:xx:xx:xx 54 | 55 | ### For MadWiFi: 56 | # wlanconfig ath0 create wlandev wifi0 wlanmode monitor 57 | # ifconfig ath0 up 58 | # ./80211ping -I ath0 xx:xx:xx:xx:xx:xx 59 | 60 | ### Notes: 61 | * Not all drivers support setting the data rate. 62 | * The "ping" frames will only reach the target device when both sending and target device are set to the same channel. 63 | * When creating a monitor mode device in parallel to another (client or AP) device, the channel of the monitor mode device may be determined by the other device. 64 | 65 | 66 | How does it work? 67 | ----------------- 68 | 69 | 80211ping sends a 802.11 null data frames addressed to the target device and then waits for acknowledgement (ACK) frames. This works because all 802.11 devices I met so far acknowledge every valid frame they receive that is addressed to them and has a correct FCS. 80211ping uses a randomly selected MAC address as source and BSSID address. Libpcap is used for both injection and capturing. 70 | 71 | 72 | How to compile? 73 | --------------- 74 | 75 | For compiling 80211ping you only need GCC and standard binutils plus libpcap and its header files. A makefile is provided. 76 | 77 | 80211ping can be built using the OpenWRT toolchain (tested with backfire): 78 | 79 | $ export STAGING_DIR=/path/to/openwrt/backfire/staging_dir 80 | $ export PATH=$PATH:STAGING_DIR/toolchain-mips_r2_gcc-4.3.3+cs_uClibc-0.9.30.1/bin 81 | $ make CC=mips-openwrt-linux-gcc CFLAGS="-I$STAGING_DIR/target-mips_r2_uClibc-0.9.30.1/usr/include" LFLAGS="-L$STAGING_DIR/target-mips_r2_uClibc-0.9.30.1/usr/lib" 82 | 83 | 84 | Questions? 85 | ---------- 86 | 87 | You can reach me through till <dot> wollenberg <at> uni-rostock <dot> de. Bug reports are welcome. :-) 88 | 89 | -------------------------------------------------------------------------------- /endian.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1992, 1996, 1997, 2000, 2008 Free Software Foundation, Inc. 2 | This file is part of the GNU C Library. 3 | 4 | The GNU C Library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | The GNU C Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with the GNU C Library; if not, write to the Free 16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 17 | 02111-1307 USA. */ 18 | 19 | #ifndef _LOCAL_ENDIAN_H 20 | #define _LOCAL_ENDIAN_H 1 21 | 22 | #include 23 | 24 | /* Definitions for byte order, according to significance of bytes, 25 | from low addresses to high addresses. The value is what you get by 26 | putting '4' in the most significant byte, '3' in the second most 27 | significant byte, '2' in the second least significant byte, and '1' 28 | in the least significant byte, and then writing down one digit for 29 | each byte, starting with the byte at the lowest address at the left, 30 | and proceeding to the byte with the highest address at the right. */ 31 | 32 | #define __LITTLE_ENDIAN 1234 33 | #define __BIG_ENDIAN 4321 34 | #define __PDP_ENDIAN 3412 35 | 36 | #include 37 | 38 | /* Some machines may need to use a different endianness for floating point 39 | values. */ 40 | #ifndef __FLOAT_WORD_ORDER 41 | # define __FLOAT_WORD_ORDER __BYTE_ORDER 42 | #endif 43 | 44 | #ifdef __USE_BSD 45 | # define LITTLE_ENDIAN __LITTLE_ENDIAN 46 | # define BIG_ENDIAN __BIG_ENDIAN 47 | # define PDP_ENDIAN __PDP_ENDIAN 48 | # define BYTE_ORDER __BYTE_ORDER 49 | #endif 50 | 51 | #if __BYTE_ORDER == __LITTLE_ENDIAN 52 | # define __LONG_LONG_PAIR(HI, LO) LO, HI 53 | #elif __BYTE_ORDER == __BIG_ENDIAN 54 | # define __LONG_LONG_PAIR(HI, LO) HI, LO 55 | #endif 56 | 57 | 58 | #ifdef __USE_BSD 59 | /* Conversion interfaces. */ 60 | # include 61 | 62 | # if __BYTE_ORDER == __LITTLE_ENDIAN 63 | # define htobe16(x) __bswap_16 (x) 64 | # define htole16(x) (x) 65 | # define be16toh(x) __bswap_16 (x) 66 | # define le16toh(x) (x) 67 | 68 | # define htobe32(x) __bswap_32 (x) 69 | # define htole32(x) (x) 70 | # define be32toh(x) __bswap_32 (x) 71 | # define le32toh(x) (x) 72 | 73 | # define htobe64(x) __bswap_64 (x) 74 | # define htole64(x) (x) 75 | # define be64toh(x) __bswap_64 (x) 76 | # define le64toh(x) (x) 77 | # else 78 | # define htobe16(x) (x) 79 | # define htole16(x) __bswap_16 (x) 80 | # define be16toh(x) (x) 81 | # define le16toh(x) __bswap_16 (x) 82 | 83 | # define htobe32(x) (x) 84 | # define htole32(x) __bswap_32 (x) 85 | # define be32toh(x) (x) 86 | # define le32toh(x) __bswap_32 (x) 87 | 88 | # define htobe64(x) (x) 89 | # define htole64(x) __bswap_64 (x) 90 | # define be64toh(x) (x) 91 | # define le64toh(x) __bswap_64 (x) 92 | # endif 93 | #endif 94 | 95 | #endif /* endian.h */ 96 | --------------------------------------------------------------------------------