static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)

{

    unsigned    desc[2];

    target_phys_addr_t packet_desc_addr, last_desc_addr;

    GemState *s;

    unsigned   rxbufsize, bytes_to_copy;

    unsigned   rxbuf_offset;

    uint8_t    rxbuf[2048];

    uint8_t   *rxbuf_ptr;



    s = DO_UPCAST(NICState, nc, nc)->opaque;



    /* Do nothing if receive is not enabled. */

    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {

        return -1;

    }



    /* Is this destination MAC address "for us" ? */

    if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {

        return -1;

    }



    /* Discard packets with receive length error enabled ? */

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {

        unsigned type_len;



        /* Fish the ethertype / length field out of the RX packet */

        type_len = buf[12] << 8 | buf[13];

        /* It is a length field, not an ethertype */

        if (type_len < 0x600) {

            if (size < type_len) {

                /* discard */

                return -1;

            }

        }

    }



    /*

     * Determine configured receive buffer offset (probably 0)

     */

    rxbuf_offset = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>

                   GEM_NWCFG_BUFF_OFST_S;



    /* The configure size of each receive buffer.  Determines how many

     * buffers needed to hold this packet.

     */

    rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>

                 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;

    bytes_to_copy = size;



    /* Strip of FCS field ? (usually yes) */

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {

        rxbuf_ptr = (void *)buf;

    } else {

        unsigned crc_val;

        int      crc_offset;



        /* The application wants the FCS field, which QEMU does not provide.

         * We must try and caclculate one.

         */



        memcpy(rxbuf, buf, size);

        memset(rxbuf + size, 0, sizeof(rxbuf) - size);

        rxbuf_ptr = rxbuf;

        crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));

        if (size < 60) {

            crc_offset = 60;

        } else {

            crc_offset = size;

        }

        memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val));



        bytes_to_copy += 4;

        size += 4;

    }



    /* Pad to minimum length */

    if (size < 64) {

        size = 64;

    }



    DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);



    packet_desc_addr = s->rx_desc_addr;

    while (1) {

        DB_PRINT("read descriptor 0x%x\n", packet_desc_addr);

        /* read current descriptor */

        cpu_physical_memory_read(packet_desc_addr,

                                 (uint8_t *)&desc[0], sizeof(desc));



        /* Descriptor owned by software ? */

        if (rx_desc_get_ownership(desc) == 1) {

            DB_PRINT("descriptor 0x%x owned by sw.\n", packet_desc_addr);

            s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;

            /* Handle interrupt consequences */

            gem_update_int_status(s);

            return -1;

        }



        DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),

                rx_desc_get_buffer(desc));



        /*

         * Let's have QEMU lend a helping hand.

         */

        if (rx_desc_get_buffer(desc) == 0) {

            DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",

                       packet_desc_addr);

            break;

        }



        /* Copy packet data to emulated DMA buffer */

        cpu_physical_memory_write(rx_desc_get_buffer(desc) + rxbuf_offset,

                                  rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));

        bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);

        rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);

        if (bytes_to_copy == 0) {

            break;

        }



        /* Next descriptor */

        if (rx_desc_get_wrap(desc)) {

            packet_desc_addr = s->regs[GEM_RXQBASE];

        } else {

            packet_desc_addr += 8;

        }

    }



    DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,

            (unsigned)packet_desc_addr);



    /* Update last descriptor with EOF and total length */

    rx_desc_set_eof(desc);

    rx_desc_set_length(desc, size);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&desc[0], sizeof(desc));



    /* Advance RX packet descriptor Q */

    last_desc_addr = packet_desc_addr;

    packet_desc_addr = s->rx_desc_addr;

    s->rx_desc_addr = last_desc_addr;

    if (rx_desc_get_wrap(desc)) {

        s->rx_desc_addr = s->regs[GEM_RXQBASE];

    } else {

        s->rx_desc_addr += 8;

    }



    DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", packet_desc_addr);



    /* Count it */

    gem_receive_updatestats(s, buf, size);



    /* Update first descriptor (which could also be the last) */

    /* read descriptor */

    cpu_physical_memory_read(packet_desc_addr,

                             (uint8_t *)&desc[0], sizeof(desc));

    rx_desc_set_sof(desc);

    rx_desc_set_ownership(desc);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&desc[0], sizeof(desc));



    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;



    /* Handle interrupt consequences */

    gem_update_int_status(s);



    return size;

}

