1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12 
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include <time.h>
18 
19 #include <ethernet.h>
20 #include <ipv4.h>
21 #include <udp.h>
22 #include <dhcp.h>
23 
24 #define DEBUG 0
25 
26 static char * response_buffer;
27 
28 #if DEBUG
29 static void
print_ip(char * ip)30 print_ip(char *ip)
31 {
32 	printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
33 }
34 #endif
35 
36 /* IP header checksum calculation */
37 static unsigned short
checksum(unsigned short * packet,int words)38 checksum(unsigned short *packet, int words)
39 {
40 	unsigned long checksum;
41 	for (checksum = 0; words > 0; words--)
42 		checksum += *packet++;
43 	checksum = (checksum >> 16) + (checksum & 0xffff);
44 	checksum += (checksum >> 16);
45 	return ~checksum;
46 }
47 
48 
49 static int
send_bootp(filename_ip_t * fn_ip)50 send_bootp(filename_ip_t * fn_ip)
51 {
52 #if DEBUG
53 	int i;
54 #endif
55 	unsigned int packetsize =
56 	    sizeof(struct iphdr) + sizeof(struct ethhdr) +
57 	    sizeof(struct udphdr) + sizeof(struct btphdr);
58 	unsigned char packet[packetsize];
59 	struct iphdr *iph;
60 	struct udphdr *udph;
61 	struct btphdr *btph;
62 
63 	iph = (struct iphdr *) packet;
64 	udph = (struct udphdr *) (iph + 1);
65 	btph = (struct btphdr *) (udph + 1);
66 
67 	memset(packet, 0, packetsize);
68 
69 	fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)),
70 	           IPTYPE_UDP, 0, fn_ip->server_ip);
71 	fill_udphdr((uint8_t *) udph,
72 	            htons(sizeof(struct udphdr) + sizeof(struct btphdr)),
73 	            htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS));
74 	btph->op = 1;
75 	btph->htype = 1;
76 	btph->hlen = 6;
77 	strcpy((char *) btph->file, "bla");
78 	memcpy(btph->chaddr, get_mac_address(), 6);
79 
80 #if DEBUG
81 	printf("Sending packet\n");
82 	printf("Packet is ");
83 	for (i = 0; i < packetsize; i++)
84 		printf(" %02x", packet[i]);
85 	printf(".\n");
86 #endif
87 
88 	send_ipv4(fn_ip->fd, packet, iph->ip_len);
89 #if DEBUG
90 	printf("%d bytes transmitted over socket.\n", i);
91 #endif
92 
93 	return 0;
94 }
95 
96 
97 static int
receive_bootp(filename_ip_t * fn_ip)98 receive_bootp(filename_ip_t * fn_ip)
99 {
100 	int len, old_sum;
101 	unsigned int packetsize = 2000;
102 	unsigned char packet[packetsize];
103 	struct iphdr *iph;
104 	struct udphdr *udph;
105 	struct btphdr *btph;
106 
107 #if DEBUG
108 	struct ethhdr *ethh;
109 	ethh = (struct ethhdr *) packet;
110 #endif
111 
112 	iph = (struct iphdr *) (packet + sizeof(struct ethhdr));
113 	udph = (struct udphdr *) (iph + 1);
114 	btph = (struct btphdr *) (udph + 1);
115 
116 	memset(packet, 0, packetsize);
117 
118 	/* setting up a timer with a timeout of one second */
119 	set_timer(TICKS_SEC);
120 
121 	do {
122 
123 		/* let's receive a packet */
124 		len = recv(fn_ip->fd, packet, packetsize, 0);
125 
126 #if DEBUG
127 		int j;
128 		printf("%d bytes received, %d expected \n", len, packetsize);
129 		if (len == 346) {
130 			printf("Rec packet\n");
131 			printf("Packet is ");
132 			for (j = 0; j < len; j++) {
133 				if (j % 16 == 0)
134 					printf("\n");
135 				printf(" %02x", packet[j]);
136 			}
137 			printf(".\n");
138 		}
139 #endif
140 		if (len == 0)
141 			continue;
142 
143 		/* check if the ip checksum is correct */
144 		old_sum = iph->ip_sum;
145 		iph->ip_sum = 0x00;
146 		if (old_sum !=
147 		    checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1))
148 			/* checksum failed */
149 			continue;
150 		/* is it a udp packet */
151 		if (iph->ip_p != IPTYPE_UDP)
152 			continue;
153 		/* check if the source port and destination port and the packet
154 		 * say that it is a bootp answer */
155 		if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS))
156 			continue;
157 		/* check if it is a Boot Reply */
158 		if (btph->op != 2)
159 			continue;
160 		/* Comparing our mac address with the one in the bootp reply */
161 		if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN))
162 			continue;
163 
164 		if(response_buffer)
165 			memcpy(response_buffer, btph, 1720);
166 
167 		fn_ip->own_ip = btph->yiaddr;
168 		fn_ip->server_ip = btph->siaddr;
169 		strcpy(fn_ip->filename, (char *)btph->file);
170 
171 #if DEBUG
172 		printf("\nThese are the details of the bootp reply:\n");
173 		printf("Our IP address: ");
174 		print_ip((char*) &fn_ip->own_ip);
175 		printf("Next server IP address: ");
176 		print_ip((char*) &fn_ip->server_ip);
177 		printf("Boot file name: %s\n", btph->file);
178 		printf("Packet is: %s\n", btph->file);
179 		for (j = 0; j < len; j++) {
180 			if (j % 16 == 0)
181 				printf("\n");
182 			printf(" %02x", packet[j]);
183 		}
184 		printf(".\n");
185 		printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
186 		        get_mac_address()[0], get_mac_address()[1],
187 		        get_mac_address()[2], get_mac_address()[3],
188 		        get_mac_address()[4], get_mac_address()[5]);
189 		printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
190 		       ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2],
191 		       ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]);
192 		printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
193 		       ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2],
194 		       ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]);
195 		printf("Header ethh->typ: %x\n",ethh->type);
196 		printf("Header iph->ip_hlv: %x\n",iph->ip_hlv);
197 		printf("Header iph->ip_len: %x\n",iph->ip_len);
198 		printf("Header iph->ip_id: %x\n",iph->ip_id);
199 		printf("Header iph->ip_off: %x\n",iph->ip_off);
200 		printf("Header iph->ip_ttl: %x\n",iph->ip_ttl);
201 		printf("Header iph->ip_p: %x\n",iph->ip_p);
202 		printf("Header iph->ip_sum: %x\n",iph->ip_sum);
203 		printf("Header iph->ip_src: %x\n",iph->ip_src);
204 		printf("Header iph->ip_dst: %x\n",iph->ip_dst);
205 
206 		printf("Header btph->op: %x\n",btph->op);
207 		printf("Header btph->htype: %x\n",btph->htype);
208 		printf("Header btph->hlen: %x\n",btph->hlen);
209 		printf("Header btph->hops: %x\n",btph->hops);
210 		printf("Header btph->xid: %x\n",btph->xid);
211 		printf("Header btph->secs: %x\n",btph->secs);
212 		printf("Header btph->ciaddr: %x\n",btph->ciaddr);
213 		printf("Header btph->yiaddr: %x\n",btph->yiaddr);
214 		printf("Header btph->siaddr: %x\n",btph->siaddr);
215 		printf("Header btph->giaddr: %x\n",btph->giaddr);
216 
217  		printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n",
218 		       btph->chaddr[0], btph->chaddr[1], btph->chaddr[2],
219 		       btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]);
220 #endif
221 		return 0;
222 
223 		/* only do this for the time specified during set_timer() */
224 	} while (get_timer() > 0);
225 	return -1;
226 }
227 
228 
229 int
bootp(char * ret_buffer,filename_ip_t * fn_ip,unsigned int retries)230 bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
231 {
232 	int i = (int) retries+1;
233 	fn_ip->own_ip = 0;
234 
235 	printf("  Requesting IP address via BOOTP:    ");
236 
237 	response_buffer = ret_buffer;
238 
239 	do {
240 		printf("\b\b%02d", i);
241 		if (!i--) {
242 			printf("\nGiving up after %d bootp requests\n",
243 			       retries+1);
244 			return -1;
245 		}
246 		send_bootp(fn_ip);
247 		/* if the timer in receive_bootp expired it will return
248 		 * -1 and we will just send another bootp request just
249 		 * in case the previous one was lost. And because we don't
250 		 * trust the network cable we keep on doing this 30 times */
251 	} while (receive_bootp(fn_ip) != 0);
252 
253 	printf("\b\b\bdone\n");
254 	return 0;
255 }
256