1 |
/* vi: set sw=4 ts=4: */ |
/* vi: set sw=4 ts=4: */ |
2 |
|
/* |
3 |
|
* packet.c -- packet ops |
4 |
|
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 |
5 |
|
* |
6 |
|
* Licensed under GPLv2, see file LICENSE in this tarball for details. |
7 |
|
*/ |
8 |
#include <netinet/in.h> |
#include <netinet/in.h> |
9 |
#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION |
#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION |
10 |
#include <netpacket/packet.h> |
#include <netpacket/packet.h> |
19 |
#include "dhcpd.h" |
#include "dhcpd.h" |
20 |
#include "options.h" |
#include "options.h" |
21 |
|
|
22 |
|
void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) |
|
void FAST_FUNC udhcp_init_header(struct dhcpMessage *packet, char type) |
|
23 |
{ |
{ |
24 |
memset(packet, 0, sizeof(struct dhcpMessage)); |
memset(packet, 0, sizeof(struct dhcp_packet)); |
25 |
packet->op = BOOTREQUEST; /* if client to a server */ |
packet->op = BOOTREQUEST; /* if client to a server */ |
26 |
switch (type) { |
switch (type) { |
27 |
case DHCPOFFER: |
case DHCPOFFER: |
36 |
add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); |
add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); |
37 |
} |
} |
38 |
|
|
39 |
|
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 |
40 |
|
void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) |
41 |
|
{ |
42 |
|
char buf[sizeof(packet->chaddr)*2 + 1]; |
43 |
|
|
44 |
|
if (dhcp_verbose < 2) |
45 |
|
return; |
46 |
|
|
47 |
|
bb_info_msg( |
48 |
|
//" op %x" |
49 |
|
//" htype %x" |
50 |
|
" hlen %x" |
51 |
|
//" hops %x" |
52 |
|
" xid %x" |
53 |
|
//" secs %x" |
54 |
|
//" flags %x" |
55 |
|
" ciaddr %x" |
56 |
|
" yiaddr %x" |
57 |
|
" siaddr %x" |
58 |
|
" giaddr %x" |
59 |
|
//" chaddr %s" |
60 |
|
//" sname %s" |
61 |
|
//" file %s" |
62 |
|
//" cookie %x" |
63 |
|
//" options %s" |
64 |
|
//, packet->op |
65 |
|
//, packet->htype |
66 |
|
, packet->hlen |
67 |
|
//, packet->hops |
68 |
|
, packet->xid |
69 |
|
//, packet->secs |
70 |
|
//, packet->flags |
71 |
|
, packet->ciaddr |
72 |
|
, packet->yiaddr |
73 |
|
, packet->siaddr_nip |
74 |
|
, packet->gateway_nip |
75 |
|
//, packet->chaddr[16] |
76 |
|
//, packet->sname[64] |
77 |
|
//, packet->file[128] |
78 |
|
//, packet->cookie |
79 |
|
//, packet->options[] |
80 |
|
); |
81 |
|
*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; |
82 |
|
bb_info_msg(" chaddr %s", buf); |
83 |
|
} |
84 |
|
#endif |
85 |
|
|
86 |
/* read a packet from socket fd, return -1 on read error, -2 on packet error */ |
/* Read a packet from socket fd, return -1 on read error, -2 on packet error */ |
87 |
int FAST_FUNC udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) |
int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) |
88 |
{ |
{ |
89 |
int bytes; |
int bytes; |
90 |
unsigned char *vendor; |
unsigned char *vendor; |
92 |
memset(packet, 0, sizeof(*packet)); |
memset(packet, 0, sizeof(*packet)); |
93 |
bytes = safe_read(fd, packet, sizeof(*packet)); |
bytes = safe_read(fd, packet, sizeof(*packet)); |
94 |
if (bytes < 0) { |
if (bytes < 0) { |
95 |
DEBUG("cannot read on listening socket, ignoring"); |
log1("Packet read error, ignoring"); |
96 |
return bytes; /* returns -1 */ |
return bytes; /* returns -1 */ |
97 |
} |
} |
98 |
|
|
99 |
if (packet->cookie != htonl(DHCP_MAGIC)) { |
if (packet->cookie != htonl(DHCP_MAGIC)) { |
100 |
bb_error_msg("received bogus message, ignoring"); |
bb_info_msg("Packet with bad magic, ignoring"); |
101 |
return -2; |
return -2; |
102 |
} |
} |
103 |
DEBUG("Received a packet"); |
log1("Received a packet"); |
104 |
|
udhcp_dump_packet(packet); |
105 |
|
|
106 |
if (packet->op == BOOTREQUEST) { |
if (packet->op == BOOTREQUEST) { |
107 |
vendor = get_option(packet, DHCP_VENDOR); |
vendor = get_option(packet, DHCP_VENDOR); |
116 |
if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i]) |
if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i]) |
117 |
&& !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2]) |
&& !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2]) |
118 |
) { |
) { |
119 |
DEBUG("broken client (%s), forcing broadcast replies", |
log1("Broken client (%s), forcing broadcast replies", |
120 |
broken_vendors[i]); |
broken_vendors[i]); |
121 |
packet->flags |= htons(BROADCAST_FLAG); |
packet->flags |= htons(BROADCAST_FLAG); |
122 |
} |
} |
125 |
if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1) |
if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1) |
126 |
&& memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 |
&& memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 |
127 |
) { |
) { |
128 |
DEBUG("broken client (%s), forcing broadcast replies", "MSFT 98"); |
log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); |
129 |
packet->flags |= htons(BROADCAST_FLAG); |
packet->flags |= htons(BROADCAST_FLAG); |
130 |
} |
} |
131 |
#endif |
#endif |
135 |
return bytes; |
return bytes; |
136 |
} |
} |
137 |
|
|
|
|
|
138 |
uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) |
uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) |
139 |
{ |
{ |
140 |
/* Compute Internet Checksum for "count" bytes |
/* Compute Internet Checksum for "count" bytes |
141 |
* beginning at location "addr". |
* beginning at location "addr". |
142 |
*/ |
*/ |
143 |
int32_t sum = 0; |
int32_t sum = 0; |
144 |
uint16_t *source = (uint16_t *) addr; |
uint16_t *source = (uint16_t *) addr; |
164 |
return ~sum; |
return ~sum; |
165 |
} |
} |
166 |
|
|
|
|
|
167 |
/* Construct a ip/udp header for a packet, send packet */ |
/* Construct a ip/udp header for a packet, send packet */ |
168 |
int FAST_FUNC udhcp_send_raw_packet(struct dhcpMessage *payload, |
int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, |
169 |
uint32_t source_ip, int source_port, |
uint32_t source_ip, int source_port, |
170 |
uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, |
uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, |
171 |
int ifindex) |
int ifindex) |
172 |
{ |
{ |
173 |
struct sockaddr_ll dest; |
struct sockaddr_ll dest; |
174 |
struct udp_dhcp_packet packet; |
struct ip_udp_dhcp_packet packet; |
175 |
int fd; |
int fd; |
176 |
int result = -1; |
int result = -1; |
177 |
const char *msg; |
const char *msg; |
178 |
|
|
179 |
enum { |
enum { |
180 |
IP_UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
181 |
UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct udp_dhcp_packet, udp), |
UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct ip_udp_dhcp_packet, udp), |
182 |
}; |
}; |
183 |
|
|
184 |
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); |
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); |
189 |
|
|
190 |
memset(&dest, 0, sizeof(dest)); |
memset(&dest, 0, sizeof(dest)); |
191 |
memset(&packet, 0, sizeof(packet)); |
memset(&packet, 0, sizeof(packet)); |
192 |
packet.data = *payload; /* struct copy */ |
packet.data = *dhcp_pkt; /* struct copy */ |
193 |
|
|
194 |
dest.sll_family = AF_PACKET; |
dest.sll_family = AF_PACKET; |
195 |
dest.sll_protocol = htons(ETH_P_IP); |
dest.sll_protocol = htons(ETH_P_IP); |
222 |
* If you need to change this: last byte of the packet is |
* If you need to change this: last byte of the packet is |
223 |
* packet.data.options[end_option(packet.data.options)] |
* packet.data.options[end_option(packet.data.options)] |
224 |
*/ |
*/ |
225 |
|
udhcp_dump_packet(dhcp_pkt); |
226 |
result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, |
result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, |
227 |
(struct sockaddr *) &dest, sizeof(dest)); |
(struct sockaddr *) &dest, sizeof(dest)); |
228 |
msg = "sendto"; |
msg = "sendto"; |
235 |
return result; |
return result; |
236 |
} |
} |
237 |
|
|
|
|
|
238 |
/* Let the kernel do all the work for packet generation */ |
/* Let the kernel do all the work for packet generation */ |
239 |
int FAST_FUNC udhcp_send_kernel_packet(struct dhcpMessage *payload, |
int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, |
240 |
uint32_t source_ip, int source_port, |
uint32_t source_ip, int source_port, |
241 |
uint32_t dest_ip, int dest_port) |
uint32_t dest_ip, int dest_port) |
242 |
{ |
{ |
246 |
const char *msg; |
const char *msg; |
247 |
|
|
248 |
enum { |
enum { |
249 |
DHCP_SIZE = sizeof(struct dhcpMessage) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
250 |
}; |
}; |
251 |
|
|
252 |
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
275 |
} |
} |
276 |
|
|
277 |
/* Currently we send full-sized DHCP packets (see above) */ |
/* Currently we send full-sized DHCP packets (see above) */ |
278 |
result = safe_write(fd, payload, DHCP_SIZE); |
udhcp_dump_packet(dhcp_pkt); |
279 |
|
result = safe_write(fd, dhcp_pkt, DHCP_SIZE); |
280 |
msg = "write"; |
msg = "write"; |
281 |
ret_close: |
ret_close: |
282 |
close(fd); |
close(fd); |