static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)

{

    unsigned    desc[2];

    target_phys_addr_t packet_desc_addr, last_desc_addr;

    GemState *s;

    unsigned   rxbufsize, bytes_to_copy;

    unsigned   rxbuf_offset;

    uint8_t    rxbuf[2048];

    uint8_t   *rxbuf_ptr;



    s = DO_UPCAST(NICState, nc, nc)->opaque;



    

    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {

        return -1;

    }



    

    if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {

        return -1;

    }



    

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {

        unsigned type_len;



        

        type_len = buf[12] << 8 | buf[13];

        

        if (type_len < 0x600) {

            if (size < type_len) {

                

                return -1;

            }

        }

    }



    





    rxbuf_offset = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>

                   GEM_NWCFG_BUFF_OFST_S;



    





    rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>

                 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;

    bytes_to_copy = size;



    

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {

        rxbuf_ptr = (void *)buf;

    } else {

        unsigned crc_val;

        int      crc_offset;



        







        memcpy(rxbuf, buf, size);

        memset(rxbuf + size, 0, sizeof(rxbuf) - size);

        rxbuf_ptr = rxbuf;

        crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));

        if (size < 60) {

            crc_offset = 60;

        } else {

            crc_offset = size;

        }

        memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val));



        bytes_to_copy += 4;

        size += 4;

    }



    

    if (size < 64) {

        size = 64;

    }



    DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);



    packet_desc_addr = s->rx_desc_addr;

    while (1) {

        DB_PRINT("read descriptor 0x%x\n", packet_desc_addr);

        

        cpu_physical_memory_read(packet_desc_addr,

                                 (uint8_t *)&desc[0], sizeof(desc));



        

        if (rx_desc_get_ownership(desc) == 1) {

            DB_PRINT("descriptor 0x%x owned by sw.\n", packet_desc_addr);

            s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;

            

            gem_update_int_status(s);

            return -1;

        }



        DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),

                rx_desc_get_buffer(desc));



        





        if (rx_desc_get_buffer(desc) == 0) {

            DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",

                       packet_desc_addr);

            break;

        }



        

        cpu_physical_memory_write(rx_desc_get_buffer(desc) + rxbuf_offset,

                                  rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));

        bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);

        rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);

        if (bytes_to_copy == 0) {

            break;

        }



        

        if (rx_desc_get_wrap(desc)) {

            packet_desc_addr = s->regs[GEM_RXQBASE];

        } else {

            packet_desc_addr += 8;

        }

    }



    DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,

            (unsigned)packet_desc_addr);



    

    rx_desc_set_eof(desc);

    rx_desc_set_length(desc, size);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&desc[0], sizeof(desc));



    

    last_desc_addr = packet_desc_addr;

    packet_desc_addr = s->rx_desc_addr;

    s->rx_desc_addr = last_desc_addr;

    if (rx_desc_get_wrap(desc)) {

        s->rx_desc_addr = s->regs[GEM_RXQBASE];

    } else {

        s->rx_desc_addr += 8;

    }



    DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", packet_desc_addr);



    

    gem_receive_updatestats(s, buf, size);



    

    

    cpu_physical_memory_read(packet_desc_addr,

                             (uint8_t *)&desc[0], sizeof(desc));

    rx_desc_set_sof(desc);

    rx_desc_set_ownership(desc);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&desc[0], sizeof(desc));



    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;



    

    gem_update_int_status(s);



    return size;

}

