void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { struct usb_setup_packet *setup = (void *)usb_dc_stm32_state.pcd.Setup; struct usb_dc_stm32_ep_state *ep_state; LOG_DBG(""); ep_state = usb_dc_stm32_get_ep_state(EP0_OUT); /* can't fail for ep0 */ ep_state->read_count = SETUP_SIZE; ep_state->read_offset = 0U; memcpy(&usb_dc_stm32_state.ep_buf[EP0_IDX], usb_dc_stm32_state.pcd.Setup, ep_state->read_count); if (ep_state->cb) { ep_state->cb(EP0_OUT, USB_DC_EP_SETUP); if (!(setup->wLength == 0U) && !(REQTYPE_GET_DIR(setup->bmRequestType) == REQTYPE_DIR_TO_HOST)) { usb_dc_ep_start_read(EP0_OUT, usb_dc_stm32_state.ep_buf[EP0_IDX], setup->wLength); } } }
/************************************************************************* PreHandleRequest ================ Change data pointer for data out request Returns TRUE if the pointer was changed **************************************************************************/ static BOOL PreHandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) { if ((pSetup->wLength != 0) && (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_DEVICE) && (pSetup->bRequest == REQ_DATA_TRANSFER) && (*piLen <= write_ram_len)) { // directly write to the location given by WRITE_TO_RAM *ppbData = (U8*) write_ram_adr; return TRUE; } return FALSE; }
/** * Handles IN/OUT transfers on EP0 * * @param [in] bEP Endpoint address * @param [in] bEPStat Endpoint status */ void USBHandleControlTransfer(U8 bEP, U8 bEPStat) { int iChunk, iType; if (bEP == 0x00) { // OUT transfer if (bEPStat & EP_STATUS_SETUP) { // setup packet, reset request message state machine USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup)); DBG("S%x", Setup.bRequest); // defaults for data pointer and residue iType = REQTYPE_GET_TYPE(Setup.bmRequestType); pbData = apbDataStore[iType]; iResidue = Setup.wLength; iLen = Setup.wLength; if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { // ask installed handler to process request if (!_HandleRequest(&Setup, &iLen, &pbData)) { DBG("_HandleRequest1 failed\n"); StallControlPipe(bEPStat); return; } // send smallest of requested and offered length iResidue = MIN(iLen, Setup.wLength); // send first part (possibly a zero-length status message) DataIn(); } } else { if (iResidue > 0) { // store data iChunk = USBHwEPRead(0x00, pbData, iResidue); if (iChunk < 0) { StallControlPipe(bEPStat); return; } pbData += iChunk; iResidue -= iChunk; if (iResidue == 0) { // received all, send data to handler iType = REQTYPE_GET_TYPE(Setup.bmRequestType); pbData = apbDataStore[iType]; if (!_HandleRequest(&Setup, &iLen, &pbData)) { DBG("_HandleRequest2 failed\n"); StallControlPipe(bEPStat); return; } // send status to host DataIn(); } } else { // absorb zero-length status message iChunk = USBHwEPRead(0x00, NULL, 0); DBG(iChunk > 0 ? "?" : ""); } } } else if (bEP == 0x80) { // IN transfer // send more data if available (possibly a 0-length packet) DataIn(); } else { ASSERT(FALSE); } }
void USBCTRL::EPIntHandler(USBHW *u, uint8_t bEP, uint8_t bEPStatus) { iprintf("E0x%02X:0x%02X\t", bEP, bEPStatus); if (bEP == 0x00) { if (bEPStatus & EP_STATUS_SETUP) { // defaults for data pointer and residue HwEPRead(bEP, (uint8_t *) &Setup, sizeof(Setup)); uint8_t iType = REQTYPE_GET_TYPE(Setup.bmRequestType); pbData = &apbDataStore[iType][0]; iResidue = Setup.wLength; iLen = Setup.wLength; if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { switch(REQTYPE_GET_TYPE(Setup.bmRequestType)) { case REQTYPE_TYPE_STANDARD: { // iprintf("STDREQ:%02X,%02X,%04X,%04X,%04x\n", Setup.bmRequestType, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength); uint8_t r = 0; switch (REQTYPE_GET_RECIP(Setup.bmRequestType)) { case REQTYPE_RECIP_DEVICE: { iprintf("StdDevReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength); r = HandleStdDeviceReq(&Setup, &iLen, &pbData); iprintf("Reply:%d bytes, max this packet: %d\n", iLen, Setup.wLength); break; } case REQTYPE_RECIP_INTERFACE: { iprintf("StdIntReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength); r = HandleStdInterfaceReq(&Setup, &iLen, &pbData); break; } case REQTYPE_RECIP_ENDPOINT: { iprintf("StdEPReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength); r = HandleStdEndPointReq(&Setup, &iLen, &pbData); break; } case REQTYPE_RECIP_OTHER: { iprintf("StdReq?:RqType=%02x;Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bmRequestType, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength); break; } } if (!r) { iprintf("STALL!\n"); HwEPStall(0x80, TRUE); return; } iResidue = iLen; if (iResidue > Setup.wLength) iResidue = Setup.wLength; DataIn(); return; }; } } iprintf("Unknown Setup ReqType %d - ignored\n", Setup.bmRequestType); iprintf("bRequest: %d (0x%02X), wValue: %d, wIndex: %d (0x%X), wLength: %d\n", Setup.bRequest, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wIndex, Setup.wLength); iprintf("Dir: %s, ", (REQTYPE_GET_DIR(Setup.bmRequestType)?"Device->Host":"Host->Device")); if (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_DEVICE) { iResidue = Setup.wLength; } else { iResidue = 0; } switch (REQTYPE_GET_TYPE(Setup.bmRequestType)) { case REQTYPE_TYPE_STANDARD: iprintf("Type: Standard, "); break; case REQTYPE_TYPE_CLASS: iprintf("Type: Class , "); break; case REQTYPE_TYPE_VENDOR: iprintf("Type: Vendor , "); break; default: iprintf("Type: Reserved, "); break; } switch (REQTYPE_GET_RECIP(Setup.bmRequestType)) { case 0: iprintf("Recip: Device\n"); break; case 1: iprintf("Recip: Interface 0x%X\n", Setup.wIndex); break; case 2: iprintf("Recip: Endpoint 0x%X\n", Setup.wIndex); break; case 3: iprintf("Recip: Other\n"); break; default: iprintf("Recip: unknown\n"); break; } // if (REQTYPE_GET_TYPE(Setup.bmRequestType) == REQTYPE_TYPE_CLASS) { // // find interface // int i; // for (i = 0; descriptors[i] != ((usbdesc_base *) 0); i++) { // if ((descriptors[i]->bDescType == DT_INTERFACE) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_INTERFACE)) { // usbdesc_interface *inf = (usbdesc_interface *) descriptors[i]; // if (inf->bInterfaceNumber == Setup.wIndex) { // iprintf("Firing Interface's setup handler: %p\n", inf->setupReceiver); // if (inf->setupReceiver) { // inf->setupReceiver->SetupHandler(u, bEP, &Setup); // break; // } // } // } // if ((descriptors[i]->bDescType == DT_ENDPOINT) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_ENDPOINT)) { // usbdesc_endpoint *ep = (usbdesc_endpoint *) descriptors[i]; // if (ep->bEndpointAddress == bEP) { // iprintf("Firing Endpoint's setup handler: %p\n", ep->setupReceiver); // if (ep->setupReceiver) // ep->setupReceiver->SetupHandler(u, bEP, &Setup); // } // } // } // } } else { int iChunk; if (iResidue > 0) { // store data iChunk = HwEPRead(0x00, pbData, iResidue); iprintf("G:%db\n", iChunk); if (iChunk < 0) { HwEPStall(0x80, TRUE); return; } pbData += iChunk; iResidue -= iChunk; if (iResidue == 0) { // received all, send data to handler uint8_t iType = REQTYPE_GET_TYPE(Setup.bmRequestType); pbData = apbDataStore[iType]; iprintf("HANDLE 0x%02X with %db\n", iType, iLen); // if (!_HandleRequest(&Setup, &iLen, &pbData)) { // DBG("_HandleRequest2 failed\n"); // StallControlPipe(bEPStat); // return; // } // send status to host DataIn(); } } else { // absorb zero-length status message iChunk = HwEPRead(0x00, NULL, 0); iprintf("g%db\n", iChunk); // acknowledge HwEPWrite(0x80, 0, 0); // DBG(iChunk > 0 ? "?" : ""); } } if (REQTYPE_GET_TYPE(Setup.bmRequestType) == REQTYPE_TYPE_CLASS) { if ((iResidue == Setup.wLength) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { // find interface int i; for (i = 0; descriptors[i] != ((usbdesc_base *) 0); i++) { if ((descriptors[i]->bDescType == DT_INTERFACE) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_INTERFACE)) { usbdesc_interface *inf = (usbdesc_interface *) descriptors[i]; if (inf->bInterfaceNumber == Setup.wIndex) { iprintf("Firing Interface's setup handler: %p\n", inf->setupReceiver); if (inf->setupReceiver) { inf->setupReceiver->SetupHandler(u, bEP, &Setup); break; } } } if ((descriptors[i]->bDescType == DT_ENDPOINT) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_ENDPOINT)) { usbdesc_endpoint *ep = (usbdesc_endpoint *) descriptors[i]; if (ep->bEndpointAddress == bEP) { iprintf("Firing Endpoint's setup handler: %p\n", ep->setupReceiver); if (ep->setupReceiver) ep->setupReceiver->SetupHandler(u, bEP, &Setup); } } } } } } else if (bEP == 0x80) { DataIn(); } else { int i; usbdesc_base *descriptor; for (i = 0; i < 32; i++) { descriptor = descriptors[i]; if (descriptor->bDescType == DT_ENDPOINT) { usbdesc_endpoint *endpoint = (usbdesc_endpoint *) descriptor; if (endpoint->bEndpointAddress == bEP) { endpoint->callbackReceiver->EPIntHandler(u, bEP, bEPStatus); } } } } }
/************************************************************************* USBHandleControlTransfer ======================== Handles IN/OUT transfers on EP0 **************************************************************************/ void USBHandleControlTransfer(U8 bEP, U8 bEPStat) { int iChunk; if (bEP == 0x00) { // OUT transfer if (bEPStat & EP_STATUS_SETUP) { // setup packet, reset request message state machine USBHwEPRead(0x00, (U8 *)&Setup, &iLen); //mmmm DBG("S%x", Setup.bRequest); // defaults for data pointer and residue pbData = abControlData; iResidue = Setup.wLength; iLen = Setup.wLength; // ask installed handler to pre process request if (!_PreHandleRequest(&Setup, &iLen, &pbData)) { // silently ignore non installed handler } if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { // ask installed handler to process request if (!_HandleRequest(&Setup, &iLen, &pbData)) { DBG("_HandleRequest1 failed\n"); StallControlPipe(bEPStat); return; } // send smallest of requested and offered length iResidue = MIN(iLen, Setup.wLength); // send first part (possibly a zero-length status message) DataIn(); } if ((Setup.wLength != 0) && (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_DEVICE)) { if (!_PreHandleRequest(&Setup, &iLen, &pbData)) { // this is not a must, might fail } } } else { if (iResidue > 0) { // store data iChunk = 0; USBHwEPRead(0x00, pbData, &iChunk); pbData += iChunk; iResidue -= iChunk; if (iResidue == 0) { // received all, send data to handler // TODO set pointer correctly pbData = abControlData; if (!_HandleRequest(&Setup, &iLen, &pbData)) { StallControlPipe(bEPStat); DBG("_HandleRequest2 failed\n"); return; } // send status to host DataIn(); } } else { // absorb zero-length status message USBHwEPRead(0x00, NULL, &iChunk); DBG(iChunk > 0 ? "?" : ""); } } } else if (bEP == 0x80) { // IN transfer // send more data if available (possibly a 0-length packet) DataIn(); } else { ASSERT(FALSE); } }
/************************************************************************* HandleVendorRequest =================== **************************************************************************/ static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) { IAP func_entry; func_entry = (IAP) IAP_LOCATION; if (pSetup->wIndex != 0) { DBG("Invalid idx %X\n", pSetup->wIndex); return FALSE; } if (pSetup->wValue != 0) { DBG("Invalid val %X\n", pSetup->wValue); return FALSE; } switch (pSetup->bRequest) { // commands case REQ_IAP_COMMAND: /* fallthrough */ case REQ_ISP_COMMAND: /* fallthrough */ case REQ_BTL_COMMAND: if (pSetup->bRequest == REQ_IAP_COMMAND) func_entry = (IAP) IAP_LOCATION; if (pSetup->bRequest == REQ_ISP_COMMAND) func_entry = isp_entry; if (pSetup->bRequest == REQ_BTL_COMMAND) func_entry = btl_entry; if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) { // send result *ppbData = (U8*) rescmd; *piLen = 32; // TODO remove if (*piLen != 32) return FALSE; } else { // start command if (*piLen != 20) return FALSE; memcpy(&rescmd[3], *ppbData, 20); func_entry(&rescmd[3], rescmd); } break; // data transfer case REQ_DATA_TRANSFER: if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) { // check if data to read if (*piLen > read_mem_len) return FALSE; *ppbData = (U8*) read_mem_adr; read_mem_adr += *piLen; read_mem_len -= *piLen; } else { // data is already written, adjust pointers if (*piLen > write_ram_len) return FALSE; write_ram_adr += *piLen; write_ram_len -= *piLen; } break; default: DBG("Unhandled vendor\n"); return FALSE; } return TRUE; }
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; }