source: MondoRescue/branches/3.3/mindi-busybox/networking/udhcp/packet.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: 6.1 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
[2725]2/*
3 * Packet ops
4 *
5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
[821]9#include "common.h"
10#include "dhcpd.h"
[3232]11#include <netinet/in.h>
12#include <netinet/if_ether.h>
13#include <netpacket/packet.h>
[821]14
[2725]15void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type)
[821]16{
[2725]17 memset(packet, 0, sizeof(*packet));
18 packet->op = BOOTREQUEST; /* if client to a server */
[821]19 switch (type) {
20 case DHCPOFFER:
21 case DHCPACK:
22 case DHCPNAK:
[2725]23 packet->op = BOOTREPLY; /* if server to client */
[821]24 }
[2725]25 packet->htype = 1; /* ethernet */
26 packet->hlen = 6;
[821]27 packet->cookie = htonl(DHCP_MAGIC);
[2725]28 if (DHCP_END != 0)
29 packet->options[0] = DHCP_END;
30 udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
[821]31}
32
[2725]33#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
34void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
35{
36 char buf[sizeof(packet->chaddr)*2 + 1];
[821]37
[2725]38 if (dhcp_verbose < 2)
39 return;
40
[3621]41 bb_error_msg(
42 //"op %x"
[2725]43 //" htype %x"
44 " hlen %x"
45 //" hops %x"
46 " xid %x"
47 //" secs %x"
48 //" flags %x"
49 " ciaddr %x"
50 " yiaddr %x"
51 " siaddr %x"
52 " giaddr %x"
53 //" chaddr %s"
54 //" sname %s"
55 //" file %s"
56 //" cookie %x"
57 //" options %s"
58 //, packet->op
59 //, packet->htype
60 , packet->hlen
61 //, packet->hops
62 , packet->xid
63 //, packet->secs
64 //, packet->flags
65 , packet->ciaddr
66 , packet->yiaddr
67 , packet->siaddr_nip
68 , packet->gateway_nip
69 //, packet->chaddr[16]
70 //, packet->sname[64]
71 //, packet->file[128]
72 //, packet->cookie
73 //, packet->options[]
74 );
75 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
[3621]76 bb_error_msg("chaddr %s", buf);
[2725]77}
78#endif
79
80/* Read a packet from socket fd, return -1 on read error, -2 on packet error */
81int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
[821]82{
83 int bytes;
84
[1765]85 memset(packet, 0, sizeof(*packet));
[2725]86 bytes = safe_read(fd, packet, sizeof(*packet));
[821]87 if (bytes < 0) {
[3621]88 log1("packet read error, ignoring");
[2725]89 return bytes; /* returns -1 */
[821]90 }
91
[3232]92 if (bytes < offsetof(struct dhcp_packet, options)
93 || packet->cookie != htonl(DHCP_MAGIC)
94 ) {
[3621]95 bb_error_msg("packet with bad magic, ignoring");
[821]96 return -2;
97 }
[3621]98 log1("received %s", "a packet");
[2725]99 udhcp_dump_packet(packet);
[821]100
101 return bytes;
102}
103
[2725]104/* Construct a ip/udp header for a packet, send packet */
105int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
106 uint32_t source_nip, int source_port,
107 uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
108 int ifindex)
[821]109{
[2725]110 struct sockaddr_ll dest_sll;
111 struct ip_udp_dhcp_packet packet;
112 unsigned padding;
[821]113 int fd;
[2725]114 int result = -1;
115 const char *msg;
[821]116
[1765]117 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
118 if (fd < 0) {
[2725]119 msg = "socket(%s)";
120 goto ret_msg;
[821]121 }
122
[2725]123 memset(&dest_sll, 0, sizeof(dest_sll));
124 memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
125 packet.data = *dhcp_pkt; /* struct copy */
[821]126
[2725]127 dest_sll.sll_family = AF_PACKET;
128 dest_sll.sll_protocol = htons(ETH_P_IP);
129 dest_sll.sll_ifindex = ifindex;
130 dest_sll.sll_halen = 6;
131 memcpy(dest_sll.sll_addr, dest_arp, 6);
132
133 if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
134 msg = "bind(%s)";
135 goto ret_close;
[821]136 }
137
[2725]138 /* We were sending full-sized DHCP packets (zero padded),
139 * but some badly configured servers were seen dropping them.
140 * Apparently they drop all DHCP packets >576 *ethernet* octets big,
141 * whereas they may only drop packets >576 *IP* octets big
142 * (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
143 *
144 * In order to work with those buggy servers,
145 * we truncate packets after end option byte.
[3621]146 *
147 * However, RFC 1542 says "The IP Total Length and UDP Length
148 * must be large enough to contain the minimal BOOTP header of 300 octets".
149 * Thus, we retain enough padding to not go below 300 BOOTP bytes.
150 * Some devices have filters which drop DHCP packets shorter than that.
[2725]151 */
152 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
[3621]153 if (padding > DHCP_SIZE - 300)
154 padding = DHCP_SIZE - 300;
[2725]155
[821]156 packet.ip.protocol = IPPROTO_UDP;
[2725]157 packet.ip.saddr = source_nip;
158 packet.ip.daddr = dest_nip;
[821]159 packet.udp.source = htons(source_port);
160 packet.udp.dest = htons(dest_port);
[2725]161 /* size, excluding IP header: */
162 packet.udp.len = htons(UDP_DHCP_SIZE - padding);
163 /* for UDP checksumming, ip.len is set to UDP packet len */
[821]164 packet.ip.tot_len = packet.udp.len;
[3232]165 packet.udp.check = inet_cksum((uint16_t *)&packet,
166 IP_UDP_DHCP_SIZE - padding);
[2725]167 /* but for sending, it is set to IP packet len */
168 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
[821]169 packet.ip.ihl = sizeof(packet.ip) >> 2;
170 packet.ip.version = IPVERSION;
171 packet.ip.ttl = IPDEFTTL;
[3232]172 packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip));
[821]173
[2725]174 udhcp_dump_packet(dhcp_pkt);
175 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
176 (struct sockaddr *) &dest_sll, sizeof(dest_sll));
177 msg = "sendto";
178 ret_close:
179 close(fd);
180 if (result < 0) {
181 ret_msg:
182 bb_perror_msg(msg, "PACKET");
[821]183 }
184 return result;
185}
186
187/* Let the kernel do all the work for packet generation */
[2725]188int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
189 uint32_t source_nip, int source_port,
190 uint32_t dest_nip, int dest_port)
[821]191{
[3232]192 struct sockaddr_in sa;
[2725]193 unsigned padding;
194 int fd;
195 int result = -1;
196 const char *msg;
[821]197
[1765]198 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
[2725]199 if (fd < 0) {
200 msg = "socket(%s)";
201 goto ret_msg;
202 }
[1765]203 setsockopt_reuseaddr(fd);
[821]204
[3232]205 memset(&sa, 0, sizeof(sa));
206 sa.sin_family = AF_INET;
207 sa.sin_port = htons(source_port);
208 sa.sin_addr.s_addr = source_nip;
209 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
[2725]210 msg = "bind(%s)";
211 goto ret_close;
[821]212 }
213
[3232]214 memset(&sa, 0, sizeof(sa));
215 sa.sin_family = AF_INET;
216 sa.sin_port = htons(dest_port);
217 sa.sin_addr.s_addr = dest_nip;
218 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
[2725]219 msg = "connect";
220 goto ret_close;
[821]221 }
222
[2725]223 udhcp_dump_packet(dhcp_pkt);
224 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
[3621]225 if (padding > DHCP_SIZE - 300)
226 padding = DHCP_SIZE - 300;
[2725]227 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
228 msg = "write";
229 ret_close:
[821]230 close(fd);
[2725]231 if (result < 0) {
232 ret_msg:
233 bb_perror_msg(msg, "UDP");
234 }
[821]235 return result;
236}
Note: See TracBrowser for help on using the repository browser.