static ssize_t FUNC_0(NetClientState *nc, const uint8_t *buf, size_t size)

{

    unsigned    VAR_0[2];

    target_phys_addr_t packet_desc_addr, last_desc_addr;

    GemState *s;

    unsigned   VAR_1, VAR_2;

    unsigned   VAR_3;

    uint8_t    rxbuf[2048];

    uint8_t   *rxbuf_ptr;



    s = DO_UPCAST(NICState, nc, nc)->opaque;



    

    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {

        return -1;

    }



    

    if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {

        return -1;

    }



    

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {

        unsigned VAR_4;



        

        VAR_4 = buf[12] << 8 | buf[13];

        

        if (VAR_4 < 0x600) {

            if (size < VAR_4) {

                

                return -1;

            }

        }

    }



    





    VAR_3 = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>

                   GEM_NWCFG_BUFF_OFST_S;



    





    VAR_1 = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>

                 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;

    VAR_2 = size;



    

    if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {

        rxbuf_ptr = (void *)buf;

    } else {

        unsigned VAR_5;

        int      VAR_6;



        







        memcpy(rxbuf, buf, size);

        memset(rxbuf + size, 0, sizeof(rxbuf) - size);

        rxbuf_ptr = rxbuf;

        VAR_5 = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));

        if (size < 60) {

            VAR_6 = 60;

        } else {

            VAR_6 = size;

        }

        memcpy(rxbuf + VAR_6, &VAR_5, sizeof(VAR_5));



        VAR_2 += 4;

        size += 4;

    }



    

    if (size < 64) {

        size = 64;

    }



    DB_PRINT("config bufsize: %d packet size: %ld\n", VAR_1, size);



    packet_desc_addr = s->rx_desc_addr;

    while (1) {

        DB_PRINT("read descriptor 0x%x\n", packet_desc_addr);

        

        cpu_physical_memory_read(packet_desc_addr,

                                 (uint8_t *)&VAR_0[0], sizeof(VAR_0));



        

        if (rx_desc_get_ownership(VAR_0) == 1) {

            DB_PRINT("descriptor 0x%x owned by sw.\n", packet_desc_addr);

            s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;

            

            gem_update_int_status(s);

            return -1;

        }



        DB_PRINT("copy %d bytes to 0x%x\n", MIN(VAR_2, VAR_1),

                rx_desc_get_buffer(VAR_0));



        





        if (rx_desc_get_buffer(VAR_0) == 0) {

            DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",

                       packet_desc_addr);

            break;

        }



        

        cpu_physical_memory_write(rx_desc_get_buffer(VAR_0) + VAR_3,

                                  rxbuf_ptr, MIN(VAR_2, VAR_1));

        VAR_2 -= MIN(VAR_2, VAR_1);

        rxbuf_ptr += MIN(VAR_2, VAR_1);

        if (VAR_2 == 0) {

            break;

        }



        

        if (rx_desc_get_wrap(VAR_0)) {

            packet_desc_addr = s->regs[GEM_RXQBASE];

        } else {

            packet_desc_addr += 8;

        }

    }



    DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,

            (unsigned)packet_desc_addr);



    

    rx_desc_set_eof(VAR_0);

    rx_desc_set_length(VAR_0, size);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&VAR_0[0], sizeof(VAR_0));



    

    last_desc_addr = packet_desc_addr;

    packet_desc_addr = s->rx_desc_addr;

    s->rx_desc_addr = last_desc_addr;

    if (rx_desc_get_wrap(VAR_0)) {

        s->rx_desc_addr = s->regs[GEM_RXQBASE];

    } else {

        s->rx_desc_addr += 8;

    }



    DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", packet_desc_addr);



    

    gem_receive_updatestats(s, buf, size);



    

    

    cpu_physical_memory_read(packet_desc_addr,

                             (uint8_t *)&VAR_0[0], sizeof(VAR_0));

    rx_desc_set_sof(VAR_0);

    rx_desc_set_ownership(VAR_0);

    cpu_physical_memory_write(packet_desc_addr,

                              (uint8_t *)&VAR_0[0], sizeof(VAR_0));



    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;



    

    gem_update_int_status(s);



    return size;

}

