Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / bootp.c
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
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
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
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
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((char *) 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
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("   ");
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         printf("\b\b\b");
253         return 0;
254 }