Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / bootp.c
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
new file mode 100644 (file)
index 0000000..1bc6efe
--- /dev/null
@@ -0,0 +1,254 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+#include <dhcp.h>
+
+#define DEBUG 0
+
+static char * response_buffer;
+
+#if DEBUG
+static void
+print_ip(char *ip)
+{
+       printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
+}
+#endif
+
+/* IP header checksum calculation */
+static unsigned short
+checksum(unsigned short *packet, int words)
+{
+       unsigned long checksum;
+       for (checksum = 0; words > 0; words--)
+               checksum += *packet++;
+       checksum = (checksum >> 16) + (checksum & 0xffff);
+       checksum += (checksum >> 16);
+       return ~checksum;
+}
+
+
+static int
+send_bootp(filename_ip_t * fn_ip)
+{
+#if DEBUG
+       int i;
+#endif
+       unsigned int packetsize =
+           sizeof(struct iphdr) + sizeof(struct ethhdr) +
+           sizeof(struct udphdr) + sizeof(struct btphdr);
+       unsigned char packet[packetsize];
+       struct iphdr *iph;
+       struct udphdr *udph;
+       struct btphdr *btph;
+
+       iph = (struct iphdr *) packet;
+       udph = (struct udphdr *) (iph + 1);
+       btph = (struct btphdr *) (udph + 1);
+
+       memset(packet, 0, packetsize);
+
+       fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)),
+                  IPTYPE_UDP, 0, fn_ip->server_ip);
+       fill_udphdr((uint8_t *) udph,
+                   htons(sizeof(struct udphdr) + sizeof(struct btphdr)),
+                   htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS));
+       btph->op = 1;
+       btph->htype = 1;
+       btph->hlen = 6;
+       strcpy((char *) btph->file, "bla");
+       memcpy(btph->chaddr, get_mac_address(), 6);
+
+#if DEBUG
+       printf("Sending packet\n");
+       printf("Packet is ");
+       for (i = 0; i < packetsize; i++)
+               printf(" %02x", packet[i]);
+       printf(".\n");
+#endif
+
+       send_ipv4(fn_ip->fd, packet, iph->ip_len);
+#if DEBUG
+       printf("%d bytes transmitted over socket.\n", i);
+#endif
+
+       return 0;
+}
+
+
+static int
+receive_bootp(filename_ip_t * fn_ip)
+{
+       int len, old_sum;
+       unsigned int packetsize = 2000;
+       unsigned char packet[packetsize];
+       struct iphdr *iph;
+       struct udphdr *udph;
+       struct btphdr *btph;
+
+#if DEBUG
+       struct ethhdr *ethh;
+       ethh = (struct ethhdr *) packet;
+#endif
+
+       iph = (struct iphdr *) (packet + sizeof(struct ethhdr));
+       udph = (struct udphdr *) (iph + 1);
+       btph = (struct btphdr *) (udph + 1);
+
+       memset(packet, 0, packetsize);
+
+       /* setting up a timer with a timeout of one second */
+       set_timer(TICKS_SEC);
+
+       do {
+
+               /* let's receive a packet */
+               len = recv(fn_ip->fd, packet, packetsize, 0);
+
+#if DEBUG
+               int j;
+               printf("%d bytes received, %d expected \n", len, packetsize);
+               if (len == 346) {
+                       printf("Rec packet\n");
+                       printf("Packet is ");
+                       for (j = 0; j < len; j++) {
+                               if (j % 16 == 0)
+                                       printf("\n");
+                               printf(" %02x", packet[j]);
+                       }
+                       printf(".\n");
+               }
+#endif
+               if (len == 0)
+                       continue;
+
+               /* check if the ip checksum is correct */
+               old_sum = iph->ip_sum;
+               iph->ip_sum = 0x00;
+               if (old_sum !=
+                   checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1))
+                       /* checksum failed */
+                       continue;
+               /* is it a udp packet */
+               if (iph->ip_p != IPTYPE_UDP)
+                       continue;
+               /* check if the source port and destination port and the packet
+                * say that it is a bootp answer */
+               if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS))
+                       continue;
+               /* check if it is a Boot Reply */
+               if (btph->op != 2)
+                       continue;
+               /* Comparing our mac address with the one in the bootp reply */ 
+               if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN))
+                       continue;
+
+               if(response_buffer)
+                       memcpy(response_buffer, btph, 1720);
+
+               fn_ip->own_ip = btph->yiaddr;
+               fn_ip->server_ip = btph->siaddr;
+               strcpy((char *) fn_ip->filename, (char *) btph->file);
+
+#if DEBUG
+               printf("\nThese are the details of the bootp reply:\n");
+               printf("Our IP address: ");
+               print_ip((char*) &fn_ip->own_ip);
+               printf("Next server IP address: ");
+               print_ip((char*) &fn_ip->server_ip);
+               printf("Boot file name: %s\n", btph->file);
+               printf("Packet is: %s\n", btph->file);
+               for (j = 0; j < len; j++) {
+                       if (j % 16 == 0)
+                               printf("\n");
+                       printf(" %02x", packet[j]);
+               }
+               printf(".\n");
+               printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       get_mac_address()[0], get_mac_address()[1],
+                       get_mac_address()[2], get_mac_address()[3],
+                       get_mac_address()[4], get_mac_address()[5]);
+               printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                      ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2], 
+                      ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]);
+               printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                      ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2], 
+                      ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]);
+               printf("Header ethh->typ: %x\n",ethh->type); 
+               printf("Header iph->ip_hlv: %x\n",iph->ip_hlv); 
+               printf("Header iph->ip_len: %x\n",iph->ip_len); 
+               printf("Header iph->ip_id: %x\n",iph->ip_id); 
+               printf("Header iph->ip_off: %x\n",iph->ip_off); 
+               printf("Header iph->ip_ttl: %x\n",iph->ip_ttl); 
+               printf("Header iph->ip_p: %x\n",iph->ip_p); 
+               printf("Header iph->ip_sum: %x\n",iph->ip_sum); 
+               printf("Header iph->ip_src: %x\n",iph->ip_src); 
+               printf("Header iph->ip_dst: %x\n",iph->ip_dst); 
+
+               printf("Header btph->op: %x\n",btph->op); 
+               printf("Header btph->htype: %x\n",btph->htype); 
+               printf("Header btph->hlen: %x\n",btph->hlen); 
+               printf("Header btph->hops: %x\n",btph->hops); 
+               printf("Header btph->xid: %x\n",btph->xid); 
+               printf("Header btph->secs: %x\n",btph->secs); 
+               printf("Header btph->ciaddr: %x\n",btph->ciaddr); 
+               printf("Header btph->yiaddr: %x\n",btph->yiaddr); 
+               printf("Header btph->siaddr: %x\n",btph->siaddr); 
+               printf("Header btph->giaddr: %x\n",btph->giaddr); 
+
+               printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n",
+                      btph->chaddr[0], btph->chaddr[1], btph->chaddr[2],
+                      btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]);
+#endif
+               return 0;
+
+               /* only do this for the time specified during set_timer() */
+       } while (get_timer() > 0);
+       return -1;
+}
+
+
+int
+bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
+{
+       int i = (int) retries+1;
+       fn_ip->own_ip = 0;
+
+       printf("   ");
+
+       response_buffer = ret_buffer;
+
+       do {
+               printf("\b\b%02d", i);
+               if (!i--) {
+                       printf("\nGiving up after %d bootp requests\n",
+                              retries+1);
+                       return -1;
+               }
+               send_bootp(fn_ip);
+               /* if the timer in receive_bootp expired it will return
+                * -1 and we will just send another bootp request just
+                * in case the previous one was lost. And because we don't
+                * trust the network cable we keep on doing this 30 times */
+       } while (receive_bootp(fn_ip) != 0);
+       printf("\b\b\b");
+       return 0;
+}