]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
Add unit tests for DHCP
authorErik Ekman <erik@kryo.se>
Thu, 22 Mar 2012 09:52:05 +0000 (10:52 +0100)
committergoldsimon <goldsimon@gmx.de>
Sun, 25 Mar 2012 13:34:31 +0000 (15:34 +0200)
Three simple tests that test the basic functionality of the DHCP client.
They require that UDP checksums are off for now.

test/unit/dhcp/test_dhcp.c [new file with mode: 0644]
test/unit/dhcp/test_dhcp.h [new file with mode: 0644]
test/unit/lwip_unittests.c
test/unit/lwipopts.h

diff --git a/test/unit/dhcp/test_dhcp.c b/test/unit/dhcp/test_dhcp.c
new file mode 100644 (file)
index 0000000..ae0ad07
--- /dev/null
@@ -0,0 +1,789 @@
+#include "test_dhcp.h"
+
+#include "lwip/netif.h"
+#include "lwip/dhcp.h"
+#include "netif/etharp.h"
+
+struct netif net_test;
+
+static u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+static u8_t magic_cookie[] = { 0x63, 0x82, 0x53, 0x63 };
+
+static u8_t dhcp_offer[] = {
+    0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // To unit
+    0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, // From Remote host
+    0x08, 0x00, // Protocol: IP
+    0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, // IP header
+    0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x6a, 0xa9, // UDP header
+
+    0x02, // Type == Boot reply
+    0x01, 0x06, // Hw Ethernet, 6 bytes addrlen
+    0x00, // 0 hops
+    0xAA, 0xAA, 0xAA, 0xAA, // Transaction id, will be overwritten
+    0x00, 0x00, // 0 seconds elapsed
+    0x00, 0x00, // Flags (unicast)
+    0x00, 0x00, 0x00, 0x00, // Client ip
+    0xc3, 0xaa, 0xbd, 0xc8, // Your IP
+    0xc3, 0xaa, 0xbd, 0xab, // DHCP server ip
+    0x00, 0x00, 0x00, 0x00, // relay agent
+    0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MAC addr + padding
+
+    // Empty server name and boot file name
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+
+    0x63, 0x82, 0x53, 0x63, // Magic cookie
+    0x35, 0x01, 0x02, // Message type: Offer
+    0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Server identifier (IP)
+    0x33, 0x04, 0x00, 0x00, 0x00, 0x78, // Lease time 2 minutes
+    0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Router IP
+    0x01, 0x04, 0xff, 0xff, 0xff, 0x00, // Subnet mask
+    0xff, // End option
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Padding
+};
+
+static u8_t dhcp_ack[] = {
+    0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // To unit
+    0x00, 0x0f, 0xEE, 0x30, 0xAB, 0x22, // From remote host
+    0x08, 0x00, // Proto IP
+    0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, // IP header
+    0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x67, 0xa8, // UDP header
+    0x02, // Bootp reply
+    0x01, 0x06, // Hw type Eth, len 6
+    0x00, // 0 hops
+    0xAA, 0xAA, 0xAA, 0xAA,
+    0x00, 0x00, // 0 seconds elapsed
+    0x00, 0x00, // Flags (unicast)
+    0x00, 0x00, 0x00, 0x00, // Client IP
+    0xc3, 0xaa, 0xbd, 0xc8, // Your IP
+    0xc3, 0xaa, 0xbd, 0xab, // DHCP server IP
+    0x00, 0x00, 0x00, 0x00, // Relay agent
+    0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Macaddr + padding
+
+    // Empty server name and boot file name
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+
+    0x63, 0x82, 0x53, 0x63, // Magic cookie
+    0x35, 0x01, 0x05, // Dhcp message type ack
+    0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // DHCP server identifier
+    0x33, 0x04, 0x00, 0x00, 0x00, 0x78, // Lease time 2 minutes
+    0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, // Router IP
+    0x01, 0x04, 0xff, 0xff, 0xff, 0x00, // Netmask
+    0xff, // End marker
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Padding
+};
+
+static u8_t arpreply[] = {
+    0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, // dst mac
+    0x00, 0x32, 0x44, 0x20, 0x01, 0x02, // src mac
+    0x08, 0x06, // proto arp
+    0x00, 0x01, // hw eth
+    0x08, 0x00, // proto ip
+    0x06, // hw addr len 6
+    0x04, // proto addr len 4
+    0x00, 0x02, // arp reply
+    0x00, 0x32, 0x44, 0x20, 0x01, 0x02, // sender mac
+    0xc3, 0xaa, 0xbd, 0xc8, // sender ip
+    0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, // target mac
+    0x00, 0x00, 0x00, 0x00, // target ip
+};
+
+static int txpacket;
+static enum tcase {
+  TEST_LWIP_DHCP,
+  TEST_LWIP_DHCP_NAK,
+  TEST_LWIP_DHCP_RELAY,
+} tcase;
+
+static int debug = 0;
+static void setdebug(int a) {debug = a;}
+
+static int tick = 0;
+static void tick_lwip()
+{
+  tick++;
+  if (tick % 5 == 0) {
+    dhcp_fine_tmr();
+  }
+  if (tick % 600 == 0) {
+    dhcp_coarse_tmr();
+  }
+}
+
+static void send_pkt(struct netif *netif, u8_t *data, u32_t len)
+{
+  struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+  struct pbuf *q;
+
+  if (debug) {
+    // Dump data
+    u32_t i;
+    printf("RX data (len %d)", p->tot_len);
+    for (i = 0; i < len; i++) {
+      printf(" %02X", data[i]);
+    }
+    printf("\n");
+  }
+
+  fail_unless(p != NULL);
+  for(q = p; q != NULL; q = q->next) {
+    memcpy(q->payload, data, q->len);
+    data += q->len;
+  }
+  netif->input(p, netif);
+}
+
+static err_t lwip_tx_func(struct netif *netif, struct pbuf *p);
+
+static err_t testif_init(struct netif *netif)
+{
+  netif->name[0] = 'c';
+  netif->name[1] = 'h';
+  netif->output = etharp_output;
+  netif->linkoutput = lwip_tx_func;
+  netif->mtu = 1500;
+  netif->hwaddr_len = 6;
+  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
+
+  netif->hwaddr[0] = 0x00;
+  netif->hwaddr[1] = 0x23;
+  netif->hwaddr[2] = 0xC1;
+  netif->hwaddr[3] = 0xDE;
+  netif->hwaddr[4] = 0xD0;
+  netif->hwaddr[5] = 0x0D;
+
+  return ERR_OK;
+}
+
+static void dhcp_setup()
+{
+  txpacket = 0;
+}
+
+static void dhcp_teardown()
+{
+}
+
+static void check_pkt(struct pbuf *p, u32_t pos, u8_t *mem, u32_t len)
+{
+  fail_if((pos + len) > p->tot_len);
+  while (pos > p->len && p->next) {
+    pos -= p->len;
+    p = p->next;
+  }
+  fail_if(p == NULL);
+  fail_unless(pos + len <= p->len); // All data we seek within same pbuf
+
+  u8_t *data = p->payload;
+  fail_if(memcmp(&data[pos], mem, len), "data at pos %d, len %d in packet %d did not match", pos, len, txpacket);
+}
+
+static void check_pkt_fuzzy(struct pbuf *p, u32_t startpos, u8_t *mem, u32_t len)
+{
+  fail_if((startpos + len) > p->tot_len);
+  while (startpos > p->len && p->next) {
+    startpos -= p->len;
+    p = p->next;
+  }
+  fail_if(p == NULL);
+  fail_unless(startpos + len <= p->len); // All data we seek within same pbuf
+
+  int found = 0;
+  u32_t i;
+  u8_t *data = p->payload;
+  for (i = startpos; i <= (p->len - len); i++) {
+    if (memcmp(&data[i], mem, len) == 0) {
+      found = 1;
+      break;
+    }
+  }
+  fail_unless(found);
+}
+
+static err_t lwip_tx_func(struct netif *netif, struct pbuf *p)
+{
+  fail_unless(netif == &net_test);
+  txpacket++;
+
+  if (debug) {
+    // Dump data
+    printf("TX data (pkt %d, len %d, tick %d)", txpacket, p->tot_len, tick);
+    struct pbuf *pp = p;
+    do {
+      int i;
+      for (i = 0; i < pp->len; i++) {
+        printf(" %02X", ((u8_t *) pp->payload)[i]);
+      }
+      if (pp->next) {
+        pp = pp->next;
+      }
+    } while (pp->next);
+    printf("\n");
+  }
+
+  switch (tcase) {
+  case TEST_LWIP_DHCP:
+    switch (txpacket) {
+    case 1:
+    case 2:
+      {
+        check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast
+        check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+        u8_t ipproto[] = { 0x08, 0x00 };
+        check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip
+
+        u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops
+        check_pkt(p, 42, bootp_start, sizeof(bootp_start));
+
+        u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+        check_pkt(p, 53, ipaddrs, sizeof(ipaddrs));
+
+        check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp
+
+        check_pkt(p, 278, magic_cookie, sizeof(magic_cookie));
+
+        // Check dchp message type, can be at different positions
+        if (txpacket == 1) {
+          u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 };
+          check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt));
+        } else if (txpacket == 2) {
+          u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 };
+          check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt));
+
+          u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; // Ask for offered IP
+          check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr));
+        }
+        break;
+      }
+    case 3:
+    case 4:
+    case 5:
+      {
+        check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast
+        check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+        u8_t arpproto[] = { 0x08, 0x06 };
+        check_pkt(p, 12, arpproto, sizeof(arpproto)); // eth level proto: ip
+        break;
+      }
+    }
+    break;
+
+  case TEST_LWIP_DHCP_NAK:
+    {
+      fail_unless(txpacket == 4);
+      check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast
+      check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+      u8_t ipproto[] = { 0x08, 0x00 };
+      check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip
+
+      u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops
+      check_pkt(p, 42, bootp_start, sizeof(bootp_start));
+
+      u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+      check_pkt(p, 53, ipaddrs, sizeof(ipaddrs));
+
+      check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp
+
+      check_pkt(p, 278, magic_cookie, sizeof(magic_cookie));
+
+      u8_t dhcp_nak_opt[] = { 0x35, 0x01, 0x04 };
+      check_pkt_fuzzy(p, 282, dhcp_nak_opt, sizeof(dhcp_nak_opt)); // NAK the ack
+
+      u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; // offered IP
+      check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr));
+      break;
+    }
+
+  case TEST_LWIP_DHCP_RELAY:
+    switch (txpacket) {
+    case 1:
+    case 2:
+      {
+        check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast
+        check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+        u8_t ipproto[] = { 0x08, 0x00 };
+        check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip
+
+        u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops
+        check_pkt(p, 42, bootp_start, sizeof(bootp_start));
+
+        u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+        check_pkt(p, 53, ipaddrs, sizeof(ipaddrs));
+
+        check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp
+
+        check_pkt(p, 278, magic_cookie, sizeof(magic_cookie));
+
+        // Check dchp message type, can be at different positions
+        if (txpacket == 1) {
+          u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 };
+          check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt));
+        } else if (txpacket == 2) {
+          u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 };
+          check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt));
+
+          u8_t requested_ipaddr[] = { 0x32, 0x04, 0x4f, 0x8a, 0x33, 0x05 }; // Ask for offered IP
+          check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr));
+        }
+        break;
+      }
+    case 3:
+    case 4:
+    case 5:
+      {
+        check_pkt(p, 0, broadcast, 6); // eth level dest: broadcast
+        check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+        u8_t arpproto[] = { 0x08, 0x06 };
+        check_pkt(p, 12, arpproto, sizeof(arpproto)); // eth level proto: ip
+        break;
+      }
+    case 6:
+      {
+        u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab };
+        check_pkt(p, 0, fake_arp, 6); // eth level dest: broadcast
+        check_pkt(p, 6, netif->hwaddr, 6); // eth level src: unit mac
+
+        u8_t ipproto[] = { 0x08, 0x00 };
+        check_pkt(p, 12, ipproto, sizeof(ipproto)); // eth level proto: ip
+
+        u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; // bootp request, eth, hwaddr len 6, 0 hops
+        check_pkt(p, 42, bootp_start, sizeof(bootp_start));
+
+        u8_t ipaddrs[] = { 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+        check_pkt(p, 53, ipaddrs, sizeof(ipaddrs));
+
+        check_pkt(p, 70, netif->hwaddr, 6); // mac addr inside bootp
+
+        check_pkt(p, 278, magic_cookie, sizeof(magic_cookie));
+
+        // Check dchp message type, can be at different positions
+        u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 };
+        check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt));
+        break;
+      }
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return ERR_OK;
+}
+
+/*
+ * Test basic happy flow DHCP session.
+ * Validate that xid is checked.
+ */
+START_TEST(test_dhcp)
+{
+  struct ip_addr addr;
+  struct ip_addr netmask;
+  struct ip_addr gw;
+  int i;
+
+  tcase = TEST_LWIP_DHCP;
+  setdebug(0);
+
+  IP4_ADDR(&addr, 0, 0, 0, 0);
+  IP4_ADDR(&netmask, 0, 0, 0, 0);
+  IP4_ADDR(&gw, 0, 0, 0, 0);
+
+  netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input);
+
+  dhcp_start(&net_test);
+
+  fail_unless(txpacket == 1); // DHCP discover sent
+  u32_t xid = net_test.dhcp->xid; // Write bad xid, not using htonl!
+  memcpy(&dhcp_offer[46], &xid, 4);
+  send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer));
+
+  // Interface down
+  fail_if(netif_is_up(&net_test));
+
+  // IP addresses should be zero
+  fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr)));
+  fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr)));
+  fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr)));
+
+  fail_unless(txpacket == 1, "TX %d packets, expected 1", txpacket); // Nothing more sent
+  xid = htonl(net_test.dhcp->xid);
+  memcpy(&dhcp_offer[46], &xid, 4); // insert correct transaction id
+  send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer));
+
+  fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); // DHCP request sent
+  xid = net_test.dhcp->xid; // Write bad xid, not using htonl!
+  memcpy(&dhcp_ack[46], &xid, 4);
+  send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack));
+
+  fail_unless(txpacket == 2, "TX %d packets, still expected 2", txpacket); // No more sent
+  xid = htonl(net_test.dhcp->xid); // xid updated
+  memcpy(&dhcp_ack[46], &xid, 4); // insert transaction id
+  send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack));
+
+  for (i = 0; i < 20; i++)
+    tick_lwip();
+  fail_unless(txpacket == 4, "TX %d packets, expected 4", txpacket); // ARP requests sent
+
+  // Interface up
+  fail_unless(netif_is_up(&net_test));
+
+  // Now it should have taken the IP
+  IP4_ADDR(&addr, 195, 170, 189, 200);
+  IP4_ADDR(&netmask, 255, 255, 255, 0);
+  IP4_ADDR(&gw, 195, 170, 189, 171);
+  fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr)));
+  fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr)));
+  fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr)));
+
+  netif_remove(&net_test);
+}
+END_TEST
+
+/*
+ * Test that IP address is not taken and NAK is sent if someone
+ * replies to ARP requests for the offered address.
+ */
+START_TEST(test_dhcp_nak)
+{
+  struct ip_addr addr;
+  struct ip_addr netmask;
+  struct ip_addr gw;
+
+  tcase = TEST_LWIP_DHCP;
+  setdebug(0);
+
+  IP4_ADDR(&addr, 0, 0, 0, 0);
+  IP4_ADDR(&netmask, 0, 0, 0, 0);
+  IP4_ADDR(&gw, 0, 0, 0, 0);
+
+  netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input);
+
+  dhcp_start(&net_test);
+
+  fail_unless(txpacket == 1); // DHCP discover sent
+  u32_t xid = net_test.dhcp->xid; // Write bad xid, not using htonl!
+  memcpy(&dhcp_offer[46], &xid, 4);
+  send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer));
+
+  // Interface down
+  fail_if(netif_is_up(&net_test));
+
+  // IP addresses should be zero
+  fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr)));
+  fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr)));
+  fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr)));
+
+  fail_unless(txpacket == 1); // Nothing more sent
+  xid = htonl(net_test.dhcp->xid);
+  memcpy(&dhcp_offer[46], &xid, 4); // insert correct transaction id
+  send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer));
+
+  fail_unless(txpacket == 2); // DHCP request sent
+  xid = net_test.dhcp->xid; // Write bad xid, not using htonl!
+  memcpy(&dhcp_ack[46], &xid, 4);
+  send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack));
+
+  fail_unless(txpacket == 2); // No more sent
+  xid = htonl(net_test.dhcp->xid); // xid updated
+  memcpy(&dhcp_ack[46], &xid, 4); // insert transaction id
+  send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack));
+
+  fail_unless(txpacket == 3); // ARP request sent
+
+  tcase = TEST_LWIP_DHCP_NAK; // Switch testcase
+
+  // Send arp reply, mark offered IP as taken
+  send_pkt(&net_test, arpreply, sizeof(arpreply));
+
+  fail_unless(txpacket == 4); // DHCP nak sent
+
+  netif_remove(&net_test);
+}
+END_TEST
+
+/*
+ * Test case based on captured data where
+ * replies are sent from a different IP than the
+ * one the client unicasted to.
+ */
+START_TEST(test_dhcp_relayed)
+{
+  u8_t relay_offer[] = {
+  0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d,
+  0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60,
+  0x08, 0x00, 0x45, 0x00,
+  0x01, 0x38, 0xfd, 0x53, 0x00, 0x00, 0x40, 0x11,
+  0x78, 0x46, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a,
+  0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24,
+  0x38, 0x72, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35,
+  0xb6, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00,
+  0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23,
+  0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82,
+  0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00,
+  0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08,
+  0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1,
+  0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04,
+  0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x02, 0x36,
+  0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff
+  };
+
+  u8_t relay_ack1[] = {
+  0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22,
+  0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00,
+  0x01, 0x38, 0xfd, 0x55, 0x00, 0x00, 0x40, 0x11,
+  0x78, 0x44, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a,
+  0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24,
+  0x35, 0x71, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35,
+  0xb6, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00,
+  0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23,
+  0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82,
+  0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00,
+  0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08,
+  0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1,
+  0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04,
+  0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x05, 0x36,
+  0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff
+  };
+
+  u8_t relay_ack2[] = {
+  0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d,
+  0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60,
+  0x08, 0x00, 0x45, 0x00,
+  0x01, 0x38, 0xfa, 0x18, 0x00, 0x00, 0x40, 0x11,
+  0x7b, 0x81, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a,
+  0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24,
+  0x02, 0x6b, 0x02, 0x01, 0x06, 0x00, 0x49, 0x8b,
+  0x6e, 0xab, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a,
+  0x33, 0x05, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00,
+  0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23,
+  0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82,
+  0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00,
+  0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08,
+  0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1,
+  0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04,
+  0x00, 0x00, 0x54, 0x60, 0x35, 0x01, 0x05, 0x36,
+  0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff };
+
+  u8_t arp_resp[] = {
+  0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, // DEST
+  0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, // SRC
+  0x08, 0x06, // Type: ARP
+  0x00, 0x01, // HW: Ethernet
+  0x08, 0x00, // PROTO: IP
+  0x06, // HW size
+  0x04, // PROTO size
+  0x00, 0x02, // OPCODE: Reply
+
+  0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, // Target MAC
+  0x4f, 0x8a, 0x32, 0x01, // Target IP
+
+  0x00, 0x23, 0xc1, 0x00, 0x06, 0x50, // src mac
+  0x4f, 0x8a, 0x33, 0x05, // src ip
+
+  // Padding follows..
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00 };
+
+  struct ip_addr addr;
+  struct ip_addr netmask;
+  struct ip_addr gw;
+  int i;
+
+  tcase = TEST_LWIP_DHCP_RELAY;
+  setdebug(0);
+
+  IP4_ADDR(&addr, 0, 0, 0, 0);
+  IP4_ADDR(&netmask, 0, 0, 0, 0);
+  IP4_ADDR(&gw, 0, 0, 0, 0);
+
+  netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input);
+
+  dhcp_start(&net_test);
+
+  fail_unless(txpacket == 1); // DHCP discover sent
+
+  // Interface down
+  fail_if(netif_is_up(&net_test));
+
+  // IP addresses should be zero
+  fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr)));
+  fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr)));
+  fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr)));
+
+  fail_unless(txpacket == 1); // Nothing more sent
+  u32_t xid = htonl(net_test.dhcp->xid);
+  memcpy(&relay_offer[46], &xid, 4); // insert correct transaction id
+  send_pkt(&net_test, relay_offer, sizeof(relay_offer));
+
+  // request sent?
+  fail_unless(txpacket == 2, "txpkt = %d, should be 2", txpacket);
+  xid = htonl(net_test.dhcp->xid); // xid updated
+  memcpy(&relay_ack1[46], &xid, 4); // insert transaction id
+  send_pkt(&net_test, relay_ack1, sizeof(relay_ack1));
+
+  for (i = 0; i < 25; i++)
+    tick_lwip();
+  fail_unless(txpacket == 4, "txpkt should be 5, is %d", txpacket); // ARP requests sent
+
+  // Interface up
+  fail_unless(netif_is_up(&net_test));
+
+  // Now it should have taken the IP
+  IP4_ADDR(&addr, 79, 138, 51, 5);
+  IP4_ADDR(&netmask, 255, 255, 254, 0);
+  IP4_ADDR(&gw, 79, 138, 50, 1);
+  fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr)));
+  fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr)));
+  fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr)));
+
+  fail_unless(txpacket == 4, "txpacket = %d", txpacket);
+
+  for (i = 0; i < 108000 - 25; i++) {
+    tick_lwip();
+  }
+
+  fail_unless(netif_is_up(&net_test));
+  fail_unless(txpacket == 5, "txpacket = %d", txpacket);
+
+  // We need to send arp response here..
+
+  send_pkt(&net_test, arp_resp, sizeof(arp_resp));
+
+  fail_unless(txpacket == 6, "txpacket = %d", txpacket);
+  fail_unless(netif_is_up(&net_test));
+
+  xid = htonl(net_test.dhcp->xid); // xid updated
+  memcpy(&relay_ack2[46], &xid, 4); // insert transaction id
+  send_pkt(&net_test, relay_ack2, sizeof(relay_ack2));
+
+  for (i = 0; i < 100000; i++) {
+    tick_lwip();
+  }
+
+  fail_unless(txpacket == 6, "txpacket = %d", txpacket);
+
+  netif_remove(&net_test);
+
+}
+END_TEST
+
+/** Create the suite including all tests for this module */
+Suite *
+dhcp_suite(void)
+{
+  TFun tests[] = {
+    test_dhcp,
+    test_dhcp_nak,
+    test_dhcp_relayed
+  };
+  return create_suite("DHCP", tests, sizeof(tests)/sizeof(TFun), dhcp_setup, dhcp_teardown);
+}
diff --git a/test/unit/dhcp/test_dhcp.h b/test/unit/dhcp/test_dhcp.h
new file mode 100644 (file)
index 0000000..aff44b7
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __TEST_DHCP_H__
+#define __TEST_DHCP_H__
+
+#include "../lwip_check.h"
+
+Suite* dhcp_suite(void);
+
+#endif
index 4f537e6688c356fcaba860c62a8cac96c39b19af..01023c1472e703623b327436eeac6cad46b3c236 100644 (file)
@@ -5,6 +5,7 @@
 #include "tcp/test_tcp_oos.h"
 #include "core/test_mem.h"
 #include "etharp/test_etharp.h"
+#include "dhcp/test_dhcp.h"
 
 #include "lwip/init.h"
 
@@ -19,7 +20,8 @@ int main()
     tcp_suite,
     tcp_oos_suite,
     mem_suite,
-    etharp_suite
+    etharp_suite,
+    dhcp_suite
   };
   size_t num = sizeof(suites)/sizeof(void*);
   LWIP_ASSERT("No suites defined", num > 0);
index 88e76d7a56c433fbd8cee82340758b5f675f91ed..f44ccf858f6292f5af3e5df677dcf3cc3babb5a4 100644 (file)
 #define LWIP_NETCONN                    0
 #define LWIP_SOCKET                     0
 
+/* Enable DHCP to test it, disable UDP checksum to easier inject packets */
+#define LWIP_DHCP                       1
+#define CHECKSUM_CHECK_UDP              0
+
 /* Minimal changes to opt.h required for tcp unit tests: */
 #define MEM_SIZE                        16000
 #define TCP_SND_QUEUELEN                40