Definition of a (hopefully) generic stream API
[people/xl0/gpxe.git] / src / proto / slam.c
index 135384a..171b6d2 100644 (file)
@@ -1,7 +1,17 @@
-#ifdef DOWNLOAD_PROTO_SLAM
 #include "etherboot.h"
+#include "proto.h"
 #include "nic.h"
 
+/*
+ * IMPORTANT
+ *
+ * This file should be rewritten to avoid the use of a bitmap.  Our
+ * buffer routines can cope with being handed blocks in an arbitrary
+ * order, duplicate blocks, etc.  This code could be substantially
+ * simplified by taking advantage of these features.
+ *
+ */
+
 #define SLAM_PORT 10000
 #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
 #define SLAM_MULTICAST_PORT 10000
@@ -82,6 +92,7 @@ struct slam_state {
 
        unsigned long received_packets;
 
+       struct buffer *buffer;
        unsigned char *image;
        unsigned char *bitmap;
 } state;
@@ -101,21 +112,19 @@ static void init_slam_state(void)
 }
 
 struct slam_info {
-       in_addr server_ip;
-       in_addr multicast_ip;
-       in_addr local_ip;
-       uint16_t server_port;
-       uint16_t multicast_port;
-       uint16_t local_port;
-       int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
+       struct sockaddr_in server;
+       struct sockaddr_in local;
+       struct sockaddr_in multicast;
        int sent_nack;
+       struct buffer *buffer;
 };
 
 #define SLAM_TIMEOUT 0
 #define SLAM_REQUEST 1
 #define SLAM_DATA    2
 static int await_slam(int ival __unused, void *ptr,
-       unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp)
+                     unsigned short ptype __unused, struct iphdr *ip,
+                     struct udphdr *udp, struct tcphdr *tcp __unused)
 {
        struct slam_info *info = ptr;
        if (!udp) {
@@ -126,7 +135,7 @@ static int await_slam(int ival __unused, void *ptr,
         */
        /* Check for a data request packet */
        if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) &&
-               (ntohs(udp->dest) == info->local_port) && 
+               (ntohs(udp->dest) == info->local.sin_port) && 
                (nic.packetlen >= 
                        ETH_HLEN + 
                        sizeof(struct iphdr) + 
@@ -135,8 +144,8 @@ static int await_slam(int ival __unused, void *ptr,
                return SLAM_REQUEST;
        }
        /* Check for a multicast data packet */
-       if ((ip->dest.s_addr == info->multicast_ip.s_addr) &&
-               (ntohs(udp->dest) == info->multicast_port) &&
+       if ((ip->dest.s_addr == info->multicast.sin_addr.s_addr) &&
+               (ntohs(udp->dest) == info->multicast.sin_port) &&
                (nic.packetlen >= 
                        ETH_HLEN + 
                        sizeof(struct iphdr) + 
@@ -203,7 +212,8 @@ static int slam_skip(unsigned char **ptr, unsigned char *end)
        
 }
 
-static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err)
+static unsigned long slam_decode(unsigned char **ptr, unsigned char *end,
+                                int *err)
 {
        unsigned long value;
        unsigned bytes;
@@ -303,12 +313,11 @@ static unsigned char *reinit_slam_state(
                printf("ALERT: slam blocksize to large\n");
                return 0;
        }
-       if (state.bitmap) {
-               forget(state.bitmap);
-       }
        bitmap_len   = (state.total_packets + 1 + 7)/8;
-       state.bitmap = allot(bitmap_len);
-       state.image  = allot(total_bytes);
+       state.image  = phys_to_virt ( state.buffer->addr );
+       /* We don't use the buffer routines properly yet; fake it */
+       state.buffer->fill = total_bytes;
+       state.bitmap = state.image + total_bytes;
        if ((unsigned long)state.image < 1024*1024) {
                printf("ALERT: slam filesize to large for available memory\n");
                return 0;
@@ -368,8 +377,8 @@ static void transmit_nack(unsigned char *ptr, struct slam_info *info)
        /* Ensure the packet is null terminated */
        *ptr++ = 0;
        nack_len = ptr - (unsigned char *)&nack;
-       build_udp_hdr(info->server_ip.s_addr, 
-               info->local_port, info->server_port, 1, nack_len, &nack);
+       build_udp_hdr(info->server.sin_addr.s_addr, info->local.sin_port,
+                     info->server.sin_port, 1, nack_len, &nack);
        ip_transmit(nack_len, &nack);
 #if defined(MDEBUG) && 0
        printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n", 
@@ -439,16 +448,17 @@ static int proto_slam(struct slam_info *info)
        long timeout;
 
        init_slam_state();
+       state.buffer = info->buffer;
 
        retry = -1;
        rx_qdrain();
        /* Arp for my server */
-       if (arptable[ARP_SERVER].ipaddr.s_addr != info->server_ip.s_addr) {
-               arptable[ARP_SERVER].ipaddr.s_addr = info->server_ip.s_addr;
+       if (arptable[ARP_SERVER].ipaddr.s_addr != info->server.sin_addr.s_addr) {
+               arptable[ARP_SERVER].ipaddr.s_addr = info->server.sin_addr.s_addr;
                memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);
        }
        /* If I'm running over multicast join the multicast group */
-       join_group(IGMP_SERVER, info->multicast_ip.s_addr);
+       join_group(IGMP_SERVER, info->multicast.sin_addr.s_addr);
        for(;;) {
                unsigned char *header;
                unsigned char *data;
@@ -503,39 +513,29 @@ static int proto_slam(struct slam_info *info)
        leave_group(IGMP_SERVER);
        /* FIXME don't overwrite myself */
        /* load file to correct location */
-       return info->fnc(state.image, 1, state.total_bytes, 1);
+       return 1;
 }
 
-
-int url_slam(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
-{
+static int url_slam ( char *url __unused, struct sockaddr_in *server,
+                     char *file, struct buffer *buffer ) {
        struct slam_info info;
        /* Set the defaults */
-       info.server_ip.s_addr    = arptable[ARP_SERVER].ipaddr.s_addr;
-       info.server_port         = SLAM_PORT;
-       info.multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP);
-       info.multicast_port      = SLAM_MULTICAST_PORT;
-       info.local_ip.s_addr     = arptable[ARP_CLIENT].ipaddr.s_addr;
-       info.local_port          = SLAM_LOCAL_PORT;
-       info.fnc                 = fnc;
+       info.server = *server;
+       info.multicast.sin_addr.s_addr = htonl(SLAM_MULTICAST_IP);
+       info.multicast.sin_port      = SLAM_MULTICAST_PORT;
+       info.local.sin_addr.s_addr   = arptable[ARP_CLIENT].ipaddr.s_addr;
+       info.local.sin_port          = SLAM_LOCAL_PORT;
+       info.buffer                  = buffer;
        info.sent_nack = 0;
-       /* Now parse the url */
-       if (url_port != -1) {
-               info.server_port = url_port;
-       }
-       if (name[0]) {
-               /* multicast ip */
-               name += inet_aton(name, &info.multicast_ip);
-               if (name[0] == ':') {
-                       name++;
-                       info.multicast_port = strtoul(name, &name, 10);
-               }
-       }
-       if (name[0]) {
+       if (file[0]) {
                printf("\nBad url\n");
                return 0;
        }
        return proto_slam(&info);
 }
 
-#endif /* DOWNLOAD_PROTO_SLAM */
+struct protocol slam_protocol __protocol = {
+       .name = "x-slam",
+       .default_port = SLAM_PORT,
+       .load = url_slam,
+};