package firmware import ( "bytes" "encoding/binary" "errors" "github.com/go-playground/log/v8" "hash/crc32" "io" "io/ioutil" "os" "path" ) // FwExists check if file exists func FwExists(path string) bool { _, err := os.Stat(path) return !errors.Is(err, os.ErrNotExist) } // ChkHeader: runs header and CRC checks on the firmware file func ChkHeader(fwfile string) error { log.Info("checking ", fwfile) // SCS has two different file layouts, one for the "Dragons", the other for any older modem var offset uint32 if path.Ext(fwfile) == ".dr7" { offset = 0 } else { offset = 4 } r, err := os.Open(fwfile) if err != nil { return err } defer r.Close() var header [2]byte _, err = io.ReadFull(r, header[:]) if err != nil { return err } if offset == 0 { if header != [2]byte{0x50, 0x34} { return errors.New("ERROR: wrong firmware header") } } else { if header != [2]byte{0x60, 0xea} { return errors.New("ERROR: wrong firmware header") } } r.Close() firmware, err := ioutil.ReadFile(fwfile) if err != nil { return errors.New("ERROR: ReadFile operation failed") } var size uint32 if offset == 0 { size = binary.LittleEndian.Uint32(firmware[4:8]) // Dragons } else { size = uint32(binary.LittleEndian.Uint16(firmware[2:4])) // PTC-3 and Co } a := make([]byte, 4) binary.LittleEndian.PutUint32(a, crc32.ChecksumIEEE(firmware[offset:offset+size])) if bytes.Equal(a, firmware[offset+size:offset+size+4]) { log.Info("CRC checksum ok!") } else { return errors.New("CRC checksum NOT ok!") } return nil }