source: MondoRescue/branches/3.3/mindi-busybox/networking/udhcp/arpping.c@ 3803

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 4.4 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
[821]2/*
3 * Mostly stolen from: dhcpcd - DHCP client daemon
4 * by Yoichi Hariguchi <yoichi@fore.com>
[2725]5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
[821]7 */
8#include <netinet/if_ether.h>
9#include <net/if_arp.h>
10
[1765]11#include "common.h"
[821]12#include "dhcpd.h"
13
[1765]14struct arpMsg {
15 /* Ethernet header */
16 uint8_t h_dest[6]; /* 00 destination ether addr */
17 uint8_t h_source[6]; /* 06 source ether addr */
18 uint16_t h_proto; /* 0c packet type ID field */
[821]19
[1765]20 /* ARP packet */
21 uint16_t htype; /* 0e hardware type (must be ARPHRD_ETHER) */
22 uint16_t ptype; /* 10 protocol type (must be ETH_P_IP) */
23 uint8_t hlen; /* 12 hardware address length (must be 6) */
24 uint8_t plen; /* 13 protocol address length (must be 4) */
25 uint16_t operation; /* 14 ARP opcode */
26 uint8_t sHaddr[6]; /* 16 sender's hardware address */
27 uint8_t sInaddr[4]; /* 1c sender's IP address */
28 uint8_t tHaddr[6]; /* 20 target's hardware address */
29 uint8_t tInaddr[4]; /* 26 target's IP address */
30 uint8_t pad[18]; /* 2a pad for min. ethernet payload (60 bytes) */
[2725]31} PACKED;
[821]32
[2725]33enum {
34 ARP_MSG_SIZE = 0x2a
35};
[821]36
[1765]37/* Returns 1 if no reply received */
[2725]38int FAST_FUNC arpping(uint32_t test_nip,
39 const uint8_t *safe_mac,
40 uint32_t from_ip,
41 uint8_t *from_mac,
[3621]42 const char *interface,
43 unsigned timeo)
[1765]44{
[2725]45 int timeout_ms;
46 struct pollfd pfd[1];
47#define s (pfd[0].fd) /* socket */
[1765]48 int rv = 1; /* "no reply received" yet */
49 struct sockaddr addr; /* for interface name */
50 struct arpMsg arp;
51
[3621]52 if (!timeo)
53 return 1;
54
[1765]55 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
56 if (s == -1) {
57 bb_perror_msg(bb_msg_can_not_create_raw_socket);
[821]58 return -1;
59 }
60
[1765]61 if (setsockopt_broadcast(s) == -1) {
[2725]62 bb_perror_msg("can't enable bcast on raw socket");
[1765]63 goto ret;
[821]64 }
65
66 /* send arp request */
67 memset(&arp, 0, sizeof(arp));
[1765]68 memset(arp.h_dest, 0xff, 6); /* MAC DA */
69 memcpy(arp.h_source, from_mac, 6); /* MAC SA */
70 arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
71 arp.htype = htons(ARPHRD_ETHER); /* hardware type */
72 arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
73 arp.hlen = 6; /* hardware address length */
74 arp.plen = 4; /* protocol address length */
75 arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
76 memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */
77 memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
[2725]78 /* tHaddr is zero-filled */ /* target hardware address */
79 memcpy(arp.tInaddr, &test_nip, sizeof(test_nip));/* target IP address */
[821]80
81 memset(&addr, 0, sizeof(addr));
[1765]82 safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data));
[2725]83 if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) {
84 // TODO: error message? caller didn't expect us to fail,
85 // just returning 1 "no reply received" misleads it.
[1765]86 goto ret;
[2725]87 }
[821]88
[1765]89 /* wait for arp reply, and check it */
[3621]90 timeout_ms = (int)timeo;
[1765]91 do {
[2725]92 typedef uint32_t aliased_uint32_t FIX_ALIASING;
[1765]93 int r;
[2725]94 unsigned prevTime = monotonic_ms();
95
96 pfd[0].events = POLLIN;
97 r = safe_poll(pfd, 1, timeout_ms);
98 if (r < 0)
99 break;
100 if (r) {
101 r = safe_read(s, &arp, sizeof(arp));
102 if (r < 0)
[1765]103 break;
[2725]104
105 //log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
106 // arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
107 // arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
108
109 if (r >= ARP_MSG_SIZE
110 && arp.operation == htons(ARPOP_REPLY)
111 /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
112 /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
113 && *(aliased_uint32_t*)arp.sInaddr == test_nip
[1765]114 ) {
[2725]115 /* if ARP source MAC matches safe_mac
116 * (which is client's MAC), then it's not a conflict
117 * (client simply already has this IP and replies to ARPs!)
118 */
119 if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0)
120 rv = 0;
121 //else log2("sHaddr == safe_mac");
[821]122 break;
123 }
124 }
[3232]125 timeout_ms -= (unsigned)monotonic_ms() - prevTime + 1;
[1765]126
[3232]127 /* We used to check "timeout_ms > 0", but
128 * this is more under/overflow-resistant
129 * (people did see overflows here when system time jumps):
130 */
[3621]131 } while ((unsigned)timeout_ms <= timeo);
[3232]132
[1765]133 ret:
[821]134 close(s);
[3621]135 log1("%srp reply received for this address", rv ? "no a" : "A");
[821]136 return rv;
137}
Note: See TracBrowser for help on using the repository browser.