Merge from Etherboot 5.4
[people/lynusvaz/gpxe.git] / src / core / nic.c
index 3909f54..be6eb7b 100644 (file)
@@ -21,13 +21,10 @@ Literature dealing with the network protocols:
 #include "resolv.h"
 #include "dev.h"
 #include "nic.h"
+#include "background.h"
 #include "elf.h" /* FOR EM_CURRENT */
 
 struct arptable_t      arptable[MAX_ARP];
-#if MULTICAST_LEVEL2
-unsigned long last_igmpv1 = 0;
-struct igmptable_t     igmptable[MAX_IGMP];
-#endif
 /* Put rom_info in .nocompress section so romprefix.S can write to it */
 struct rom_info        rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
 static unsigned long   netmask;
@@ -36,6 +33,14 @@ char *hostname = "";
 int hostnamelen = 0;
 static uint32_t xid;
 unsigned char *end_of_rfc1533 = NULL;
+unsigned char *addparam;
+int addparamlen;
+
+#ifdef IMAGE_FREEBSD
+int freebsd_howto = 0;
+char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
+#endif /* IMAGE_FREEBSD */
+
 static int vendorext_isvalid;
 static const unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* √§Eth */
 static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -264,9 +269,8 @@ static int nic_configure ( struct type_dev *type_dev ) {
 #endif /* PXE_EXPORT */
 #endif /* ! NO_DHCP_SUPPORT */
        printf(", TFTP: %@", arptable[ARP_SERVER].ipaddr.s_addr);
-       if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
-               printf(", Relay: %@",
-                       BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
+       if (bootp_data.bootp_reply.bp_giaddr.s_addr)
+               printf(", Relay: %@", bootp_data.bootp_reply.bp_giaddr.s_addr);
        if (arptable[ARP_GATEWAY].ipaddr.s_addr)
                printf(", Gateway %@", arptable[ARP_GATEWAY].ipaddr.s_addr);
        if (arptable[ARP_NAMESERVER].ipaddr.s_addr)
@@ -319,6 +323,22 @@ static int nic_load ( struct type_dev *type_dev, struct buffer *buffer ) {
                NULL
 #endif
                : KERNEL_BUF;
+#ifdef  ZPXE_SUFFIX_STRIP
+        {
+          int i = 0;
+          while (kernel[i++]);
+          if(i > 5) {
+            if(kernel[i - 6] == '.' &&
+               kernel[i - 5] == 'z' &&
+               kernel[i - 4] == 'p' &&
+               kernel[i - 3] == 'x' &&
+               kernel[i - 2] == 'e') {
+              printf("Trimming .zpxe extension\n");
+              kernel[i - 6] = 0;
+            }
+          }
+        }
+#endif
        if ( kernel ) {
                return download_url ( kernel, buffer );
        } else {        
@@ -427,7 +447,6 @@ int ip_transmit(int len, const void *buf)
        destip = ip->dest.s_addr;
        if (destip == IP_BROADCAST) {
                eth_transmit(broadcast, ETH_P_IP, len, buf);
-#ifdef MULTICAST_LEVEL1 
        } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
                unsigned char multicast[6];
                unsigned long hdestip;
@@ -439,7 +458,6 @@ int ip_transmit(int len, const void *buf)
                multicast[4] = (hdestip >> 8) & 0xff;
                multicast[5] = hdestip & 0xff;
                eth_transmit(multicast, ETH_P_IP, len, buf);
-#endif
        } else {
                if (((destip & netmask) !=
                        (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
@@ -664,8 +682,8 @@ static int await_bootp(int ival __unused, void *ptr __unused,
 #endif /* NO_DHCP_SUPPORT */
                netmask = default_netmask();
                /* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
-               memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
-               decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, 0,
+               memcpy((char *)&bootp_data, (char *)bootpreply, sizeof(struct bootpd_t));
+               decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
 #ifdef NO_DHCP_SUPPORT
                               BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 
 #else
@@ -740,11 +758,13 @@ static int bootp(void)
                remaining_time = rfc2131_sleep_interval(BOOTP_TIMEOUT, retry++);
                stop_time = currticks() + remaining_time;
 #ifdef NO_DHCP_SUPPORT
-               if (await_reply(await_bootp, 0, NULL, timeout))
+               if (await_reply(await_bootp, 0, NULL, remaining_time))
                        return(1);
 #else
                while ( remaining_time > 0 ) {
                        if (await_reply(await_bootp, 0, NULL, remaining_time)){
+                               if (arptable[ARP_CLIENT].ipaddr.s_addr)
+                                       break;
                        }
                        remaining_time = stop_time - currticks();
                }
@@ -827,140 +847,6 @@ uint16_t tcpudpchksum(struct iphdr *ip)
        return checksum;
 }
 
-#ifdef MULTICAST_LEVEL2
-static void send_igmp_reports(unsigned long now)
-{
-       int i;
-       for(i = 0; i < MAX_IGMP; i++) {
-               if (igmptable[i].time && (now >= igmptable[i].time)) {
-                       struct igmp_ip_t igmp;
-                       igmp.router_alert[0] = 0x94;
-                       igmp.router_alert[1] = 0x04;
-                       igmp.router_alert[2] = 0;
-                       igmp.router_alert[3] = 0;
-                       build_ip_hdr(igmptable[i].group.s_addr, 
-                               1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
-                       igmp.igmp.type = IGMPv2_REPORT;
-                       if (last_igmpv1 && 
-                               (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
-                               igmp.igmp.type = IGMPv1_REPORT;
-                       }
-                       igmp.igmp.response_time = 0;
-                       igmp.igmp.chksum = 0;
-                       igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
-                       igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
-                       ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
-                       printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
-#endif
-                       /* Don't send another igmp report until asked */
-                       igmptable[i].time = 0;
-               }
-       }
-}
-
-static void process_igmp(struct iphdr *ip, unsigned long now)
-{
-       struct igmp *igmp;
-       int i;
-       unsigned iplen;
-       if (!ip || (ip->protocol == IP_IGMP) ||
-               (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
-               return;
-       }
-       iplen = (ip->verhdrlen & 0xf)*4;
-       igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
-       if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
-               return;
-       if ((igmp->type == IGMP_QUERY) && 
-               (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
-               unsigned long interval = IGMP_INTERVAL;
-               if (igmp->response_time == 0) {
-                       last_igmpv1 = now;
-               } else {
-                       interval = (igmp->response_time * TICKS_PER_SEC)/10;
-               }
-               
-#ifdef MDEBUG
-               printf("Received IGMP query for: %@\n", igmp->group.s_addr);
-#endif                        
-               for(i = 0; i < MAX_IGMP; i++) {
-                       uint32_t group = igmptable[i].group.s_addr;
-                       if ((group == 0) || (group == igmp->group.s_addr)) {
-                               unsigned long time;
-                               time = currticks() + rfc1112_sleep_interval(interval, 0);
-                               if (time < igmptable[i].time) {
-                                       igmptable[i].time = time;
-                               }
-                       }
-               }
-       }
-       if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
-               (ip->dest.s_addr == igmp->group.s_addr)) {
-#ifdef MDEBUG
-               printf("Received IGMP report for: %@\n", igmp->group.s_addr);
-#endif                        
-               for(i = 0; i < MAX_IGMP; i++) {
-                       if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
-                               igmptable[i].time != 0) {
-                               igmptable[i].time = 0;
-                       }
-               }
-       }
-}
-
-void leave_group(int slot)
-{
-       /* Be very stupid and always send a leave group message if 
-        * I have subscribed.  Imperfect but it is standards
-        * compliant, easy and reliable to implement.
-        *
-        * The optimal group leave method is to only send leave when,
-        * we were the last host to respond to a query on this group,
-        * and igmpv1 compatibility is not enabled.
-        */
-       if (igmptable[slot].group.s_addr) {
-               struct igmp_ip_t igmp;
-               igmp.router_alert[0] = 0x94;
-               igmp.router_alert[1] = 0x04;
-               igmp.router_alert[2] = 0;
-               igmp.router_alert[3] = 0;
-               build_ip_hdr(htonl(GROUP_ALL_HOSTS),
-                       1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
-               igmp.igmp.type = IGMP_LEAVE;
-               igmp.igmp.response_time = 0;
-               igmp.igmp.chksum = 0;
-               igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
-               igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
-               ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
-               printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
-#endif 
-       }
-       memset(&igmptable[slot], 0, sizeof(igmptable[0]));
-}
-
-void join_group(int slot, unsigned long group)
-{
-       /* I have already joined */
-       if (igmptable[slot].group.s_addr == group)
-               return;
-       if (igmptable[slot].group.s_addr) {
-               leave_group(slot);
-       }
-       /* Only join a group if we are given a multicast ip, this way
-        * code can be given a non-multicast (broadcast or unicast ip)
-        * and still work... 
-        */
-       if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
-               igmptable[slot].group.s_addr = group;
-               igmptable[slot].time = currticks();
-       }
-}
-#else
-#define send_igmp_reports(now) do {} while(0)
-#define process_igmp(ip, now)  do {} while(0)
-#endif
 
 #include "proto_eth_slow.c"
 
@@ -985,8 +871,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
         */
        for (;;) {
                now = currticks();
+               background_send(now);
                send_eth_slow_reports(now);
-               send_igmp_reports(now);
                result = eth_poll(1);
                if (result == 0) {
                        /* We don't have anything */
@@ -1104,8 +990,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
 #endif /* MDEBUG */
                        }
                }
+               background_process(now, ptype, ip);
                process_eth_slow(ptype, now);
-               process_igmp(ip, now);
        }
        return(0);
 }
@@ -1168,6 +1054,8 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
 #else
                vendorext_isvalid = 0;
 #endif
+               addparam = NULL;
+               addparamlen = 0;
                if (memcmp(p, rfc1533_cookie, 4))
                        return(0); /* no RFC 1533 header found */
                p += 4;
@@ -1178,7 +1066,7 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
                                return(0); /* no RFC 1533 header found */
                        p += 4;
                        len -= 4; }
-               if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) {
+               if (extend + len <= (unsigned char *)&(bootp_data.bootp_extension[MAX_BOOTP_EXTLEN])) {
                        memcpy(extend, p, len);
                        extend += len;
                } else {
@@ -1235,6 +1123,17 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
                          p[6] == RFC1533_VENDOR_MAJOR
                        )
                        vendorext_isvalid++;
+               else if (c == RFC1533_VENDOR_ADDPARM) {
+                       /* This tag intentionally works for BOTH the encapsulated and
+                        * non-encapsulated case, since the current menu code (in mknbi)
+                        * creates this tag without encapsulation.  In the future both the
+                        * menu from mknbi and this code should learn about the proper
+                        * encapsulation (which will require substantial changes to various
+                        * stuff from mknbi, which will break compatibility with older
+                        * versions of Etherboot).  */
+                       addparam = p + 2;
+                       addparamlen = *(p + 1);
+               }
                else if (NON_ENCAP_OPT c == RFC1533_VENDOR_ETHERBOOT_ENCAP) {
                        in_encapsulated_options = 1;
                        decode_rfc1533(p+2, 0, TAG_LEN(p), -1);
@@ -1289,28 +1188,10 @@ RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1
 long rfc2131_sleep_interval(long base, int exp)
 {
        unsigned long tmo;
-#ifdef BACKOFF_LIMIT
        if (exp > BACKOFF_LIMIT)
                exp = BACKOFF_LIMIT;
-#endif
        tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
        return tmo;
 }
 
-#ifdef MULTICAST_LEVEL2
-/**************************************************************************
-RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
-**************************************************************************/
-long rfc1112_sleep_interval(long base, int exp)
-{
-       unsigned long divisor, tmo;
-#ifdef BACKOFF_LIMIT
-       if (exp > BACKOFF_LIMIT)
-               exp = BACKOFF_LIMIT;
-#endif
-       divisor = RAND_MAX/(base << exp);
-       tmo = random()/divisor;
-       return tmo;
-}
-#endif /* MULTICAST_LEVEL_2 */