signed EmulateHost (struct plc * plc) { struct channel * channel = (struct channel *)(plc->channel); struct message * message = (struct message *)(plc->message); static char const * actions [] = { "start device", "store firmware", "store parameters", "update host", "config memory", "restore defaults", "unknown" }; #ifndef __GNUC__ #pragma pack (push,1) #endif struct __packed vs_host_action_ind { struct ethernet_hdr ethernet; struct qualcomm_hdr qualcomm; uint8_t MACTION; uint8_t MAJOR_VERSION; uint8_t MINOR_VERSION; } * indicate = (struct vs_host_action_ind *) (message); #if 0 struct __packed vs_host_action_rsp { struct ethernet_hdr ethernet; struct qualcomm_hdr qualcomm; uint8_t MSTATUS; } * response = (struct vs_host_action_rsp *) (message); #endif #ifndef __GNUC__ #pragma pack (pop) #endif struct nvm_header1 nvm_header; struct pib_header pib_header; uint32_t offset; char const * PIB = plc->PIB.name; char const * NVM = plc->NVM.name; signed timer = channel->timeout; signed status = 0; Request (plc, "Waiting for Host Action"); while (1) { channel->timeout = plc->timer; status = ReadMME (plc, 0, (VS_HOST_ACTION | MMTYPE_IND)); channel->timeout = timer; if (status < 0) { break; } if (status > 0) { printf ("\n"); if (indicate->MACTION < (sizeof (actions) / sizeof (char const *))) { Confirm (plc, "Host Action Request is (%d) %s.", indicate->MACTION, actions [indicate->MACTION]); } else { error (0, ENOTSUP, "Host Action 0x%0X", indicate->MACTION); continue; } memcpy (channel->peer, indicate->ethernet.OSA, sizeof (channel->peer)); channel->timeout = timer; if (indicate->MACTION == 0x00) { unsigned module = 0; char firmware [PLC_VERSION_STRING]; if (HostActionResponse (plc)) { return (-1); } if (lseek (plc->PIB.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->PIB.name); } if (read (plc->PIB.file, &pib_header, sizeof (pib_header)) != sizeof (pib_header)) { error (1, errno, FILE_CANTREAD, plc->PIB.name); } if (lseek (plc->PIB.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->PIB.name); } if (BE16TOH (*(uint16_t *)(&pib_header)) < 0x0305) { offset = LEGACY_PIBOFFSET; } else if (BE16TOH (*(uint16_t *)(&pib_header)) < 0x0500) { offset = INT6x00_PIBOFFSET; } else { offset = AR7x00_PIBOFFSET; } if (WriteMEM (plc, &plc->PIB, 0, offset, LE16TOH (pib_header.PIBLENGTH))) { return (-1); } if (lseek (plc->NVM.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->NVM.name); } if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { error (1, errno, FILE_CANTREAD, plc->NVM.name); } while (nvm_header.NEXTHEADER) { lseek (plc->NVM.file, LE32TOH (nvm_header.NEXTHEADER), SEEK_SET); if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { error (1, errno, FILE_CANTREAD, plc->NVM.name); } module++; } if (WriteFirmware1 (plc, module, &nvm_header)) { return (-1); } if (StartFirmware1 (plc, module, &nvm_header)) { return (-1); } if (WaitForStart (plc, firmware, sizeof (firmware))) { return (-1); } if (_anyset (plc->flags, PLC_FLASH_DEVICE)) { if (WriteNVM (plc)) { return (-1); } if (WritePIB (plc)) { return (-1); } if (FlashNVM (plc)) { return (-1); } } continue; } if (indicate->MACTION == 0x01) { if (HostActionResponse (plc)) { return (-1); } close (plc->NVM.file); if (ReadFirmware1 (plc)) { return (-1); } if ((plc->NVM.file = open (plc->NVM.name = plc->nvm.name, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->NVM.name); } if (ResetDevice (plc)) { return (-1); } continue; } if (indicate->MACTION == 0x02) { if (HostActionResponse (plc)) { return (-1); } close (plc->PIB.file); if (ReadParameters1 (plc)) { return (-1); } if ((plc->PIB.file = open (plc->PIB.name = plc->pib.name, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->PIB.name); } if (ResetDevice (plc)) { return (-1); } continue; } if (indicate->MACTION == 0x03) { if (HostActionResponse (plc)) { return (-1); } close (plc->NVM.file); if (ReadFirmware1 (plc)) { return (-1); } if ((plc->NVM.file = open (plc->NVM.name = plc->nvm.name, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->NVM.name); } close (plc->PIB.file); if (ReadParameters1 (plc)) { return (-1); } if ((plc->PIB.file = open (plc->PIB.name = plc->pib.name, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->PIB.name); } if (ResetDevice (plc)) { return (-1); } continue; } if (indicate->MACTION == 0x04) { #if 0 /* * Due to an omission in the INT6300 BootLoader, responding to this VS_HOST_ACTION * indication will suppress subsequent VS_HOST_ACTION messages and the device will * not request firmware and parameters; this may be corrected on the INT6400; */ if (HostActionResponse (plc)) { return (-1); } #endif if (WriteCFG (plc)) { return (-1); } /* * At this point, one could download firmware and parameters without waiting for * further requests from the device; however, we elect to wait for them since it * is 'good form'; a device should send code 0x00 within 10 seconds of this one; */ continue; } if (indicate->MACTION == 0x05) { if (HostActionResponse (plc)) { return (-1); } close (plc->NVM.file); if ((plc->NVM.file = open (plc->NVM.name = NVM, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->NVM.name); } close (plc->PIB.file); if ((plc->PIB.file = open (plc->PIB.name = PIB, O_BINARY|O_RDONLY)) == -1) { error (1, errno, "%s", plc->PIB.name); } if (ResetDevice (plc)) { return (-1); } continue; } error (0, ENOSYS, "Host Action 0x%0X", indicate->MACTION); } } return (0); }
signed ExecuteApplets1 (struct plc * plc) { unsigned module = 0; struct nvm_header1 nvm_header; if (lseek (plc->NVM.file, 0, SEEK_SET)) { if (_allclr (plc->flags, PLC_SILENCE)) { error (PLC_EXIT (plc), errno, FILE_CANTHOME, plc->NVM.name); } return (-1); } do { if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { if (_allclr (plc->flags, PLC_SILENCE)) { error (PLC_EXIT (plc), errno, NVM_HDR_CANTREAD, plc->NVM.name, module); } return (-1); } if (LE32TOH (nvm_header.HEADERVERSION) != 0x60000000) { if (_allclr (plc->flags, PLC_SILENCE)) { error (PLC_EXIT (plc), 0, NVM_HDR_VERSION, plc->NVM.name, module); } return (-1); } if (checksum32 (&nvm_header, sizeof (nvm_header), 0)) { if (_allclr (plc->flags, PLC_SILENCE)) { error (PLC_EXIT (plc), 0, NVM_HDR_CHECKSUM, plc->NVM.name, module); } return (-1); } if (plc->hardwareID < CHIPSET_AR7400) { if (WriteFirmware1 (plc, module, &nvm_header)) { return (-1); } if (StartFirmware1 (plc, module, &nvm_header)) { return (-1); } } else { if (WriteExecuteFirmware1 (plc, module, &nvm_header)) { return (-1); } } if (_anyset (plc->flags, PLC_QUICK_FLASH)) { break; } while (!ReadMME (plc, 0, (VS_HOST_ACTION | MMTYPE_IND))); module++; } while (nvm_header.NEXTHEADER); return (0); }
signed BootFirmware1 (struct plc * plc) { unsigned module = 0; struct nvm_header1 nvm_header; if (lseek (plc->NVM.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->NVM.name); } do { if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { error (PLC_EXIT (plc), errno, NVM_HDR_CANTREAD, plc->NVM.name, module); } if (LE32TOH (nvm_header.HEADERVERSION) != 0x60000000) { error (PLC_EXIT (plc), ECANCELED, NVM_HDR_VERSION, plc->NVM.name, module); } if (checksum32 (&nvm_header, sizeof (nvm_header), 0)) { error (PLC_EXIT (plc), ECANCELED, NVM_HDR_CHECKSUM, plc->NVM.name, module); } #if 0 if (_anyset (LE16TOH (nvm_header.IGNOREMASK), (1 << (plc->hardwareID - 1)))) { if (lseek (plc->NVM.file, LE32TOH (nvm_header.NEXTHEADER), SEEK_SET) == -1) { error (PLC_EXIT (plc), errno, "Can't skip module: %s (%d)", plc->NVM.name, module); } } else #endif if (nvm_header.IMAGETYPE == NVM_IMAGE_FIRMWARE) { if (plc->hardwareID < CHIPSET_AR7400) { if (WriteFirmware1 (plc, module, &nvm_header)) { return (-1); } if (StartFirmware1 (plc, module, &nvm_header)) { return (-1); } break; } if (WriteExecuteFirmware1 (plc, module, &nvm_header)) { return (-1); } break; } if (lseek (plc->NVM.file, LE32TOH (nvm_header.NEXTHEADER), SEEK_SET) == -1) { error (PLC_EXIT (plc), errno, "Can't skip module: %s (%d)", plc->NVM.name, module); } module++; } while (nvm_header.NEXTHEADER); return (0); }
int StartDevice1 (struct plc * plc) { unsigned module = 0; struct nvm_header1 nvm_header; struct pib_header pib_header; uint32_t offset; if (WriteCFG (plc)) { return (-1); } if (lseek (plc->NVM.file, 0, SEEK_SET)) { error (PLC_EXIT (plc), errno, FILE_CANTHOME, plc->NVM.name); return (-1); } if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { error (PLC_EXIT (plc), errno, FILE_CANTREAD, plc->NVM.name); return (-1); } while (nvm_header.NEXTHEADER) { if (lseek (plc->NVM.file, LE32TOH (nvm_header.NEXTHEADER), SEEK_SET) == -1) { error (PLC_EXIT (plc), errno, FILE_CANTHOME, plc->NVM.name); return (-1); } if (read (plc->NVM.file, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header)) { error (PLC_EXIT (plc), errno, FILE_CANTREAD, plc->NVM.name); return (-1); } module++; } if (lseek (plc->PIB.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->PIB.name); } if (read (plc->PIB.file, &pib_header, sizeof (pib_header)) != sizeof (pib_header)) { error (1, errno, FILE_CANTREAD, plc->PIB.name); } if (lseek (plc->PIB.file, 0, SEEK_SET)) { error (1, errno, FILE_CANTHOME, plc->PIB.name); } if (BE16TOH (*(uint16_t *)(&pib_header)) < 0x0305) { offset = LEGACY_PIBOFFSET; } else if (BE16TOH (*(uint16_t *)(&pib_header)) < 0x0500) { offset = INT6x00_PIBOFFSET; } else { offset = AR7x00_PIBOFFSET; } if (WriteMEM (plc, &plc->PIB, 0, offset, LE16TOH (pib_header.PIBLENGTH))) { return (-1); } if (WriteFirmware1 (plc, module, &nvm_header)) { return (-1); } if (StartFirmware1 (plc, module, &nvm_header)) { return (-1); } if (lseek (plc->NVM.file, 0, SEEK_SET)) { error (PLC_EXIT (plc), errno, FILE_CANTHOME, plc->NVM.name); return (-1); } return (0); }