static ssize_t FUNC_0(NetClientState *nc, const uint8_t *buf, size_t size)
{ unsigned    VAR_0[2]; target_phys_addr_t packet_desc_addr, last_desc_addr; GemState *s; unsigned   VAR_1, VAR_2; unsigned   VAR_3; uint8_t    rxbuf[2048]; uint8_t   *rxbuf_ptr; s = DO_UPCAST(NICState, nc, nc)->opaque; if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) { return -1; } if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) { return -1; } if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) { unsigned VAR_4; VAR_4 = buf[12] << 8 | buf[13]; if (VAR_4 < 0x600) { if (size < VAR_4) { return -1; } } } VAR_3 = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>
GEM_NWCFG_BUFF_OFST_S; VAR_1 = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>
GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL; VAR_2 = size; if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) { rxbuf_ptr = (void *)buf; } else { unsigned VAR_5; int      VAR_6; memcpy(rxbuf, buf, size); memset(rxbuf + size, 0, sizeof(rxbuf) - size); rxbuf_ptr = rxbuf; VAR_5 = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60))); if (size < 60) { VAR_6 = 60; } else { VAR_6 = size; } memcpy(rxbuf + VAR_6, &VAR_5, sizeof(VAR_5)); VAR_2 += 4; size += 4; } if (size < 64) { size = 64; } DB_PRINT("config bufsize: %d packet size: %ld\n", VAR_1, size); packet_desc_addr = s->rx_desc_addr; while (1) { DB_PRINT("read descriptor 0x%x\n", packet_desc_addr); cpu_physical_memory_read(packet_desc_addr,
(uint8_t *)&VAR_0[0], sizeof(VAR_0)); if (rx_desc_get_ownership(VAR_0) == 1) { DB_PRINT("descriptor 0x%x owned by sw.\n", packet_desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; gem_update_int_status(s); return -1; } DB_PRINT("copy %d bytes to 0x%x\n", MIN(VAR_2, VAR_1),
rx_desc_get_buffer(VAR_0)); if (rx_desc_get_buffer(VAR_0) == 0) { DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",
packet_desc_addr); break; } cpu_physical_memory_write(rx_desc_get_buffer(VAR_0) + VAR_3,
rxbuf_ptr, MIN(VAR_2, VAR_1)); VAR_2 -= MIN(VAR_2, VAR_1); rxbuf_ptr += MIN(VAR_2, VAR_1); if (VAR_2 == 0) { break; } if (rx_desc_get_wrap(VAR_0)) { packet_desc_addr = s->regs[GEM_RXQBASE]; } else { packet_desc_addr += 8; } } DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,
(unsigned)packet_desc_addr); rx_desc_set_eof(VAR_0); rx_desc_set_length(VAR_0, size); cpu_physical_memory_write(packet_desc_addr,
(uint8_t *)&VAR_0[0], sizeof(VAR_0)); last_desc_addr = packet_desc_addr; packet_desc_addr = s->rx_desc_addr; s->rx_desc_addr = last_desc_addr; if (rx_desc_get_wrap(VAR_0)) { s->rx_desc_addr = s->regs[GEM_RXQBASE]; } else { s->rx_desc_addr += 8; } DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", packet_desc_addr); gem_receive_updatestats(s, buf, size); cpu_physical_memory_read(packet_desc_addr,
(uint8_t *)&VAR_0[0], sizeof(VAR_0)); rx_desc_set_sof(VAR_0); rx_desc_set_ownership(VAR_0); cpu_physical_memory_write(packet_desc_addr,
(uint8_t *)&VAR_0[0], sizeof(VAR_0)); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD; gem_update_int_status(s); return size; }