0

I am trying to create a software simulation on an Ubuntu GNU/Linux machine which will work like PPPoE. I would like this simulator to take outgoing packets, strip off the ethernet header, insert the PPP flags (7E, FF, 03, 00, and 21) and place the IP layer information in the PPP packet. I am having trouble with the FCS that goes after the data. From what I can tell, the cell modem I am using has a 2 byte FCS using the CRC16-CCITT method. I have found several pieces of software that will calculate this checksum, but none of them produce what is coming out the serial line (I have a serial line "sniffer" that shows me everything the modem is being sent).

I have been looking into the source of pppd and the linux kernel itself, and I can see that both of them have a method of adding an FCS to the data. It seems quite difficult to implement, as I have no experience in kernel hacking. Can someone come up with a simple way (preferably in Python) of calculating an FCS that matches the one that the kernel produces?

Thanks.

P.S. If anyone wants, I can add a sample of the data output I am getting to the serial modem.

J Sin
  • 1
  • 1
  • 1

3 Answers3

2

Used simple python library crcmod.

import crcmod   #pip3 install crcmod
fcsData = "A0 19 03 61 DC"
fcsData=''.join(fcsData.split(' '))
print(fcsData)
crc16 = crcmod.mkCrcFun(0x11021, rev=True,initCrc=0x0000, xorOut=0xFFFF)
print(hex(crc16(bytes.fromhex(fcsData))))
fcs=hex(crc16(bytes.fromhex(fcsData)))
Manish Gupta
  • 672
  • 6
  • 10
0

Got this from mbed.org PPP-Blinky:

// http://www.sunshine2k.de/coding/javascript/crc/crc_js.html - Correctly calculates
// the 16-bit FCS (crc) on our frames (Choose CRC16_CCITT_FALSE)

int crc;

void crcReset()
{
    crc=0xffff;   // crc restart
}

void crcDo(int x) // cumulative crc
{
    for (int i=0; i<8; i++) {
        crc=((crc&1)^(x&1))?(crc>>1)^0x8408:crc>>1; // crc calculator
        x>>=1;
    }
}

int crcBuf(char * buf, int size) // crc on an entire block of memory
{
    crcReset();
    for(int i=0; i<size; i++)crcDo(*buf++);
    return crc;
}
neonzeon
  • 197
  • 5
0

I recently did something like this while testing code to kill a ppp connection .. This worked for me:

# RFC 1662 Appendix C

def mkfcstab():
    P = 0x8408

    def valiter():
        for b in range(256):
            v = b
            i = 8
            while i:
                v = (v >> 1) ^ P if v & 1 else v >> 1
                i -= 1

            yield v & 0xFFFF

    return tuple(valiter())

fcstab = mkfcstab()

PPPINITFCS16 = 0xffff  # Initial FCS value
PPPGOODFCS16 = 0xf0b8  # Good final FCS value

def pppfcs16(fcs, bytelist):
    for b in bytelist:
        fcs = (fcs >> 8) ^ fcstab[(fcs ^ b) & 0xff]
    return fcs

To get the value:

fcs = pppfcs16(PPPINITFCS16, (ord(c) for c in frame)) ^ 0xFFFF

and swap the bytes (I used chr((fcs & 0xFF00) >> 8), chr(fcs & 0x00FF))

derekerdmann
  • 17,696
  • 11
  • 76
  • 110
cwa
  • 1,092
  • 9
  • 12