public static byte [] generate() {
    // create ethernet header
    byte [] packet = HeaderGenerator.generateRandomEthernetHeader();
    int eProto = 
      ArrayHelper.extractInteger(packet, ETH_CODE_POS, ETH_CODE_LEN);

    // figure out what type of packet should be encapsulated after the 
    // newly generated ethernet header.
    switch(eProto) {
    case EthernetProtocols.IP: // encapsulate IP
      byte [] ipHeader = HeaderGenerator.generateRandomIPHeader();
      packet = ArrayHelper.join(packet, ipHeader);

      // figure out what type of protocol should be encapsulated after the 
      // newly generated IP header.
      int ipProto = 
        ArrayHelper.extractInteger(ipHeader, IP_CODE_POS, IP_CODE_LEN);
      switch(ipProto) {
      case IPProtocols.UDP: // encapsulate UDP inside IP
        byte [] udpHeader = HeaderGenerator.generateRandomUDPHeader();
        packet = ArrayHelper.join(packet, udpHeader);
        break;
      case IPProtocols.ICMP: // encapsulate ICMP inside IP
        byte [] icmpHeader = HeaderGenerator.generateRandomICMPHeader();
        packet = ArrayHelper.join(packet, icmpHeader);
        break;
      case IPProtocols.TCP: // encapsulate TCP inside IP
        byte [] tcpHeader = HeaderGenerator.generateRandomTCPHeader();
        packet = ArrayHelper.join(packet, tcpHeader);
        break;
      default: 
        // if the IP protocol isn't known, leave the data payload empty
        break;
      }
      break;
    case EthernetProtocols.ARP:
      byte [] arpHeader = HeaderGenerator.generateRandomARPHeader();
      packet = ArrayHelper.join(packet, arpHeader);
      break;
    default:
      // if the ethernet protocol isn't known, leave the data payload empty
      break;
    }

    return packet;
  }