1 /* vi: set sw=4 ts=4: */
5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
7 * Licensed under GPLv2, see file LICENSE in this source tree.
11 #include <netinet/in.h>
12 #include <netinet/if_ether.h>
13 #include <netpacket/packet.h>
15 int minpkt
= 0; // zzz
17 void FAST_FUNC
udhcp_init_header(struct dhcp_packet
*packet
, char type
)
19 memset(packet
, 0, sizeof(*packet
));
20 packet
->op
= BOOTREQUEST
; /* if client to a server */
25 packet
->op
= BOOTREPLY
; /* if server to client */
27 packet
->htype
= 1; /* ethernet */
29 packet
->cookie
= htonl(DHCP_MAGIC
);
31 packet
->options
[0] = DHCP_END
;
32 udhcp_add_simple_option(packet
, DHCP_MESSAGE_TYPE
, type
);
35 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
36 void FAST_FUNC
udhcp_dump_packet(struct dhcp_packet
*packet
)
38 char buf
[sizeof(packet
->chaddr
)*2 + 1];
71 //, packet->chaddr[16]
77 *bin2hex(buf
, (void *) packet
->chaddr
, sizeof(packet
->chaddr
)) = '\0';
78 bb_error_msg("chaddr %s", buf
);
82 /* Read a packet from socket fd, return -1 on read error, -2 on packet error */
83 int FAST_FUNC
udhcp_recv_kernel_packet(struct dhcp_packet
*packet
, int fd
)
87 memset(packet
, 0, sizeof(*packet
));
88 bytes
= safe_read(fd
, packet
, sizeof(*packet
));
90 log1("packet read error, ignoring");
91 return bytes
; /* returns -1 */
94 if (bytes
< offsetof(struct dhcp_packet
, options
)
95 || packet
->cookie
!= htonl(DHCP_MAGIC
)
97 bb_error_msg("packet with bad magic, ignoring");
100 log1("received %s", "a packet");
101 udhcp_dump_packet(packet
);
106 /* Construct a ip/udp header for a packet, send packet */
107 int FAST_FUNC
udhcp_send_raw_packet(struct dhcp_packet
*dhcp_pkt
,
108 uint32_t source_nip
, int source_port
,
109 uint32_t dest_nip
, int dest_port
, const uint8_t *dest_arp
,
112 struct sockaddr_ll dest_sll
;
113 struct ip_udp_dhcp_packet packet
;
119 fd
= socket(PF_PACKET
, SOCK_DGRAM
, htons(ETH_P_IP
));
125 memset(&dest_sll
, 0, sizeof(dest_sll
));
126 memset(&packet
, 0, offsetof(struct ip_udp_dhcp_packet
, data
));
127 packet
.data
= *dhcp_pkt
; /* struct copy */
129 dest_sll
.sll_family
= AF_PACKET
;
130 dest_sll
.sll_protocol
= htons(ETH_P_IP
);
131 dest_sll
.sll_ifindex
= ifindex
;
132 dest_sll
.sll_halen
= 6;
133 memcpy(dest_sll
.sll_addr
, dest_arp
, 6);
135 if (bind(fd
, (struct sockaddr
*)&dest_sll
, sizeof(dest_sll
)) < 0) {
140 /* We were sending full-sized DHCP packets (zero padded),
141 * but some badly configured servers were seen dropping them.
142 * Apparently they drop all DHCP packets >576 *ethernet* octets big,
143 * whereas they may only drop packets >576 *IP* octets big
144 * (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
146 * In order to work with those buggy servers,
147 * we truncate packets after end option byte.
149 * However, RFC 1542 says "The IP Total Length and UDP Length
150 * must be large enough to contain the minimal BOOTP header of 300 octets".
151 * Thus, we retain enough padding to not go below 300 BOOTP bytes.
152 * Some devices have filters which drop DHCP packets shorter than that.
155 padding
= minpkt
? DHCP_OPTIONS_BUFSIZE
- 1 - udhcp_end_option(packet
.data
.options
) : 0;
157 if (padding
> DHCP_SIZE
- 300)
158 padding
= DHCP_SIZE
- 300;
160 packet
.ip
.protocol
= IPPROTO_UDP
;
161 packet
.ip
.saddr
= source_nip
;
162 packet
.ip
.daddr
= dest_nip
;
163 packet
.udp
.source
= htons(source_port
);
164 packet
.udp
.dest
= htons(dest_port
);
165 /* size, excluding IP header: */
166 packet
.udp
.len
= htons(UDP_DHCP_SIZE
- padding
);
167 /* for UDP checksumming, ip.len is set to UDP packet len */
168 packet
.ip
.tot_len
= packet
.udp
.len
;
169 packet
.udp
.check
= inet_cksum((uint16_t *)&packet
,
170 IP_UDP_DHCP_SIZE
- padding
);
171 /* but for sending, it is set to IP packet len */
172 packet
.ip
.tot_len
= htons(IP_UDP_DHCP_SIZE
- padding
);
173 packet
.ip
.ihl
= sizeof(packet
.ip
) >> 2;
174 packet
.ip
.version
= IPVERSION
;
175 packet
.ip
.ttl
= IPDEFTTL
;
176 packet
.ip
.check
= inet_cksum((uint16_t *)&packet
.ip
, sizeof(packet
.ip
));
178 udhcp_dump_packet(dhcp_pkt
);
179 result
= sendto(fd
, &packet
, IP_UDP_DHCP_SIZE
- padding
, /*flags:*/ 0,
180 (struct sockaddr
*) &dest_sll
, sizeof(dest_sll
));
186 bb_perror_msg(msg
, "PACKET");
191 /* Let the kernel do all the work for packet generation */
192 int FAST_FUNC
udhcp_send_kernel_packet(struct dhcp_packet
*dhcp_pkt
,
193 uint32_t source_nip
, int source_port
,
194 uint32_t dest_nip
, int dest_port
)
196 struct sockaddr_in sa
;
202 fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
207 setsockopt_reuseaddr(fd
);
209 memset(&sa
, 0, sizeof(sa
));
210 sa
.sin_family
= AF_INET
;
211 sa
.sin_port
= htons(source_port
);
212 sa
.sin_addr
.s_addr
= source_nip
;
213 if (bind(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
218 memset(&sa
, 0, sizeof(sa
));
219 sa
.sin_family
= AF_INET
;
220 sa
.sin_port
= htons(dest_port
);
221 sa
.sin_addr
.s_addr
= dest_nip
;
222 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
227 udhcp_dump_packet(dhcp_pkt
);
228 padding
= minpkt
? DHCP_OPTIONS_BUFSIZE
- 1 - udhcp_end_option(dhcp_pkt
->options
) : 0;
229 if (padding
> DHCP_SIZE
- 300)
230 padding
= DHCP_SIZE
- 300;
231 result
= safe_write(fd
, dhcp_pkt
, DHCP_SIZE
- padding
);
237 bb_perror_msg(msg
, "UDP");