jiahuimbzuai/CoQuIR huggingface dataset:
//  [c]
static void print_buttons(HttpRequest req, HttpResponse res, Service_T s) {
        if (is_readonly(req)) {
                 // A read-only REMOTE_USER does not get access to these buttons
                return;
        }
        StringBuffer_append(res->outputbuffer, "<table id='buttons'><tr>");
        /* Start program */
        if (s->start)
                StringBuffer_append(res->outputbuffer,
                                    "<td>"
                                    "<form method=POST action=%s>"
                                    "<input type=hidden name='securitytoken' value='%s'>"
                                    "<input type=hidden value='start' name=action>"
                                    "<input type=submit value='Start service'>"
                                    "</form>"
                                    "</td>", s->name, res->token);
        /* Stop program */
        if (s->stop)
                StringBuffer_append(res->outputbuffer,
                                    "<td>"
                                    "<form method=POST action=%s>"
                                    "<input type=hidden name='securitytoken' value='%s'>"
                                    "<input type=hidden value='stop' name=action>"
                                    "<input type=submit value='Stop service'>"
                                    "</form>"
                                    "</td>", s->name, res->token);
        /* Restart program */
        if ((s->start && s->stop) || s->restart)
                StringBuffer_append(res->outputbuffer,
                                    "<td>"
                                    "<form method=POST action=%s>"
                                    "<input type=hidden name='securitytoken' value='%s'>"
                                    "<input type=hidden value='restart' name=action>"
                                    "<input type=submit value='Restart service'>"
                                    "</form>"
                                    "</td>", s->name, res->token);
        /* (un)monitor */
        StringBuffer_append(res->outputbuffer,
                                    "<td>"
                                    "<form method=POST action=%s>"
                                    "<input type=hidden name='securitytoken' value='%s'>"
                                    "<input type=hidden value='%s' name=action>"
                                    "<input type=submit value='%s'>"
                                    "</form>"
                                    "</td>",
                                    s->name,
                                    res->token,
                                    s->monitor ? "unmonitor" : "monitor",
                                    s->monitor ? "Disable monitoring" : "Enable monitoring");
        StringBuffer_append(res->outputbuffer, "</tr></table>");
}
//  [c]
static void print_buttons(HttpRequest req, HttpResponse res, Service_T s) {
        if (is_readonly(req)) {
                 // A read-only REMOTE_USER does not get access to these buttons
                return;
        }
        StringBuffer_append(res->outputbuffer, "<table id='buttons'><tr>");
        /* Start program */
        if (s->start)
                StringBuffer_append(res->outputbuffer,
                                    "<td><form method=POST action=%s>"
                                    "<input type=hidden value='start' name=action>"
                                    "<input type=submit value='Start service'></form></td>", s->name);
        /* Stop program */
        if (s->stop)
                StringBuffer_append(res->outputbuffer,
                                    "<td><form method=POST action=%s>"
                                    "<input type=hidden value='stop' name=action>"
                                    "<input type=submit value='Stop service'></form></td>", s->name);
        /* Restart program */
        if ((s->start && s->stop) || s->restart)
                StringBuffer_append(res->outputbuffer,
                                    "<td><form method=POST action=%s>"
                                    "<input type=hidden value='restart' name=action>"
                                    "<input type=submit value='Restart service'></form></td>", s->name);
        /* (un)monitor */
        StringBuffer_append(res->outputbuffer,
                            "<td><form method=POST action=%s>"
                            "<input type=hidden value='%s' name=action>"
                            "<input type=submit value='%s'></form></td></tr></table>",
                            s->name,
                            s->monitor ? "unmonitor" : "monitor",
                            s->monitor ? "Disable monitoring" : "Enable monitoring");
}
//  [c]
void enc624j600EventHandler(NetInterface *interface)
{
   error_t error;
   uint16_t status;
   uint16_t value;

   //Read interrupt status register
   status = enc624j600ReadReg(interface, ENC624J600_EIR);

   //Check whether the link state has changed
   if((status & ENC624J600_EIR_LINKIF) != 0)
   {
      //Clear interrupt flag
      enc624j600ClearBit(interface, ENC624J600_EIR, ENC624J600_EIR_LINKIF);
      //Read Ethernet status register
      value = enc624j600ReadReg(interface, ENC624J600_ESTAT);

      //Check link state
      if((value & ENC624J600_ESTAT_PHYLNK) != 0)
      {
         //Read PHY status register 3
         value = enc624j600ReadPhyReg(interface, ENC624J600_PHSTAT3);

         //Get current speed
         if((value & ENC624J600_PHSTAT3_SPDDPX1) != 0)
         {
            interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
         }
         else
         {
            interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
         }

         //Determine the new duplex mode
         if((value & ENC624J600_PHSTAT3_SPDDPX2) != 0)
         {
            interface->duplexMode = NIC_FULL_DUPLEX_MODE;
         }
         else
         {
            interface->duplexMode = NIC_HALF_DUPLEX_MODE;
         }

         //Link is up
         interface->linkState = TRUE;

         //Update MAC configuration parameters for proper operation
         enc624j600UpdateMacConfig(interface);
      }
      else
      {
         //Link is down
         interface->linkState = FALSE;
      }

      //Process link state change event
      nicNotifyLinkChange(interface);
   }

   //Check whether a packet has been received?
   if((status & ENC624J600_EIR_PKTIF) != 0)
   {
      //Clear interrupt flag
      enc624j600ClearBit(interface, ENC624J600_EIR, ENC624J600_EIR_PKTIF);

      //Process all pending packets
      do
      {
         //Read incoming packet
         error = enc624j600ReceivePacket(interface);

         //No more data in the receive buffer?
      } while(error != ERROR_BUFFER_EMPTY);
   }

   //Re-enable LINKIE and PKTIE interrupts
   enc624j600SetBit(interface, ENC624J600_EIE, ENC624J600_EIE_LINKIE |
      ENC624J600_EIE_PKTIE);
}
//  [c]
void enc624j600EventHandler(NetInterface *interface)
{
   error_t error;
   uint16_t status;
   uint16_t value;

   //Read interrupt status register
   status = enc624j600ReadReg(interface, ENC624J600_REG_EIR);

   //Check whether the link state has changed
   if((status & EIR_LINKIF) != 0)
   {
      //Clear interrupt flag
      enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_LINKIF);
      //Read Ethernet status register
      value = enc624j600ReadReg(interface, ENC624J600_REG_ESTAT);

      //Check link state
      if((value & ESTAT_PHYLNK) != 0)
      {
         //Read PHY status register 3
         value = enc624j600ReadPhyReg(interface, ENC624J600_PHY_REG_PHSTAT3);

         //Get current speed
         if((value & PHSTAT3_SPDDPX1) != 0)
         {
            interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
         }
         else
         {
            interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
         }

         //Determine the new duplex mode
         if((value & PHSTAT3_SPDDPX2) != 0)
         {
            interface->duplexMode = NIC_FULL_DUPLEX_MODE;
         }
         else
         {
            interface->duplexMode = NIC_HALF_DUPLEX_MODE;
         }

         //Link is up
         interface->linkState = TRUE;

         //Update MAC configuration parameters for proper operation
         enc624j600UpdateMacConfig(interface);
      }
      else
      {
         //Link is down
         interface->linkState = FALSE;
      }

      //Process link state change event
      nicNotifyLinkChange(interface);
   }

   //Check whether a packet has been received?
   if((status & EIR_PKTIF) != 0)
   {
      //Clear interrupt flag
      enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_PKTIF);

      //Process all pending packets
      do
      {
         //Read incoming packet
         error = enc624j600ReceivePacket(interface);

         //No more data in the receive buffer?
      } while(error != ERROR_BUFFER_EMPTY);
   }

   //Re-enable LINKIE and PKTIE interrupts
   enc624j600SetBit(interface, ENC624J600_REG_EIE, EIE_LINKIE | EIE_PKTIE);
}
//  [c]
uint16_t enc624j600ReadPhyReg(NetInterface *interface, uint8_t address)
{
   uint16_t status;

   //Write the address of the PHY register to read from
   enc624j600WriteReg(interface, ENC624J600_MIREGADR,
      ENC624J600_MIREGADR_R12_8_DEFAULT | address);

   //Start read operation
   enc624j600WriteReg(interface, ENC624J600_MICMD, ENC624J600_MICMD_MIIRD);

   //Wait at least 25.6us before polling the BUSY bit
   usleep(100);

   //Wait for the read operation to complete
   do
   {
      //Read MII Management Status register
      status = enc624j600ReadReg(interface, ENC624J600_MISTAT);
      //Check the value of the busy status bit
   } while((status & ENC624J600_MISTAT_BUSY) != 0);

   //Clear command register
   enc624j600WriteReg(interface, ENC624J600_MICMD, 0x00);

   //Return register contents
   return enc624j600ReadReg(interface, ENC624J600_MIRD);
}
//  [c]
uint16_t enc624j600ReadPhyReg(NetInterface *interface, uint8_t address)
{
   //Write the address of the PHY register to read from
   enc624j600WriteReg(interface, ENC624J600_REG_MIREGADR, MIREGADR_R8 | address);
   //Start read operation
   enc624j600WriteReg(interface, ENC624J600_REG_MICMD, MICMD_MIIRD);

   //Wait at least 25.6us before polling the BUSY bit
   usleep(100);
   //Wait for the read operation to complete
   while((enc624j600ReadReg(interface, ENC624J600_REG_MISTAT) & MISTAT_BUSY) != 0)
   {
   }

   //Clear command register
   enc624j600WriteReg(interface, ENC624J600_REG_MICMD, 0x00);

   //Return register contents
   return enc624j600ReadReg(interface, ENC624J600_REG_MIRD);
}
//  [c]
bool_t enc624j600IrqHandler(NetInterface *interface)
{
   bool_t flag;
   uint16_t status;

   //This flag will be set if a higher priority task must be woken
   flag = FALSE;

   //Clear the INTIE bit, immediately after an interrupt event
   enc624j600ClearBit(interface, ENC624J600_EIE, ENC624J600_EIE_INTIE);

   //Read interrupt status register
   status = enc624j600ReadReg(interface, ENC624J600_EIR);

   //Link status change?
   if((status & ENC624J600_EIR_LINKIF) != 0)
   {
      //Disable LINKIE interrupt
      enc624j600ClearBit(interface, ENC624J600_EIE, ENC624J600_EIE_LINKIE);

      //Set event flag
      interface->nicEvent = TRUE;
      //Notify the TCP/IP stack of the event
      flag |= osSetEventFromIsr(&netEvent);
   }

   //Packet received?
   if((status & ENC624J600_EIR_PKTIF) != 0)
   {
      //Disable PKTIE interrupt
      enc624j600ClearBit(interface, ENC624J600_EIE, ENC624J600_EIE_PKTIE);

      //Set event flag
      interface->nicEvent = TRUE;
      //Notify the TCP/IP stack of the event
      flag |= osSetEventFromIsr(&netEvent);
   }

   //Packet transmission complete?
   if((status & (ENC624J600_EIR_TXIF | ENC624J600_EIR_TXABTIF)) != 0)
   {
      //Clear interrupt flags
      enc624j600ClearBit(interface, ENC624J600_EIR, ENC624J600_EIR_TXIF |
         ENC624J600_EIR_TXABTIF);

      //Notify the TCP/IP stack that the transmitter is ready to send
      flag |= osSetEventFromIsr(&interface->nicTxEvent);
   }

   //Once the interrupt has been serviced, the INTIE bit
   //is set again to re-enable interrupts
   enc624j600SetBit(interface, ENC624J600_EIE, ENC624J600_EIE_INTIE);

   //A higher priority task must be woken?
   return flag;
}
//  [c]
bool_t enc624j600IrqHandler(NetInterface *interface)
{
   bool_t flag;
   uint16_t status;

   //This flag will be set if a higher priority task must be woken
   flag = FALSE;

   //Clear the INTIE bit, immediately after an interrupt event
   enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_INTIE);

   //Read interrupt status register
   status = enc624j600ReadReg(interface, ENC624J600_REG_EIR);

   //Link status change?
   if((status & EIR_LINKIF) != 0)
   {
      //Disable LINKIE interrupt
      enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_LINKIE);

      //Set event flag
      interface->nicEvent = TRUE;
      //Notify the TCP/IP stack of the event
      flag |= osSetEventFromIsr(&netEvent);
   }

   //Packet received?
   if((status & EIR_PKTIF) != 0)
   {
      //Disable PKTIE interrupt
      enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_PKTIE);

      //Set event flag
      interface->nicEvent = TRUE;
      //Notify the TCP/IP stack of the event
      flag |= osSetEventFromIsr(&netEvent);
   }

   //Packet transmission complete?
   if((status & (EIR_TXIF | EIR_TXABTIF)) != 0)
   {
      //Clear interrupt flags
      enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_TXIF | EIR_TXABTIF);

      //Notify the TCP/IP stack that the transmitter is ready to send
      flag |= osSetEventFromIsr(&interface->nicTxEvent);
   }

   //Once the interrupt has been serviced, the INTIE bit
   //is set again to re-enable interrupts
   enc624j600SetBit(interface, ENC624J600_REG_EIE, EIE_INTIE);

   //A higher priority task must be woken?
   return flag;
}
//  [c]
error_t enc624j600UpdateMacAddrFilter(NetInterface *interface)
{
   uint_t i;
   uint_t k;
   uint32_t crc;
   uint16_t hashTable[4];
   MacFilterEntry *entry;

   //Debug message
   TRACE_DEBUG("Updating MAC filter...\r\n");

   //Clear hash table
   osMemset(hashTable, 0, sizeof(hashTable));

   //The MAC address filter contains the list of MAC addresses to accept
   //when receiving an Ethernet frame
   for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
   {
      //Point to the current entry
      entry = &interface->macAddrFilter[i];

      //Valid entry?
      if(entry->refCount > 0)
      {
         //Compute CRC over the current MAC address
         crc = enc624j600CalcCrc(&entry->addr, sizeof(MacAddr));
         //Calculate the corresponding index in the table
         k = (crc >> 23) & 0x3F;
         //Update hash table contents
         hashTable[k / 16] |= (1 << (k % 16));
      }
   }

   //Write the hash table to the ENC624J600 controller
   enc624j600WriteReg(interface, ENC624J600_EHT1, hashTable[0]);
   enc624j600WriteReg(interface, ENC624J600_EHT2, hashTable[1]);
   enc624j600WriteReg(interface, ENC624J600_EHT3, hashTable[2]);
   enc624j600WriteReg(interface, ENC624J600_EHT4, hashTable[3]);

   //Debug message
   TRACE_DEBUG("  EHT1 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_EHT1));
   TRACE_DEBUG("  EHT2 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_EHT2));
   TRACE_DEBUG("  EHT3 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_EHT3));
   TRACE_DEBUG("  EHT4 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_EHT4));

   //Successful processing
   return NO_ERROR;
}
//  [c]
error_t enc624j600UpdateMacAddrFilter(NetInterface *interface)
{
   uint_t i;
   uint_t k;
   uint32_t crc;
   uint16_t hashTable[4];
   MacFilterEntry *entry;

   //Debug message
   TRACE_DEBUG("Updating MAC filter...\r\n");

   //Clear hash table
   osMemset(hashTable, 0, sizeof(hashTable));

   //The MAC address filter contains the list of MAC addresses to accept
   //when receiving an Ethernet frame
   for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
   {
      //Point to the current entry
      entry = &interface->macAddrFilter[i];

      //Valid entry?
      if(entry->refCount > 0)
      {
         //Compute CRC over the current MAC address
         crc = enc624j600CalcCrc(&entry->addr, sizeof(MacAddr));
         //Calculate the corresponding index in the table
         k = (crc >> 23) & 0x3F;
         //Update hash table contents
         hashTable[k / 16] |= (1 << (k % 16));
      }
   }

   //Write the hash table to the ENC624J600 controller
   enc624j600WriteReg(interface, ENC624J600_REG_EHT1, hashTable[0]);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT2, hashTable[1]);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT3, hashTable[2]);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT4, hashTable[3]);

   //Debug message
   TRACE_DEBUG("  EHT1 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT1));
   TRACE_DEBUG("  EHT2 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT2));
   TRACE_DEBUG("  EHT3 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT3));
   TRACE_DEBUG("  EHT4 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT4));

   //Successful processing
   return NO_ERROR;
}
//  [c]
error_t enc624j600SendPacket(NetInterface *interface,
   const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
{
   size_t length;

   //Retrieve the length of the packet
   length = netBufferGetLength(buffer) - offset;

   //Check the frame length
   if(length > 1536)
   {
      //The transmitter can accept another packet
      osSetEvent(&interface->nicTxEvent);
      //Report an error
      return ERROR_INVALID_LENGTH;
   }

   //Make sure the link is up before transmitting the frame
   if(!interface->linkState)
   {
      //The transmitter can accept another packet
      osSetEvent(&interface->nicTxEvent);
      //Drop current packet
      return NO_ERROR;
   }

   //Ensure that the transmitter is ready to send
   if(enc624j600ReadReg(interface, ENC624J600_ECON1) & ENC624J600_ECON1_TXRTS)
   {
      return ERROR_FAILURE;
   }

   //Point to the SRAM buffer
   enc624j600WriteReg(interface, ENC624J600_EGPWRPT, ENC624J600_TX_BUFFER_START);
   //Copy the packet to the SRAM buffer
   enc624j600WriteBuffer(interface, ENC624J600_CMD_WGPDATA, buffer, offset);

   //Program ETXST to the start address of the packet
   enc624j600WriteReg(interface, ENC624J600_ETXST, ENC624J600_TX_BUFFER_START);
   //Program ETXLEN with the length of data copied to the memory
   enc624j600WriteReg(interface, ENC624J600_ETXLEN, length);

   //Clear TXIF and TXABTIF interrupt flags
   enc624j600ClearBit(interface, ENC624J600_EIR, ENC624J600_EIR_TXIF |
      ENC624J600_EIR_TXABTIF);

   //Set the TXRTS bit to initiate transmission
   enc624j600SetBit(interface, ENC624J600_ECON1, ENC624J600_ECON1_TXRTS);

   //Successful processing
   return NO_ERROR;
}
//  [c]
error_t enc624j600SendPacket(NetInterface *interface,
   const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
{
   size_t length;

   //Retrieve the length of the packet
   length = netBufferGetLength(buffer) - offset;

   //Check the frame length
   if(length > 1536)
   {
      //The transmitter can accept another packet
      osSetEvent(&interface->nicTxEvent);
      //Report an error
      return ERROR_INVALID_LENGTH;
   }

   //Make sure the link is up before transmitting the frame
   if(!interface->linkState)
   {
      //The transmitter can accept another packet
      osSetEvent(&interface->nicTxEvent);
      //Drop current packet
      return NO_ERROR;
   }

   //Ensure that the transmitter is ready to send
   if(enc624j600ReadReg(interface, ENC624J600_REG_ECON1) & ECON1_TXRTS)
   {
      return ERROR_FAILURE;
   }

   //Point to the SRAM buffer
   enc624j600WriteReg(interface, ENC624J600_REG_EGPWRPT, ENC624J600_TX_BUFFER_START);
   //Copy the packet to the SRAM buffer
   enc624j600WriteBuffer(interface, ENC624J600_CMD_WGPDATA, buffer, offset);

   //Program ETXST to the start address of the packet
   enc624j600WriteReg(interface, ENC624J600_REG_ETXST, ENC624J600_TX_BUFFER_START);
   //Program ETXLEN with the length of data copied to the memory
   enc624j600WriteReg(interface, ENC624J600_REG_ETXLEN, length);

   //Clear TXIF and TXABTIF interrupt flags
   enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_TXIF | EIR_TXABTIF);
   //Set the TXRTS bit to initiate transmission
   enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_TXRTS);

   //Successful processing
   return NO_ERROR;
}
//  [c]
error_t enc624j600ReceivePacket(NetInterface *interface)
{
   error_t error;
   uint16_t length;
   uint32_t status;
   uint8_t header[8];
   Enc624j600Context *context;

   //Point to the driver context
   context = (Enc624j600Context *) interface->nicContext;

   //Verify that a packet is waiting by ensuring that PKTCNT is non-zero
   if(enc624j600ReadReg(interface, ENC624J600_ESTAT) & ENC624J600_ESTAT_PKTCNT)
   {
      //Point to the next packet
      enc624j600WriteReg(interface, ENC624J600_ERXRDPT, context->nextPacket);

      //The packet is preceded by a 8-byte header
      enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA, header, sizeof(header));

      //The first two bytes are the address of the next packet
      context->nextPacket = LOAD16LE(header);
      //Get the length of the received packet
      length = LOAD16LE(header + 2);
      //Get the receive status vector (RSV)
      status = LOAD32LE(header + 4);

      //Make sure no error occurred
      if((status & ENC624J600_RSV_RECEIVED_OK) != 0)
      {
         //Limit the number of data to read
         length = MIN(length, ETH_MAX_FRAME_SIZE);

         //Read the Ethernet frame
         enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
            context->rxBuffer, length);

         //Valid packet received
         error = NO_ERROR;
      }
      else
      {
         //The received packet contains an error
         error = ERROR_INVALID_PACKET;
      }

      //Update the ERXTAIL pointer value to the point where the packet
      //has been processed, taking care to wrap back at the end of the
      //received memory buffer
      if(context->nextPacket == ENC624J600_RX_BUFFER_START)
      {
         enc624j600WriteReg(interface, ENC624J600_ERXTAIL,
            ENC624J600_RX_BUFFER_STOP);
      }
      else
      {
         enc624j600WriteReg(interface, ENC624J600_ERXTAIL,
            context->nextPacket - 2);
      }

      //Set PKTDEC to decrement the PKTCNT bits
      enc624j600SetBit(interface, ENC624J600_ECON1, ENC624J600_ECON1_PKTDEC);
   }
   else
   {
      //No more data in the receive buffer
      error = ERROR_BUFFER_EMPTY;
   }

   //Check whether a valid packet has been received
   if(!error)
   {
      NetRxAncillary ancillary;

      //Additional options can be passed to the stack along with the packet
      ancillary = NET_DEFAULT_RX_ANCILLARY;

      //Pass the packet to the upper layer
      nicProcessPacket(interface, context->rxBuffer, length, &ancillary);
   }

   //Return status code
   return error;
}
//  [c]
error_t enc624j600ReceivePacket(NetInterface *interface)
{
   error_t error;
   uint16_t n;
   uint32_t status;
   Enc624j600Context *context;

   //Point to the driver context
   context = (Enc624j600Context *) interface->nicContext;

   //Verify that a packet is waiting by ensuring that PKTCNT is non-zero
   if(enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_PKTCNT)
   {
      //Point to the next packet
      enc624j600WriteReg(interface, ENC624J600_REG_ERXRDPT, context->nextPacket);

      //Read the first two bytes, which are the address of the next packet
      enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
         (uint8_t *) &context->nextPacket, sizeof(uint16_t));

      //Convert the value to host byte order
      context->nextPacket = letoh16(context->nextPacket);

      //Get the length of the received frame in bytes
      enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
         (uint8_t *) &n, sizeof(uint16_t));

      //Convert the value to host byte order
      n = letoh16(n);

      //Read the receive status vector (RSV)
      enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
         (uint8_t *) &status, sizeof(uint32_t));

      //Convert the value to host byte order
      status = letoh32(status);

      //Make sure no error occurred
      if((status & RSV_RECEIVED_OK) != 0)
      {
         //Limit the number of data to read
         n = MIN(n, ETH_MAX_FRAME_SIZE);
         //Read the Ethernet frame
         enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA, context->rxBuffer, n);
         //Valid packet received
         error = NO_ERROR;
      }
      else
      {
         //The received packet contains an error
         error = ERROR_INVALID_PACKET;
      }

      //Update the ERXTAIL pointer value to the point where the packet
      //has been processed, taking care to wrap back at the end of the
      //received memory buffer
      if(context->nextPacket == ENC624J600_RX_BUFFER_START)
      {
         enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, ENC624J600_RX_BUFFER_STOP);
      }
      else
      {
         enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, context->nextPacket - 2);
      }

      //Set PKTDEC to decrement the PKTCNT bits
      enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_PKTDEC);
   }
   else
   {
      //No more data in the receive buffer
      error = ERROR_BUFFER_EMPTY;
   }

   //Check whether a valid packet has been received
   if(!error)
   {
      NetRxAncillary ancillary;

      //Additional options can be passed to the stack along with the packet
      ancillary = NET_DEFAULT_RX_ANCILLARY;

      //Pass the packet to the upper layer
      nicProcessPacket(interface, context->rxBuffer, n, &ancillary);
   }

   //Return status code
   return error;
}
//  [c]
void enc624j600WritePhyReg(NetInterface *interface, uint8_t address,
   uint16_t data)
{
   uint16_t status;

   //Write the address of the PHY register to write to
   enc624j600WriteReg(interface, ENC624J600_MIREGADR,
      ENC624J600_MIREGADR_R12_8_DEFAULT | address);

   //Write the 16 bits of data into the MIWR register
   enc624j600WriteReg(interface, ENC624J600_MIWR, data);

   //Wait until the PHY register has been written
   do
   {
      //Read MII Management Status register
      status = enc624j600ReadReg(interface, ENC624J600_MISTAT);
      //Check the value of the busy status bit
   } while((status & ENC624J600_MISTAT_BUSY) != 0);
}
//  [c]
void enc624j600WritePhyReg(NetInterface *interface, uint8_t address,
   uint16_t data)
{
   //Write the address of the PHY register to write to
   enc624j600WriteReg(interface, ENC624J600_REG_MIREGADR, MIREGADR_R8 | address);
   //Write the 16 bits of data into the MIWR register
   enc624j600WriteReg(interface, ENC624J600_REG_MIWR, data);

   //Wait until the PHY register has been written
   while((enc624j600ReadReg(interface, ENC624J600_REG_MISTAT) & MISTAT_BUSY) != 0)
   {
   }
}
//  [c]
error_t enc624j600SoftReset(NetInterface *interface)
{
   //Wait for the SPI interface to be ready
   do
   {
      //Write 0x1234 to EUDAST
      enc624j600WriteReg(interface, ENC624J600_EUDAST, 0x1234);
      //Read back register and check contents
   } while(enc624j600ReadReg(interface, ENC624J600_EUDAST) != 0x1234);

   //Poll CLKRDY and wait for it to become set
   while((enc624j600ReadReg(interface, ENC624J600_ESTAT) & ENC624J600_ESTAT_CLKRDY) == 0)
   {
   }

   //Issue a system reset command by setting ETHRST
   enc624j600SetBit(interface, ENC624J600_ECON2, ENC624J600_ECON2_ETHRST);
   //Wait at least 25us for the reset to take place
   sleep(1);

   //Read EUDAST to confirm that the system reset took place.
   //EUDAST should have reverted back to its reset default
   if(enc624j600ReadReg(interface, ENC624J600_EUDAST) != 0x0000)
   {
      return ERROR_FAILURE;
   }

   //Wait at least 256us for the PHY registers and PHY
   //status bits to become available
   sleep(1);

   //The controller is now ready to accept further commands
   return NO_ERROR;
}
//  [c]
error_t enc624j600SoftReset(NetInterface *interface)
{
   //Wait for the SPI interface to be ready
   do
   {
      //Write 0x1234 to EUDAST
      enc624j600WriteReg(interface, ENC624J600_REG_EUDAST, 0x1234);
      //Read back register and check contents
   } while(enc624j600ReadReg(interface, ENC624J600_REG_EUDAST) != 0x1234);

   //Poll CLKRDY and wait for it to become set
   while((enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_CLKRDY) == 0)
   {
   }

   //Issue a system reset command by setting ETHRST
   enc624j600SetBit(interface, ENC624J600_REG_ECON2, ECON2_ETHRST);
   //Wait at least 25us for the reset to take place
   sleep(1);

   //Read EUDAST to confirm that the system reset took place.
   //EUDAST should have reverted back to its reset default
   if(enc624j600ReadReg(interface, ENC624J600_REG_EUDAST) != 0x0000)
   {
      return ERROR_FAILURE;
   }

   //Wait at least 256us for the PHY registers and PHY
   //status bits to become available
   sleep(1);

   //The controller is now ready to accept further commands
   return NO_ERROR;
}
//  [c]
void enc624j600UpdateMacConfig(NetInterface *interface)
{
   uint16_t duplexMode;

   //Determine the new duplex mode by reading the PHYDPX bit
   duplexMode = enc624j600ReadReg(interface, ENC624J600_ESTAT) & ENC624J600_ESTAT_PHYDPX;

   //Full-duplex mode?
   if(duplexMode)
   {
      //Configure the FULDPX bit to match the current duplex mode
      enc624j600WriteReg(interface, ENC624J600_MACON2, ENC624J600_MACON2_DEFER |
         ENC624J600_MACON2_PADCFG_AUTO | ENC624J600_MACON2_TXCRCEN |
         ENC624J600_MACON2_R1_DEFAULT | ENC624J600_MACON2_FULDPX);

      //Configure the Back-to-Back Inter-Packet Gap register
      enc624j600WriteReg(interface, ENC624J600_MABBIPG,
         ENC624J600_MABBIPG_BBIPG_DEFAULT_FD);
   }
   //Half-duplex mode?
   else
   {
      //Configure the FULDPX bit to match the current duplex mode
      enc624j600WriteReg(interface, ENC624J600_MACON2, ENC624J600_MACON2_DEFER |
         ENC624J600_MACON2_PADCFG_AUTO | ENC624J600_MACON2_TXCRCEN |
         ENC624J600_MACON2_R1_DEFAULT);

      //Configure the Back-to-Back Inter-Packet Gap register
      enc624j600WriteReg(interface, ENC624J600_MABBIPG,
         ENC624J600_MABBIPG_BBIPG_DEFAULT_HD);
   }
}
//  [c]
void enc624j600UpdateMacConfig(NetInterface *interface)
{
   uint16_t duplexMode;

   //Determine the new duplex mode by reading the PHYDPX bit
   duplexMode = enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_PHYDPX;

   //Full-duplex mode?
   if(duplexMode)
   {
      //Configure the FULDPX bit to match the current duplex mode
      enc624j600WriteReg(interface, ENC624J600_REG_MACON2, MACON2_DEFER |
         MACON2_PADCFG2 | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1 | MACON2_FULDPX);
      //Configure the Back-to-Back Inter-Packet Gap register
      enc624j600WriteReg(interface, ENC624J600_REG_MABBIPG, 0x15);
   }
   //Half-duplex mode?
   else
   {
      //Configure the FULDPX bit to match the current duplex mode
      enc624j600WriteReg(interface, ENC624J600_REG_MACON2, MACON2_DEFER |
         MACON2_PADCFG2 | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1);
      //Configure the Back-to-Back Inter-Packet Gap register
      enc624j600WriteReg(interface, ENC624J600_REG_MABBIPG, 0x12);
   }
}
//  [c]
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
	unsigned int offset = sizeof(struct ipv6hdr);
	unsigned int packet_len = skb_tail_pointer(skb) -
		skb_network_header(skb);
	int found_rhdr = 0;
	*nexthdr = &ipv6_hdr(skb)->nexthdr;

	while (offset <= packet_len) {
		struct ipv6_opt_hdr *exthdr;
		unsigned int len;

		switch (**nexthdr) {

		case NEXTHDR_HOP:
			break;
		case NEXTHDR_ROUTING:
			found_rhdr = 1;
			break;
		case NEXTHDR_DEST:
#if IS_ENABLED(CONFIG_IPV6_MIP6)
			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
				break;
#endif
			if (found_rhdr)
				return offset;
			break;
		default:
			return offset;
		}

		if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
			return -EINVAL;

		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
						 offset);
		len = ipv6_optlen(exthdr);
		if (len + offset >= IPV6_MAXPLEN)
			return -EINVAL;
		offset += len;
		*nexthdr = &exthdr->nexthdr;
	}

	return -EINVAL;
}
//  [c]
int shadow_server_start(rdpShadowServer* server)
{
	BOOL ipc;
	BOOL status;
	WSADATA wsaData;

	if (!server)
		return -1;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return -1;

#ifndef _WIN32
	signal(SIGPIPE, SIG_IGN);
#endif
	server->screen = shadow_screen_new(server);

	if (!server->screen)
	{
		WLog_ERR(TAG, "screen_new failed");
		return -1;
	}

	server->capture = shadow_capture_new(server);

	if (!server->capture)
	{
		WLog_ERR(TAG, "capture_new failed");
		return -1;
	}

	/* Bind magic:
	 *
	 * emtpy                 ... bind TCP all
	 * <local path>          ... bind local (IPC)
	 * bind-socket,<address> ... bind TCP to specified interface
	 */
	ipc = server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
	                                    strnlen(bind_address, sizeof(bind_address))) != 0);
	if (!ipc)
	{
		size_t x, count;
		char** list = CommandLineParseCommaSeparatedValuesEx(NULL, server->ipcSocket, &count);
		if (!list || (count <= 1))
		{
			if (server->ipcSocket == NULL)
			{
				if (!open_port(server, NULL))
				{
					free(list);
					return -1;
				}
			}
			else
			{
				free(list);
				return -1;
			}
		}

		for (x = 1; x < count; x++)
		{
			BOOL success = open_port(server, list[x]);
			if (!success)
			{
				free(list);
				return -1;
			}
		}
		free(list);
	}
	else
	{
		status = server->listener->OpenLocal(server->listener, server->ipcSocket);
		if (!status)
		{
			WLog_ERR(TAG, "Problem creating local socket listener. (Port already used or "
			              "insufficient permissions?)");
			return -1;
		}
	}

	if (!(server->thread = CreateThread(NULL, 0, shadow_server_thread, (void*)server, 0, NULL)))
	{
		return -1;
	}

	return 0;
}
//  [c]
int shadow_server_start(rdpShadowServer* server)
{
	BOOL ipc;
	BOOL status;
	WSADATA wsaData;

	if (!server)
		return -1;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return -1;

#ifndef _WIN32
	signal(SIGPIPE, SIG_IGN);
#endif
	server->screen = shadow_screen_new(server);

	if (!server->screen)
	{
		WLog_ERR(TAG, "screen_new failed");
		return -1;
	}

	server->capture = shadow_capture_new(server);

	if (!server->capture)
	{
		WLog_ERR(TAG, "capture_new failed");
		return -1;
	}

	/* Bind magic:
	 *
	 * emtpy                 ... bind TCP all
	 * <local path>          ... bind local (IPC)
	 * bind-socket,<address> ... bind TCP to specified interface
	 */
	ipc = server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
	                                    strnlen(bind_address, sizeof(bind_address))) != 0);
	if (!ipc)
	{
		size_t x, count;
		char** list = CommandLineParseCommaSeparatedValuesEx(NULL, server->ipcSocket, &count);
		if (!list || (count <= 1))
		{
			free(list);
			if (server->ipcSocket == NULL)
			{
				if (!open_port(server, NULL))
					return -1;
			}
			else
				return -1;
		}

		for (x = 1; x < count; x++)
		{
			BOOL success = open_port(server, list[x]);
			if (!success)
			{
				free(list);
				return -1;
			}
		}
		free(list);
	}
	else
	{
		status = server->listener->OpenLocal(server->listener, server->ipcSocket);
		if (!status)
		{
			WLog_ERR(TAG, "Problem creating local socket listener. (Port already used or "
			              "insufficient permissions?)");
			return -1;
		}
	}

	if (!(server->thread = CreateThread(NULL, 0, shadow_server_thread, (void*)server, 0, NULL)))
	{
		return -1;
	}

	return 0;
}
//  [c]
int passwd_to_utf16(unsigned char *in_passwd,
                    int length,
                    int max_length,
                    unsigned char *out_passwd)
{
    // Perform a password length check before proceeding
    if (length > max_length)
    {
        fprintf(stderr, "Error: password too long\n");
        return -1;
    }

#ifdef WIN32
    int ret;
    (void)length;
    ret = MultiByteToWideChar(CP_ACP,
                              0,
                              (LPCSTR) in_passwd,
                              -1,
                              (LPWSTR) out_passwd,
                              max_length / 2);
    if (ret == 0)
        return AESCRYPT_READPWD_ICONV;
    return ret * 2;
#else
#ifndef ENABLE_ICONV
    /* support only latin */
    int i;
    for (i = 0; i < length + 1; i++)
    {
        out_passwd[i * 2] = in_passwd[i];
        out_passwd[i * 2 + 1] = 0;
    }
    return length * 2;
#else
    unsigned char *ic_outbuf,
                  *ic_inbuf;
    iconv_t condesc;
    size_t ic_inbytesleft,
           ic_outbytesleft;

    /* Max length is specified in character, but this function deals
     * with bytes.  So, multiply by two since we are going to create a
     * UTF-16 string.
     */
    max_length *= 2;

    ic_inbuf = in_passwd;
    ic_inbytesleft = length;
    ic_outbytesleft = max_length;
    ic_outbuf = out_passwd;

    /* Set the locale based on the current environment */
    setlocale(LC_CTYPE,"");

    if ((condesc = iconv_open("UTF-16LE", nl_langinfo(CODESET))) ==
        (iconv_t)(-1))
    {
        perror("Error in iconv_open");
        return -1;
    }

    if (iconv(condesc,
              (char ** const) &ic_inbuf,
              &ic_inbytesleft,
              (char ** const) &ic_outbuf,
              &ic_outbytesleft) == (size_t) -1)
    {
        switch (errno)
        {
            case E2BIG:
                fprintf(stderr, "Error: password too long\n");
                iconv_close(condesc);
                return -1;
                break;
            default:
                /*
                printf("\nEILSEQ(%d), EINVAL(%d), %d\n",
                       EILSEQ,
                       EINVAL,
                       errno);
                */
                perror("Password conversion error");
                iconv_close(condesc);
                return -1;
        }
    }
    iconv_close(condesc);
    return (max_length - ic_outbytesleft);
#endif
#endif
}
//  [c]
int passwd_to_utf16(unsigned char *in_passwd,
                    int length,
                    int max_length,
                    unsigned char *out_passwd)
{
#ifdef WIN32
    int ret;
    (void)length;
    ret = MultiByteToWideChar(
        CP_ACP,
        0,
        (LPCSTR)in_passwd,
        -1,
        (LPWSTR)out_passwd,
        max_length / 2
    );
    if (ret == 0)
        return AESCRYPT_READPWD_ICONV;
    return ret * 2;
#else
#ifndef ENABLE_ICONV
    /* support only latin */
    int i;
    for (i=0;i<length+1;i++) {
        out_passwd[i*2] = in_passwd[i];
        out_passwd[i*2+1] = 0;
    }
    return length*2;
#else
    unsigned char *ic_outbuf,
                  *ic_inbuf;
    iconv_t condesc;
    size_t ic_inbytesleft,
           ic_outbytesleft;

    /* Max length is specified in character, but this function deals
     * with bytes.  So, multiply by two since we are going to create a
     * UTF-16 string.
     */
    max_length *= 2;

    ic_inbuf = in_passwd;
    ic_inbytesleft = length;
    ic_outbytesleft = max_length;
    ic_outbuf = out_passwd;

    /* Set the locale based on the current environment */
    setlocale(LC_CTYPE,"");

    if ((condesc = iconv_open("UTF-16LE", nl_langinfo(CODESET))) ==
        (iconv_t)(-1))
    {
        perror("Error in iconv_open");
        return -1;
    }

    if (iconv(condesc,
              (char ** const) &ic_inbuf,
              &ic_inbytesleft,
              (char ** const) &ic_outbuf,
              &ic_outbytesleft) == (size_t) -1)
    {
        switch (errno)
        {
            case E2BIG:
                fprintf(stderr, "Error: password too long\n");
                iconv_close(condesc);
                return -1;
                break;
            default:
                /*
                printf("\nEILSEQ(%d), EINVAL(%d), %d\n",
                       EILSEQ,
                       EINVAL,
                       errno);
                */
                perror("Password conversion error");
                iconv_close(condesc);
                return -1;
        }
    }
    iconv_close(condesc);
    return (max_length - ic_outbytesleft);
#endif
#endif
}
//  [c]
static void mspack_fmap_free(void *mem)
{
    if(mem) {
        free(mem);
        mem = NULL;
    }
    return;
}
//  [c]
static void mspack_fmap_free(void *mem)
{
	free(mem);
}
//  [c]
isoclns_print(netdissect_options *ndo, const uint8_t *p, u_int length)
{
	if (!ND_TTEST(*p)) { /* enough bytes on the wire ? */
		ND_PRINT((ndo, "|OSI"));
		return;
	}

	if (ndo->ndo_eflag)
		ND_PRINT((ndo, "OSI NLPID %s (0x%02x): ", tok2str(nlpid_values, "Unknown", *p), *p));

	switch (*p) {

	case NLPID_CLNP:
		if (!clnp_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", length);
		break;

	case NLPID_ESIS:
		esis_print(ndo, p, length);
		return;

	case NLPID_ISIS:
		if (!isis_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", length);
		break;

	case NLPID_NULLNS:
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		break;

	case NLPID_Q933:
		q933_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP:
		ip_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP6:
		ip6_print(ndo, p + 1, length - 1);
		break;

	case NLPID_PPP:
		ppp_print(ndo, p + 1, length - 1);
		break;

	default:
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, "OSI NLPID 0x%02x unknown", *p));
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		if (length > 1)
			print_unknown_data(ndo, p, "\n\t", length);
		break;
	}
}
//  [c]
isoclns_print(netdissect_options *ndo,
              const uint8_t *p, u_int length, u_int caplen)
{
	if (caplen <= 1) { /* enough bytes on the wire ? */
		ND_PRINT((ndo, "|OSI"));
		return;
	}

	if (ndo->ndo_eflag)
		ND_PRINT((ndo, "OSI NLPID %s (0x%02x): ", tok2str(nlpid_values, "Unknown", *p), *p));

	switch (*p) {

	case NLPID_CLNP:
		if (!clnp_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", caplen);
		break;

	case NLPID_ESIS:
		esis_print(ndo, p, length);
		return;

	case NLPID_ISIS:
		if (!isis_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", caplen);
		break;

	case NLPID_NULLNS:
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		break;

	case NLPID_Q933:
		q933_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP:
		ip_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP6:
		ip6_print(ndo, p + 1, length - 1);
		break;

	case NLPID_PPP:
		ppp_print(ndo, p + 1, length - 1);
		break;

	default:
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, "OSI NLPID 0x%02x unknown", *p));
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		if (caplen > 1)
			print_unknown_data(ndo, p, "\n\t", caplen);
		break;
	}
}
//  [c]
static bool check_underflow(const struct ipt_entry *e)
{
	const struct xt_entry_target *t;
	unsigned int verdict;

	if (!unconditional(e))
		return false;
	t = ipt_get_target_c(e);
	if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
		return false;
	verdict = ((struct xt_standard_target *)t)->verdict;
	verdict = -verdict - 1;
	return verdict == NF_DROP || verdict == NF_ACCEPT;
}
//  [c]
static bool check_underflow(const struct ipt_entry *e)
{
	const struct xt_entry_target *t;
	unsigned int verdict;

	if (!unconditional(&e->ip))
		return false;
	t = ipt_get_target_c(e);
	if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
		return false;
	verdict = ((struct xt_standard_target *)t)->verdict;
	verdict = -verdict - 1;
	return verdict == NF_DROP || verdict == NF_ACCEPT;
}
//  [c]
get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
		      const char *hookname, const char **chainname,
		      const char **comment, unsigned int *rulenum)
{
	const struct xt_standard_target *t = (void *)ipt_get_target_c(s);

	if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
		/* Head of user chain: ERROR target with chainname */
		*chainname = t->target.data;
		(*rulenum) = 0;
	} else if (s == e) {
		(*rulenum)++;

		if (unconditional(s) &&
		    strcmp(t->target.u.kernel.target->name,
			   XT_STANDARD_TARGET) == 0 &&
		   t->verdict < 0) {
			/* Tail of chains: STANDARD target (return/policy) */
			*comment = *chainname == hookname
				? comments[NF_IP_TRACE_COMMENT_POLICY]
				: comments[NF_IP_TRACE_COMMENT_RETURN];
		}
		return 1;
	} else
		(*rulenum)++;

	return 0;
}
//  [c]
get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
		      const char *hookname, const char **chainname,
		      const char **comment, unsigned int *rulenum)
{
	const struct xt_standard_target *t = (void *)ipt_get_target_c(s);

	if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
		/* Head of user chain: ERROR target with chainname */
		*chainname = t->target.data;
		(*rulenum) = 0;
	} else if (s == e) {
		(*rulenum)++;

		if (s->target_offset == sizeof(struct ipt_entry) &&
		    strcmp(t->target.u.kernel.target->name,
			   XT_STANDARD_TARGET) == 0 &&
		   t->verdict < 0 &&
		   unconditional(&s->ip)) {
			/* Tail of chains: STANDARD target (return/policy) */
			*comment = *chainname == hookname
				? comments[NF_IP_TRACE_COMMENT_POLICY]
				: comments[NF_IP_TRACE_COMMENT_RETURN];
		}
		return 1;
	} else
		(*rulenum)++;

	return 0;
}
//  [c]
mark_source_chains(const struct xt_table_info *newinfo,
		   unsigned int valid_hooks, void *entry0)
{
	unsigned int hook;

	/* No recursion; use packet counter to save back ptrs (reset
	   to 0 as we leave), and comefrom to save source hook bitmask */
	for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
		unsigned int pos = newinfo->hook_entry[hook];
		struct ipt_entry *e = (struct ipt_entry *)(entry0 + pos);

		if (!(valid_hooks & (1 << hook)))
			continue;

		/* Set initial back pointer. */
		e->counters.pcnt = pos;

		for (;;) {
			const struct xt_standard_target *t
				= (void *)ipt_get_target_c(e);
			int visited = e->comefrom & (1 << hook);

			if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
				pr_err("iptables: loop hook %u pos %u %08X.\n",
				       hook, pos, e->comefrom);
				return 0;
			}
			e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));

			/* Unconditional return/END. */
			if ((unconditional(e) &&
			     (strcmp(t->target.u.user.name,
				     XT_STANDARD_TARGET) == 0) &&
			     t->verdict < 0) || visited) {
				unsigned int oldpos, size;

				if ((strcmp(t->target.u.user.name,
					    XT_STANDARD_TARGET) == 0) &&
				    t->verdict < -NF_MAX_VERDICT - 1) {
					duprintf("mark_source_chains: bad "
						"negative verdict (%i)\n",
								t->verdict);
					return 0;
				}

				/* Return: backtrack through the last
				   big jump. */
				do {
					e->comefrom ^= (1<<NF_INET_NUMHOOKS);
#ifdef DEBUG_IP_FIREWALL_USER
					if (e->comefrom
					    & (1 << NF_INET_NUMHOOKS)) {
						duprintf("Back unset "
							 "on hook %u "
							 "rule %u\n",
							 hook, pos);
					}
#endif
					oldpos = pos;
					pos = e->counters.pcnt;
					e->counters.pcnt = 0;

					/* We're at the start. */
					if (pos == oldpos)
						goto next;

					e = (struct ipt_entry *)
						(entry0 + pos);
				} while (oldpos == pos + e->next_offset);

				/* Move along one */
				size = e->next_offset;
				e = (struct ipt_entry *)
					(entry0 + pos + size);
				e->counters.pcnt = pos;
				pos += size;
			} else {
				int newpos = t->verdict;

				if (strcmp(t->target.u.user.name,
					   XT_STANDARD_TARGET) == 0 &&
				    newpos >= 0) {
					if (newpos > newinfo->size -
						sizeof(struct ipt_entry)) {
						duprintf("mark_source_chains: "
							"bad verdict (%i)\n",
								newpos);
						return 0;
					}
					/* This a jump; chase it. */
					duprintf("Jump rule %u -> %u\n",
						 pos, newpos);
				} else {
					/* ... this is a fallthru */
					newpos = pos + e->next_offset;
				}
				e = (struct ipt_entry *)
					(entry0 + newpos);
				e->counters.pcnt = pos;
				pos = newpos;
			}
		}
next:
		duprintf("Finished chain %u\n", hook);
	}
	return 1;
}