void network_device_send() { int i; uint16_t len; if (packet_pending) { ETH_DEV_DBG_ERROR("network_device_send: already pending packet, discarding request"); return; } if (uip_len == 0) { ETH_DEV_DBG_ERROR("network_device_send: uip_len == 0"); return; } len = MIN(sizeof(send_buffer), uip_len); vicDisable(INT_CHANNEL_USB); for (i=0; i<len; i++) { send_buffer[i] = uip_buf[i]; } bytes_sent=0; bytes_to_send = len; packet_pending = 1; usbEnableNAKInterrupts(INACK_BI); vicEnable(INT_CHANNEL_USB); }
void network_device_send() { int i; uint16_t len; DBG("network device send! (%d bytes)",uip_len); if (uip_len == 0) { ETH_DEV_DBG_ERROR("network_device_send: uip_len == 0"); return; } vicDisable(INT_CHANNEL_USB); uint8_t packet_pending_copy = packet_pending; vicEnable(INT_CHANNEL_USB); if (packet_pending_copy) { ETH_DEV_DBG_ERROR("network_device_send: already pending packet, discarding request"); return; } len = MIN(sizeof(send_buffer), uip_len); for (i=0; i<len; i++) { send_buffer[i] = uip_buf[i]; } vicDisable(INT_CHANNEL_USB); bytes_sent=0; bytes_to_send = len; packet_pending = 1; eth_nak_interrupts |= INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); vicEnable(INT_CHANNEL_USB); //ETH_DEV_DBG_ERROR("network_device_send: NACK Interrupts enable on bulk in"); //DBG("leaving network send"); }
void usb_eth_rx(uint8_t ep, uint8_t stat) { int len; int ip_length; uint16_t eth_hdr_type; if (receive_packet == 0) { if (RING_IS_FULL(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) { ETH_DEV_DBG_ERROR("usb_eth_rx: receive ring is full, head=%d, tail=%d", receive_ring_head, receive_ring_tail); return; } receive_packet = &receive_ring[receive_ring_tail]; packet_init(receive_packet); } if (receive_packet->transferred < PACKET_SIZE) { len = usbRead(ep, &receive_packet->data[0] + receive_packet->transferred, PACKET_SIZE - receive_packet->transferred); } else { /* discard the bytes */ len = usbRead(ep, 0, 0); } receive_packet->transferred += len; ETH_DEV_DBG_INFO("usb_eth_rx: read %d bytes, head=%d, tail=%d", len, receive_ring_head, receive_ring_tail); if (receive_packet->transferred < UIP_LLH_LEN) { /* ethernet header was not received yet got some garbage which we need to ignore */ ETH_DEV_DBG_ERROR("got part of packet with %d bytes", receive_packet->transferred); receive_packet->transferred = 0; return; } if (receive_packet->size == 0) { eth_hdr_type = (receive_packet->data[0xc] << 8) | receive_packet->data[0xd]; if (eth_hdr_type == UIP_ETHTYPE_IP) { ip_length = receive_packet->data[0x10]*0xff + receive_packet->data[0x11]; receive_packet->size = ip_length + UIP_LLH_LEN; } else if (eth_hdr_type == UIP_ETHTYPE_ARP) { receive_packet->size = receive_packet->transferred; } else { ETH_DEV_DBG_ERROR("Unknown ethernet frame 0x%x", eth_hdr_type); receive_packet->size = receive_packet->transferred; } } if (receive_packet->transferred >= receive_packet->size) { if (receive_packet->transferred >= receive_packet->size) { if (receive_packet->transferred >= PACKET_SIZE) { ETH_DEV_DBG_ERROR("Discarding packet of size %d", receive_packet->transferred); packet_init(receive_packet); receive_packet = 0; } else { ETH_DEV_DBG_INFO("Received packet of size %d", receive_packet->transferred); receive_packet = 0; RING_INC(receive_ring_tail, RECEIVE_RING_SIZE); } } } }
static bool usb_control_class_handler(void) { uint32_t oid; uint32_t buflen; uint32_t bufptr; //printf("control_class_handler!!!"); ETH_DEV_DBG_INFO("class control request=%d interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type)); DBG("class control request=%d interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type)); if (REQTYPE_GET_DIR(usbRequest.type) == REQTYPE_DIR_TO_HOST) { if (rndisResponseReady) { //ETH_DEV_DBG_INFO("sending data back to the host, %d bytes\n",rndisResponseLen); usbControlTransferPtr = rndisResponse; usbControlTransferLen = rndisResponseLen; rndisResponseReady = 0; } else { //ETH_DEV_DBG_INFO("sending NO RESPONE AVAILABLE to the host"); usbControlTransferPtr = &rndisResponseNotAvailable; usbControlTransferLen = 1; } return TRUE; } uint32_t type = uint32FromLittleEndian(usbControlTransferPtr); uint32_t len = uint32FromLittleEndian(usbControlTransferPtr+4); uint32_t id = uint32FromLittleEndian(usbControlTransferPtr+8); //ETH_DEV_DBG_INFO("RNDIS request type = %x len=%u id=%u\n",type,len,id); if (type > 10 || len > 200) { ETH_DEV_DBG_INFO("Woopa!!!\n"); oid = uint32FromLittleEndian(usbControlTransferPtr+12); buflen = uint32FromLittleEndian(usbControlTransferPtr+16); bufptr = uint32FromLittleEndian(usbControlTransferPtr+20); if (type==4) ETH_DEV_DBG_INFO("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr); int iii; for (iii=0; iii<usbRequest.length; iii++) ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]); while (1); } switch (type) { case 0x02: /* REMOTE_NDIS_INITIALIZE_MSG */ ETH_DEV_DBG_INFO(" INITIALIZE_MSG version=%u.%u max device->host transfer size = %u", uint32FromLittleEndian(usbControlTransferPtr+12), uint32FromLittleEndian(usbControlTransferPtr+16), uint32FromLittleEndian(usbControlTransferPtr+20)); if (rndisState != RNDIS_UNINITIALIZED) { ETH_DEV_DBG_ERROR("INITIALIZE message when we are not in the uninitialized state (state=%d)",rndisState); break; } //int i; //for (i=0; i<len; i++) { // ETH_DEV_DBG_INFO("%d %02x",i,usbControlTransferPtr[i]); //} uint32ToLittleEndian(0x80000002,rndisResponse); /* INITIALIZE_CMPLT */ uint32ToLittleEndian(52,rndisResponse+4); /* length */ uint32ToLittleEndian(id,rndisResponse+8); /* request id to which we are responding */ uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */ uint32ToLittleEndian(1,rndisResponse+16); /* version, major */ uint32ToLittleEndian(0,rndisResponse+20); /* version, minor */ uint32ToLittleEndian(1,rndisResponse+24); /* flags = connectionless */ uint32ToLittleEndian(0,rndisResponse+28); /* medium = 802.3 */ uint32ToLittleEndian(1,rndisResponse+32); /* max packets per transfer */ /* the 22 is some voodoo from Linux drivers/gadget */ uint32ToLittleEndian((11*4+ETHERNET_FRAME_SIZE_MAX+22),rndisResponse+36); /* max transfer size; rndis header + ethernet packet */ uint32ToLittleEndian(0,rndisResponse+40); /* packet alignment for multi-packet transfers */ uint32ToLittleEndian(0,rndisResponse+44); /* reserved */ uint32ToLittleEndian(0,rndisResponse+48); /* reserved */ rndisResponseLen = 52; //usbControlTransferPtr = rndisResponse; //usbControlTransferLen = 24; rndisResponseReady = 1; eth_nak_interrupts |= INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); //usbEnableNAKInterrupts(INACK_II); rndisState = RNDIS_INITIALIZED; /* we should really do this only after sending the response */ break; case 0x03: /* HALT */ ETH_DEV_DBG_INFO("HALT!?!"); rndisState = RNDIS_UNINITIALIZED; /* we should really do this only after sending the response */ break; case 0x04: /* REMOTE_NDIS_QUERY_MSG */ oid = uint32FromLittleEndian(usbControlTransferPtr+12); buflen = uint32FromLittleEndian(usbControlTransferPtr+16); bufptr = uint32FromLittleEndian(usbControlTransferPtr+20); ETH_DEV_DBG_INFO("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr); if (buflen > 0) { //ETH_DEV_DBG_INFO("parameters???"); //int iii; //for (iii=0; iii<usbRequest.length; iii++) // ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]); //while(1); } if (buflen+28 != len) { ETH_DEV_DBG_INFO("wrong size?"); int iii; for (iii=0; iii<usbRequest.length; iii++) ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]); while(1); } if (buflen>0 && bufptr != 28-8) { ETH_DEV_DBG_INFO("wrong offset?"); int iii; for (iii=0; iii<usbRequest.length; iii++) ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]); while(1); } uint32ToLittleEndian(0x80000004,rndisResponse); /* INITIALIZE_CMPLT */ uint32ToLittleEndian(id,rndisResponse+8); /* request id to which we are responding */ rndisResponseLen = 24; uint32_t response_size = 0; switch (oid) { case OID_GEN_SUPPORTED_LIST: rndisResponseLen += sizeof(rndisSupportedOIDs); memcpy(rndisResponse + 24, rndisSupportedOIDs, sizeof(rndisSupportedOIDs)); break; case OID_GEN_PHYSICAL_MEDIUM: rndisResponseLen += sizeof(uint32_t); /* Indicate that the device is a true ethernet link */ uint32ToLittleEndian(0,rndisResponse+24); break; case OID_GEN_HARDWARE_STATUS: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(0 /* ready */,rndisResponse+24); break; case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(REMOTE_NDIS_MEDIUM_802_3,rndisResponse+24); break; case OID_GEN_VENDOR_ID: rndisResponseLen += sizeof(uint32_t); /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ uint32ToLittleEndian(0x00FFFFFF,rndisResponse+24); break; case OID_GEN_MAXIMUM_TOTAL_SIZE: rndisResponseLen += sizeof(uint32_t); /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ uint32ToLittleEndian(11*4 + ETHERNET_FRAME_SIZE_MAX,rndisResponse+24); break; case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: case OID_GEN_MAXIMUM_FRAME_SIZE: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(ETHERNET_FRAME_SIZE_MAX,rndisResponse+24); //uint32ToLittleEndian(256,rndisResponse+24); break; //case OID_GEN_TRANSMIT_BLOCK_SIZE: //case OID_GEN_RECEIVE_BLOCK_SIZE: // rndisResponseLen += sizeof(uint32_t); // uint32ToLittleEndian(102 /* from contiki */,rndisResponse+24); // break; case OID_GEN_VENDOR_DESCRIPTION: rndisResponseLen += 16; memcpy(rndisResponse+24, "Sivan Toledo\0\0\0\0",16); break; case OID_GEN_MEDIA_CONNECT_STATUS: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(REMOTE_NDIS_MEDIA_STATE_CONNECTED,rndisResponse+24); break; case OID_GEN_LINK_SPEED: rndisResponseLen += sizeof(uint32_t); /* Indicate 10Mb/s link speed */ uint32ToLittleEndian(100000,rndisResponse+24); //DBG("get link speed"); break; case OID_802_3_PERMANENT_ADDRESS: case OID_802_3_CURRENT_ADDRESS: rndisResponseLen += 6; // mac address memcpy(rndisResponse + 24, "\x22\x33\x44\x55\x66\x77", 6); // MAC address reused from some old Meraki Mini //memcpy(rndisResponse + 24, "\x00\x18\x0A\x01\xDF\x44", 6); break; case OID_802_3_MAXIMUM_LIST_SIZE: rndisResponseLen += sizeof(uint32_t); /* Indicate only one multicast address supported */ uint32ToLittleEndian(1,rndisResponse+24); break; case OID_GEN_CURRENT_PACKET_FILTER: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(rndisCurrentPacketFilter,rndisResponse+24); break; case OID_GEN_RCV_ERROR: case OID_GEN_XMIT_ERROR: case OID_GEN_RCV_NO_BUFFER: case OID_802_3_MAC_OPTIONS: case OID_802_3_RCV_ERROR_ALIGNMENT: case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: rndisResponseLen += sizeof(uint32_t); /* Unused statistic OIDs - always return 0 for each */ uint32ToLittleEndian(0,rndisResponse+24); break; case OID_GEN_RCV_OK: // received by the interface means we sent the packet to teh host. rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(rndisTxPackets,rndisResponse+24); break; case OID_GEN_XMIT_OK: rndisResponseLen += sizeof(uint32_t); uint32ToLittleEndian(rndisRxPackets,rndisResponse+24); break; case OID_802_3_MULTICAST_LIST: rndisResponseLen += sizeof(uint32_t); /* from Linux drivers/gadget */ uint32ToLittleEndian(0xE0000000,rndisResponse+24); break; default: break; } if (rndisResponseLen == 24) { DBG("No response to query!?!"); DBG("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr); uint32ToLittleEndian(RNDIS_STATUS_NOT_SUPPORTED,rndisResponse+12); /* status */ //uint32ToLittleEndian(RNDIS_STATUS_FAILURE,rndisResponse+12); /* status */ uint32ToLittleEndian(0,rndisResponse+16); /* buffer length */ uint32ToLittleEndian(0,rndisResponse+20); /* buffer ptr */ } else { ETH_DEV_DBG_INFO("response with %d bytes",rndisResponseLen); uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */ uint32ToLittleEndian(rndisResponseLen-24,rndisResponse+16); /* buffer length */ uint32ToLittleEndian(24-8,rndisResponse+20); /* buffer ptr */ } uint32ToLittleEndian(rndisResponseLen,rndisResponse+4); /* length */ // xxx wrong!!! rndisResponseReady = 1; eth_nak_interrupts |= INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); //usbEnableNAKInterrupts(INACK_II); break; case 0x05: /* REMOTE_NDIS_SET_MSG */ uint32ToLittleEndian(0x80000005,rndisResponse); /* INITIALIZE_CMPLT */ uint32ToLittleEndian(16,rndisResponse+4); /* length */ uint32ToLittleEndian(id,rndisResponse+8); /* request id to which we are responding */ uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */ rndisResponseLen = 16; oid = uint32FromLittleEndian(usbControlTransferPtr+12); buflen = uint32FromLittleEndian(usbControlTransferPtr+16); bufptr = uint32FromLittleEndian(usbControlTransferPtr+20); ETH_DEV_DBG_INFO("SET OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr); switch (oid) { case OID_GEN_CURRENT_PACKET_FILTER: // the 8 byte offset is for the header, which is the first two words in the message rndisCurrentPacketFilter = uint32FromLittleEndian(usbControlTransferPtr+8+bufptr); ETH_DEV_DBG_INFO("packet filter = %x",rndisCurrentPacketFilter); if (rndisCurrentPacketFilter) rndisState = RNDIS_DATA_INITIALIZED; else rndisState = RNDIS_INITIALIZED; break; case OID_802_3_MULTICAST_LIST: // do nothing break; default: ETH_DEV_DBG_INFO("cannot set this..."); while(1); break; } rndisResponseReady = 1; eth_nak_interrupts |= INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); //usbEnableNAKInterrupts(INACK_II); break; case 0x06: /* RESET */ ETH_DEV_DBG_INFO("RESET"); DBG("rndis RESET"); //while (1); // for testing uint32ToLittleEndian(0x80000006,rndisResponse); /* INITIALIZE_CMPLT */ uint32ToLittleEndian(16,rndisResponse+4); /* length */ uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+8); /* status */ uint32ToLittleEndian(0,rndisResponse+8); /* addressing reset: no, don't send again */ rndisResponseLen = 16; rndisResponseReady = 1; eth_nak_interrupts |= INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); //usbEnableNAKInterrupts(INACK_II); rndisReset(); break; case 0x07: /* INDICATE_STATUS */ // wrong direction; we need to send this to the host... ETH_DEV_DBG_INFO("INDICATE STATUS"); break; case 0x08: /* KEEPALIVE */ ETH_DEV_DBG_INFO("KEEPALIVE"); uint32ToLittleEndian(0x80000008,rndisResponse); /* INITIALIZE_CMPLT */ uint32ToLittleEndian(12,rndisResponse+4); /* length */ uint32ToLittleEndian(id,rndisResponse+8); /* request id to which we are responding */ rndisResponseReady = 1; eth_nak_interrupts |= INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); break; default: ETH_DEV_DBG_INFO("class control request=%x interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type)); ETH_DEV_DBG_INFO("RNDIS request type = %x len=%u id=%u\n",type,len,id); break; } return TRUE; }
void usb_rndis_rx(uint8_t ep, uint8_t stat) { int len; int ip_length; int i; uint16_t eth_hdr_type; if (!(stat & EP_STATUS_DATA)) { ETH_DEV_DBG_ERROR("rndis rx, no data..."); return; } //DBG("rndis rx ep-state=%x state=%d packetsize=%d transferred=%d",stat,rndisRxState,rndisRxPacketSize,rndisRxTransferCount); switch (rndisRxState) { case RNDIS_RX_IDLE: //if (rndisRxState == RNDIS_RX_IDLE) { len = usbRead(ep, rndisPacketHeader, 64); if (len==1 && rndisPacketHeader[0] == 0) { DBG("single byte USB packet (this is normal for rndis"); return; } if (len < 44) { ETH_DEV_DBG_ERROR("Whoops, USB packet length shorter than RNDIS message header (only %d bytes)",len); return; } uint32_t type = uint32FromLittleEndian(rndisPacketHeader); uint32_t rndislen = uint32FromLittleEndian(rndisPacketHeader+4); uint32_t dataoff = uint32FromLittleEndian(rndisPacketHeader+8); uint32_t datalen = uint32FromLittleEndian(rndisPacketHeader+12); uint32_t ooboff = uint32FromLittleEndian(rndisPacketHeader+16); uint32_t ooblen = uint32FromLittleEndian(rndisPacketHeader+20); uint32_t numoob = uint32FromLittleEndian(rndisPacketHeader+24); uint32_t perpacket_infooff = uint32FromLittleEndian(rndisPacketHeader+28); uint32_t perpacket_infolen = uint32FromLittleEndian(rndisPacketHeader+32); //DBG("rndis rx type=%x len=%d dataoff=%d datalen=%d ooblen=%d numoob=%d perpacket_infooff=%d perpacket_infolen=%d", // type,len,dataoff,datalen,ooblen,numoob,perpacket_infooff,perpacket_infolen); if (type != 1) while(1); rndisRxTransferCount = 0; rndisRxPacketSize = datalen; /* hopefully, it follows the header immediately... */ if (receive_packet == 0) { if (RING_IS_FULL(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) { DBG("usb_eth_rx: receive ring is full, head=%d, tail=%d",receive_ring_head, receive_ring_tail); rndisRxState = RNDIS_RX_DROP; for (i=0; i<(len-44); i++) { rndisRxTransferCount++; } } else { rndisRxState = RNDIS_RX_RECV; receive_packet = &receive_ring[receive_ring_tail]; packet_init(receive_packet); for (i=0; i<(len-44); i++) { (receive_packet->data)[ rndisRxTransferCount ] = rndisPacketHeader[44+i]; rndisRxTransferCount++; } } } break; case RNDIS_RX_DROP: //if (rndisRxState == RNDIS_RX_DROP) { len = usbRead(ep, NULL, rndisRxPacketSize - rndisRxTransferCount); //ETH_DEV_DBG_INFO("rndis rx read %d bytes more in drop state",len); if (len >= 0) rndisRxTransferCount += len; break; // } case RNDIS_RX_RECV: //if (rndisRxState == RNDIS_RX_RECV) { //DBG("rndis rx recv read from endpoint"); len = usbRead(ep, (receive_packet->data) + rndisRxTransferCount, rndisRxPacketSize - rndisRxTransferCount); //DBG("rndis rx read %d bytes more in recv state",len); if (len >= 0) rndisRxTransferCount += len; break; } if (rndisRxTransferCount == rndisRxPacketSize) { rndisRxPackets++; DBG("rndis rx done with a packet (%d bytes)",rndisRxPacketSize); //for (i=0; i<rndisRxPacketSize; i++) DBG("%d %02x",i,(receive_packet->data)[i]); //if (rndisRxPacketSize==54) while(1); if (rndisRxState == RNDIS_RX_RECV) { receive_packet->size = rndisRxPacketSize; receive_packet = 0; RING_INC(receive_ring_tail, RECEIVE_RING_SIZE); xxx = 1; } rndisRxState = RNDIS_RX_IDLE; } }