Benjamin-Dobell / Heimdall

Heimdall is a cross-platform open-source tool suite used to flash firmware (aka ROMs) onto Samsung Galaxy devices.
MIT License
2.58k stars 585 forks source link

sorry, donot know how to notify the fix #237

Open iamtag opened 9 years ago

iamtag commented 9 years ago

./Heimdall/heimdall/source/BridgeManager.cpp line=932,50-64 74%

<-success = ReceivePacket(receiveFilePartPacket, receiveEmptyTransferFlags); ->success = ReceivePacket(receiveFilePartPacket, kDefaultTimeOutEmptyTransfer, receiveEmptyTransferFlags);

./Heimdall/heimdall/source/BridgeManager.cpp line=747,7-21 59%

<-if (ReceiveBulkTransfer(null, 0, kDefaultTimeoutEmptyTransfer, false) < 0 && verbose) -> //in my side receivebulktransfer to a null buffer will get a error. unsigned char szTempBuffer[16]; if (ReceiveBulkTransfer(szTempBuffer, 16, kDefaultTimeoutEmptyTransfer, false)<0 && verbose)

Benjamin-Dobell commented 9 years ago
./Heimdall/heimdall/source/BridgeManager.cpp
line=932,50-64 74%

<-success = ReceivePacket(receiveFilePartPacket, receiveEmptyTransferFlags);
->success = ReceivePacket(receiveFilePartPacket, kDefaultTimeOutEmptyTransfer, receiveEmptyTransferFlags);

Thanks, this was actually already reported https://github.com/Benjamin-Dobell/Heimdall/issues/232 - I'll push a commit fixing it shortly.

./Heimdall/heimdall/source/BridgeManager.cpp
line=747,7-21 59%

<-if (ReceiveBulkTransfer(null, 0, kDefaultTimeoutEmptyTransfer, false) < 0 && verbose)
->
//in my side receivebulktransfer to a null buffer will get a error.
unsigned char szTempBuffer[16];
if (ReceiveBulkTransfer(szTempBuffer, 16, kDefaultTimeoutEmptyTransfer, false)<0 && verbose)

This does not seem correct. You've replaced an intentionally 0-length transfer with a 16-byte transfer.

iamtag commented 9 years ago

in my hand, the SM-G7108 must got a receivebulktransfer 0-length transfer here. so request 16bytes will got 0bytes return. xx

iamtag commented 9 years ago

x2 Here is odin what to do.

Benjamin-Dobell commented 9 years ago

@iamtag Okay, that does seem a bit strange as the buffer size shouldn't really make a difference given that we are expecting a 0-byte response.

Nonetheless, I'll test the change out on all the devices I have to make sure it doesn't break support for those. If all tested devices work with the change, then I'll commit it to the repo.

Thanks

iamtag commented 9 years ago

I had usblog i9100g, i879, sh-g7108, i9500 by odin. The flow of sendEmptyTransferFlags/receiveEmptyTransferFlags has a little diffs. I don't know Odin how to detect this diffs in the same flash flow.

iamtag commented 9 years ago

@Benjamin-Dobell I have send a mail to you(service@glassechidna.com.au). There are 5 models odin flash usblogs.

iamtag commented 9 years ago

@Benjamin-Dobell There are 2 case at flashing diffrent model phone.

One is:

->ODIN <-LOKE ->[BEGIN SESSION] <-[SESSION RESPONSE] ->NULL ->[CHANGE FILE PACK SIZE] <-[RESPONSE SUCCED] ->NULL ->[TOTAL BYTES] <-[RESPONSE SUCCED] //TAG:!!!<---diff begin here ->NULL ->[CMD1] <-[RESONSE...] ->NULL ->[CMD2] <-[RESPONSE...] ... It is use SendPacket(kEmptyTransferBefore) after TAG.

The other case:

->ODIN <-LOKE ->[BEGIN SESSION] <-[SESSION RESPONSE] ->NULL ->[CHANGE FILE PACK SIZE] <-[RESPONSE SUCCED] ->NULL ->[TOTAL BYTES] ->NULL //TAG:!!!<---diff begin here <-[RESPONSE SUCCED]
->[CMD1] ->NULL <-[RESONSE...] ->[CMD2] ->NULL <-[RESPONSE...] ... It is use SendPacket(kEmptyTransferAfter) after TAG.


I use below solution to detect this differents.

enum
{
    kEmptyTransferNone = 0,
    kEmptyTransferBefore = 1,
    kEmptyTransferAfter = 1 << 1,
    kEmptyTransferBeforeAndAfter = kEmptyTransferBefore | kEmptyTransferAfter,
    //use default setting every call                
    kEmptyTransferBySetting = 0x100,
    //call kEmptyTransferBeforeAndAfter in SEND_TOTAL_BYTES of flow, 
    //if fail at after, it's only support kEmptyTransferBefore
    //else only support kEmptyTransferAfter
    kEmptyTransferSetSetting = kEmptyTransferBeforeAndAfter | kEmptyTransferBySetting,
};

bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout, int emptyTransferFlags) const
{
    static int g_defaultEmptyTransferFlags = kEmptyTransferBefore;

    if (kEmptyTransferBySetting == emptyTransferFlags)
    {
        emptyTransferFlags = g_defaultEmptyTransferFlags;
    }

    packet->Pack();

    if (emptyTransferFlags & kEmptyTransferBefore)
    {
        if (!SendBulkTransfer(nullptr, 0, kDefaultTimeoutEmptyTransfer, false) && verbose)
        {
            Interface::PrintWarning("Empty bulk transfer before sending packet failed. Continuing anyway...\n");
        }
    }

    if (!SendBulkTransfer(packet->GetData(), packet->GetSize(), timeout))
        return (false);

    if (emptyTransferFlags & kEmptyTransferAfter)
    {
        const bool bRET = SendBulkTransfer(nullptr, 0, kDefaultTimeoutEmptyTransfer, false);
        if (!bRET && verbose)
        {
            Interface::PrintWarning("Empty bulk transfer after sending packet failed. Continuing anyway...\n");
        }
        if (kEmptyTransferSetSetting == emptyTransferFlags)
        {
            g_defaultEmptyTransferFlags = (bRET ? kEmptyTransferAfter : kEmptyTransferBefore);
            Interface::PrintWarning("Setting protocol to %d\n", g_defaultEmptyTransferFlags);           
        }
    }

    return (true);
}

//change default to kEmptyTransferBySetting
bool SendPacket(OutboundPacket *packet, int timeout = kDefaultTimeoutSend, int emptyTransferFlags = kEmptyTransferBySetting) const;

//update beginsession use kEmptyTransferNone
bool BridgeManager::BeginSession(void)
{
    Interface::Print("Beginning session...\n");

    BeginSessionPacket beginSessionPacket;
    //***** BEGIN SESSION *****
    if (!SendPacket(&beginSessionPacket, kDefaultTimeoutSend, kEmptyTransferNone))
    {
        Interface::PrintError("Failed to begin session!\n");
        return (false);
    }

    SessionSetupResponse beginSessionResponse;
    if (!ReceivePacket(&beginSessionResponse))
        return (false);

    unsigned int deviceDefaultPacketSize = beginSessionResponse.GetResult();

    Interface::Print("\nSome devices may take up to 2 minutes to respond.\nPlease be patient!\n\n");
    Sleep(3000); // Give the user time to read the message.

    if (deviceDefaultPacketSize != 0) // 0 means changing the packet size is not supported.
    {
        fileTransferSequenceTimeout = 120000; // 2 minutes!
        fileTransferPacketSize = 1048576; // 1 MiB
        fileTransferSequenceMaxLength = 30; // Therefore, fileTransferPacketSize * fileTransferSequenceMaxLength == 30 MiB per sequence.

        FilePartSizePacket filePartSizePacket(fileTransferPacketSize);
        //***** CHANGE FILE PACK SIZE *****
        if (!SendPacket(&filePartSizePacket, kDefaultTimeoutSend, kEmptyTransferBefore))
        {
            Interface::PrintError("Failed to send file part size packet!\n");
            return (false);
        }

        SessionSetupResponse filePartSizeResponse;

        if (!ReceivePacket(&filePartSizeResponse))
            return (false);

        if (filePartSizeResponse.GetResult() != 0)
        {
            Interface::PrintError("Unexpected file part size response!\nExpected: 0\nReceived: %d\n", filePartSizeResponse.GetResult());
            return (false);
        }
    }

    Interface::Print("Session begun.\n\n");
    return (true);
}

//in here to detect the differents and store it
static bool sendTotalTransferSize(BridgeManager *bridgeManager, const vector<PartitionFile>& partitionFiles, FILE *pitFile, bool repartition)
{
    unsigned int totalBytes = 0;

    for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
    {
        FileSeek(it->file, 0, SEEK_END);
        totalBytes += (unsigned int)FileTell(it->file);
        FileRewind(it->file);
    }

    if (repartition)
    {
        FileSeek(pitFile, 0, SEEK_END);
        totalBytes += (unsigned int)FileTell(pitFile);
        FileRewind(pitFile);
    }

    bool success;

    TotalBytesPacket *totalBytesPacket = new TotalBytesPacket(totalBytes);
    //***** SEND TOTAL BYTES *****
    success = bridgeManager->SendPacket(totalBytesPacket, 
        BridgeManager::kDefaultTimeoutSend, 
        BridgeManager::kEmptyTransferSetSetting);
.........
}
PaulSzymanski commented 9 years ago

System: Archlinux Smartphone: Samsung Galaxy S3 NFC

$ heimdall flash --RECOVERY recovery.img --no-reboot --verbose

Heimdall v1.4.1

Copyright (c) 2010-2014 Benjamin Dobell, Glass Echidna http://www.glassechidna.com.au/

This software is provided free of charge. Copying and redistribution is encouraged.

If you appreciate this software and you would like to support future development please consider donating: http://www.glassechidna.com.au/donate/

Initialising connection... Detecting device... Manufacturer: "SAMSUNG" Product: "Gadget Serial"

        length: 18
  device class: 2
           S/N: 0
       VID:PID: 04E8:685D
     bcdDevice: 021B

iMan:iProd:iSer: 1:2:0 nb confs: 1

interface[0].altsetting[0]: num endpoints = 1 Class.SubClass.Protocol: 02.02.01 endpoint[0].address: 83 max packet size: 0010 polling interval: 09

interface[1].altsetting[0]: num endpoints = 2 Class.SubClass.Protocol: 0A.00.00 endpoint[0].address: 81 max packet size: 0200 polling interval: 00 endpoint[1].address: 02 max packet size: 0200 polling interval: 00 Claiming interface... Setting up interface...

Initialising protocol... ERROR: Failed to receive handshake response. Result: -7 ERROR: Protocol initialisation failed!

Releasing device interface...