Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Computer Networks  Module 3 – Data link layer: framing and error detection

Link-layer services and framing

What the link layer does on each hop, and how framing marks where frames start and end, with length fields, PPP byte stuffing and HDLC bit stuffing.

  • Beginner
  • 25 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free: 25 minutes

What you will learn

  • List the services a link layer can provide: framing, addressing, error detection, flow control and medium access
  • Build frames from a byte stream with length fields, byte stuffing and bit stuffing
  • Explain which parts of the link layer run in NIC hardware, the driver and the operating system

Before you start

What you’ll learn · Before you start

What you will learn

  • List the services a link layer can provide: framing, addressing, error detection, flow control and medium access
  • Build frames from a byte stream with length fields, byte stuffing and bit stuffing
  • Explain which parts of the link layer run in NIC hardware, the driver and the operating system

Before you start

On this page

The link layer carries one frame across one link: from a laptop to its Wi-Fi access point, from a switch to a router, from one end of a fibre to the other. It never sees the whole path. Every hop runs its own link layer, so a packet that crosses the Internet travels in a new frame on every link it uses. The first job of any link layer is framing: the physical layer delivers a stream of bits, and the receiver has to work out where each frame starts and where it ends. This lesson lists the services a link layer can offer, shows where they run inside a computer, and builds the three classic ways of marking frames in Python: a length field, byte stuffing as PPP does it and bit stuffing as HDLC does it, with what each one costs.

The network layer hands the link layer a packet and the address of the next hop. What the link layer then does depends on the link, but the possible services are few:

  • Framing. It wraps the packet in a frame, with a header in front and often a trailer behind, and marks where each frame begins and ends.
  • Addressing. On a link that many stations share, the header says which station the frame is for and which one sent it: Ethernet and Wi-Fi use 48-bit MAC addresses. A point-to-point link has only one possible receiver, so the address field of PPP always holds 0xFF, “all stations”.
  • Error detection. A check value computed over the frame, usually a CRC called the frame check sequence (FCS), lets the receiver recognise a damaged frame and drop it.
  • Reliable delivery. The receiver acknowledges each frame and the sender resends frames that were lost.
  • Flow control. A receiver that is falling behind can ask the sender to pause.
  • Medium access. When several stations share one medium, a set of rules decides who may send and when.

Links pick from this list the services that pay off for the errors they suffer and the stations that share them. Three common links show the range:

  • Ethernet (IEEE 802.3) marks each frame with a preamble on the wire, addresses it with 48-bit MAC addresses and checks it with a 32-bit CRC. It sends no acknowledgements: a damaged frame is dropped and TCP recovers. Flow control is optional, with PAUSE frames, and full-duplex switched links need no medium access.
  • Wi-Fi (IEEE 802.11) sends each frame after a radio preamble and header, with 48-bit MAC addresses and a 32-bit CRC, and acknowledges every unicast frame: a frame whose acknowledgement does not come back is sent again. Stations share the radio with CSMA/CA.
  • PPP on a serial line (RFC 1661, RFC 1662) marks frames with a flag byte and byte or bit stuffing. It needs no addresses (the address field is always 0xFF) and checks frames with a 16-bit CRC by default, or a 32-bit one by agreement. It sends no acknowledgements and, with only two ends, needs no medium access.

Wi-Fi acknowledges frames because radio loses frames far more often than a cable does, and resending across one hop takes far less time than waiting for TCP at the far end to notice the loss; a cable loses so few frames to noise that Ethernet leaves recovery to the transport layer. Medium access gets the next module of its own.

Every service ends at the far end of the link. When a router forwards a packet, it takes the packet out of the frame it arrived in and builds a new frame for the next link, with new link-layer addresses and a new CRC. An error that happens inside the router, after the old CRC was checked and before the new one was computed, is invisible to both links; catching that kind of damage is a job for the checksums of the layers above.

In a computer, the link layer is split between the network card and the operating system:

A frame goes down the sender: OS, driver, network card; over one link; then up the receiver: network card, driver, OS.Sender: OSbuilds theframe headerReceiver: OShands thepacket to IPDriverqueues theframeDriverpasses upgood framesNetwork cardadds the CRCand preambleNetwork cardchecks the CRC,drops bad oneslink

Where the link layer's work happens on one hop

Text description of the diagram

The diagram has two columns of three boxes, the sender on the left and the receiver on the right.

  1. Left, from the top: the sender's operating system builds the frame header; its driver queues the frame; its network card adds the CRC and the preamble.
  2. An arrow labelled "link" joins the sender's network card to the receiver's network card at the bottom.
  3. Right, from the bottom: the receiver's network card checks the CRC and drops bad frames; its driver passes good frames up; its operating system hands the packet to IP.
  • The network card (a NIC: network interface card or controller). Its physical-layer part (the PHY) turns bits into signals on copper, light in fibre or radio waves, and back. Its MAC part adds the preamble and the CRC to each frame it sends, and on the way in it finds where frames begin, checks every CRC and drops frames that fail. Cards today take on more of the work as well, such as computing IP and TCP checksums.
  • The driver connects the card to the operating system. Frames wait in memory that both can reach: the card reads frames to send from it and writes received frames into it. It then signals the operating system with an interrupt, and the kernel collects the new frames in batches (Linux calls this machinery NAPI).
  • The operating system builds the frame header: its own MAC address, the next hop’s MAC address (found with ARP on IPv4 or Neighbor Discovery on IPv6, in later lessons) and the type of packet inside. On the way in, it reads the type field and hands the packet to IPv4, IPv6 or ARP.

So the preamble and the CRC exist only between two network cards. Linux, for example, offers an rx-fcs setting that asks the card to keep the FCS at the end of each received frame so that capture tools can read it, and an rx-all setting that asks it to keep damaged frames too. Without such a request the card removes the CRC and drops damaged frames, which is why a capture on your own computer almost never shows a frame’s CRC, or a frame that failed it.

Why finding the boundaries is hard

The physical layer hands up nothing but bits. A receiver that starts listening in the middle of a transmission, or that has just lost a few bits to noise, has to find the start of the next frame from those bits alone. There are four ways to make that possible:

  • A length field at the start of each frame says how many bytes follow.
  • Byte stuffing: a flag byte marks each end of a frame, and an escape byte protects any flag byte inside the data.
  • Bit stuffing: a flag pattern of bits marks each end, and the sender inserts a 0 bit into any run of 1s that could look like it.
  • Markers in the line code: the physical layer has signal patterns that never stand for data, and uses them to mark the start and the end of a frame.

Length fields: simple until one byte is wrong

A length field costs only its own byte or two, and the receiver can cut frames apart without looking at the data. The trouble starts when the length itself is damaged:

A length byte in front of every message Python · length_prefix.py
"""Framing with a length byte in front of every message, and what one damaged length byte does."""


def frame(messages):
    """Put each message after one byte that holds its length."""
    out = bytearray()
    for m in messages:
        out.append(len(m))
        out += m
    return bytes(out)


def unframe(stream):
    """Cut a stream back into messages by trusting every length byte."""
    messages, i = [], 0
    while i < len(stream):
        n = stream[i]
        messages.append(stream[i + 1 : i + 1 + n])
        i += 1 + n
    return messages


sent = [b"GET", b"temp=31", b"ok", b"bye"]
stream = frame(sent)
print("on the link:", stream.hex(" "))
print("received:   ", unframe(stream))

damaged = bytearray(stream)
damaged[4] ^= 0b0000_0001  # noise flips the lowest bit of the second length byte: 7 becomes 6
print()
print("on the link:", bytes(damaged).hex(" "))
print("received:   ", unframe(bytes(damaged)))

Output

on the link: 03 47 45 54 07 74 65 6d 70 3d 33 31 02 6f 6b 03 62 79 65
received:    [b'GET', b'temp=31', b'ok', b'bye']

on the link: 03 47 45 54 06 74 65 6d 70 3d 33 31 02 6f 6b 03 62 79 65
received:    [b'GET', b'temp=3', b'\x02ok\x03bye']

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 length_prefix.py

One flipped bit turned the second length from 7 into 6. The receiver took temp=3 as the second message, read the 1 that followed (byte 0x31, which is 49) as the next length, and swallowed the rest of the stream as one message. Four messages became three, and nothing in the stream lets the receiver find its place again: every boundary after a damaged length is lost.

Length fields work well where something else already marks the boundaries or keeps bytes from being damaged. TCP delivers a stream of bytes without loss, so a length prefix in front of each message is the usual way to frame messages on top of it (the socket programming module does exactly that). Inside an Ethernet frame, whose ends are marked by the physical layer, the two bytes after the addresses may also hold a length: values up to 1500 are a length, while values of 0x0600 (1,536) and more are an EtherType, which names the protocol inside, such as 0x0800 for IPv4 or 0x86DD for IPv6.

Byte stuffing: a flag and an escape

PPP, the Point-to-Point Protocol, carries IP packets over serial lines and modems, and its HDLC-like framing (RFC 1662) is byte stuffing in its classic form:

  • The flag byte 0x7E (binary 01111110) marks the start and the end of every frame. One flag between two frames is enough, and the receiver checks every byte it gets for it.
  • The escape byte 0x7D marks a changed byte. Before sending, every 0x7E and every 0x7D inside the frame is replaced by 0x7D followed by the original byte XOR 0x20: 0x7E goes out as 7D 5E, and 0x7D as 7D 5D.
  • The receiver removes each 0x7D and XORs the byte after it with 0x20. A flag byte can now only ever be a frame boundary.
PPP-style byte stuffing and unstuffing Python · byte_stuffing.py
"""PPP-style byte stuffing (RFC 1662, section 4.2): a flag byte marks each end, an escape byte protects the data."""
import random

FLAG = 0x7E  # 0111 1110, sent before and after every frame
ESC = 0x7D  # 0111 1101, "the next byte was changed"


def byte_stuff(payload):
    """Frame a payload: flag, the data with FLAG and ESC escaped, flag."""
    out = bytearray([FLAG])
    for b in payload:
        if b in (FLAG, ESC):
            out += bytes([ESC, b ^ 0x20])  # 0x7E is sent as 7D 5E, 0x7D as 7D 5D
        else:
            out.append(b)
    out.append(FLAG)
    return bytes(out)


def byte_unstuff(frame):
    """Undo byte_stuff(): drop the flags, and restore each byte that follows an escape."""
    out, escaped = bytearray(), False
    for b in frame[1:-1]:
        if escaped:
            out.append(b ^ 0x20)
            escaped = False
        elif b == ESC:
            escaped = True
        else:
            out.append(b)
    return bytes(out)


payload = bytes([0x41, 0x7E, 0x42, 0x7D, 0x43])
framed = byte_stuff(payload)
print("payload:", payload.hex(" "))
print("framed: ", framed.hex(" "))
print("back:   ", byte_unstuff(framed).hex(" "))

rng = random.Random(1662)
cases = {
    "a line of text": b"meter 17 reads 231 V",
    "100,000 random bytes": rng.randbytes(100_000),
    "1,000 flag bytes": bytes([FLAG]) * 1000,
}
print()
for name, data in cases.items():
    f = byte_stuff(data)
    assert byte_unstuff(f) == data
    escapes = len(f) - 2 - len(data)
    print(f"{name}: {len(data):,} bytes in, {len(f):,} on the link, {escapes:,} escaped ({escapes / len(data):.2%})")

Output

payload: 41 7e 42 7d 43
framed:  7e 41 7d 5e 42 7d 5d 43 7e
back:    41 7e 42 7d 43

a line of text: 20 bytes in, 22 on the link, 0 escaped (0.00%)
100,000 random bytes: 100,000 bytes in, 100,783 on the link, 781 escaped (0.78%)
1,000 flag bytes: 1,000 bytes in, 2,002 on the link, 1,000 escaped (100.00%)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 byte_stuffing.py

The run shows both costs. Two of the 256 possible byte values need escaping, so random data should grow by about 2/256, or 0.78 %, and the 100,000 random bytes grew by 781 bytes, 0.78 %. A payload made of nothing but flag bytes doubles in size, plus the two flags. Any protocol that accepts data from outside, so that a sender can choose its bytes, has to size its buffers and time limits for that worst case, not for the average.

RFC 1662 also lets the two ends escape more than the minimum. On asynchronous links (modems and serial ports that send one byte at a time) the default is to escape every control byte below 0x20 too, because some equipment between the ends swallows or changes them. The ends can negotiate a smaller set once the link is up.

The big win over a length field is recovery. If noise damages a frame, the frame fails its CRC and is dropped, but the next flag byte still starts the next frame. One frame is lost, not the rest of the stream.

Bit stuffing: a flag pattern and inserted zeros

HDLC and PPP on bit-synchronous links, which send a continuous stream of bits rather than separate bytes, mark frames with the same pattern 01111110, but as bits that may start anywhere, not as a byte. To make sure the data can never contain six 1s in a row, the sender inserts a 0 after every run of five 1s, and the receiver removes every 0 that directly follows five 1s (RFC 1662, section 5.2):

HDLC bit stuffing, with every inserted bit marked Python · bit_stuffing.py
"""HDLC bit stuffing (RFC 1662, section 5.2): a 0 goes in after every five 1s, so the flag 01111110 never appears in data."""
import random

FLAG = "01111110"


def bit_stuff(bits):
    """Insert a 0 after every run of five 1s; also return where the inserted bits are."""
    out, inserted, ones = [], [], 0
    for b in bits:
        out.append(b)
        ones = ones + 1 if b == "1" else 0
        if ones == 5:
            inserted.append(len(out))
            out.append("0")
            ones = 0
    return "".join(out), inserted


def bit_unstuff(bits):
    """Drop the 0 that follows every five 1s."""
    out, ones, skip = [], 0, False
    for b in bits:
        if skip:  # this is the inserted 0
            skip, ones = False, 0
            continue
        out.append(b)
        ones = ones + 1 if b == "1" else 0
        if ones == 5:
            skip = True
    return "".join(out)


data = "0111111011111111110"  # the flag pattern, then a run of ten 1s
stuffed, where = bit_stuff(data)
print("data:     ", data)
print("stuffed:  ", stuffed)
print("inserted: ", "".join("^" if i in where else " " for i in range(len(stuffed))).rstrip())
print("on the line:", FLAG + stuffed + FLAG)
print("unstuffed:", bit_unstuff(stuffed), bit_unstuff(stuffed) == data)
print("longest run of 1s after stuffing:", max(len(r) for r in stuffed.split("0")))

rng = random.Random(1662)
print()
for name, bits in {
    "8,000 random bits": "".join(rng.choice("01") for _ in range(8000)),
    "8,000 ones": "1" * 8000,
}.items():
    s, ins = bit_stuff(bits)
    assert bit_unstuff(s) == bits
    print(f"{name}: {len(ins):,} bits inserted ({len(ins) / len(bits):.2%})")

Output

data:      0111111011111111110
stuffed:   0111110101111101111100
inserted:        ^       ^     ^
on the line: 01111110011111010111110111110001111110
unstuffed: 0111111011111111110 True
longest run of 1s after stuffing: 5

8,000 random bits: 111 bits inserted (1.39%)
8,000 ones: 1,600 bits inserted (20.00%)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bit_stuffing.py

The carets mark the three inserted bits. The data held the flag pattern itself and a run of ten 1s, and after stuffing no run of 1s is longer than five, so the only six 1s on the line are the flags at the two ends. A receiver that sees seven or more 1s in a row knows the frame was aborted or damaged and discards it.

Bit stuffing costs at most one bit for every five data bits, 20 %, which is the all-ones case in the run; the random bits needed 1.39 %. Its weakness is the reverse of a length field’s strength: the receiver has to examine every bit, which is why the work is done in hardware.

Here are the three methods side by side, with the numbers from the runs above:

  • Length field. It costs only the length bytes, but one damaged length loses every boundary after it. It suits streams that something else protects from damage, such as messages on top of TCP.
  • Byte stuffing (PPP). It cost 0.78 % on random data and doubles a frame in the worst case; after damage, the next flag starts the next frame. It suits byte-oriented links: serial lines and modems.
  • Bit stuffing (HDLC). It cost 1.39 % on random bits and never more than 20 %, one bit per five; after damage, the next flag starts the next frame. It suits bit-synchronous links, where hardware examines every bit.

How Ethernet marks its frames

Ethernet needs no stuffing at all, because its physical layer marks the boundaries. Every frame goes on the wire after a preamble of seven bytes of alternating 1s and 0s, which lets the receiver lock on to the signal, and a start frame delimiter, 10101011, whose last two 1s say that the frame begins with the next bit. Faster versions of Ethernet also mark the start and the end of each frame with code groups of their line code that never carry data, and the standard keeps a gap of at least 96 bit times between frames. The receiving card removes all of this, so software only ever sees whole frames, starting with the destination address.

The same idea explains a number you may have met on broadband connections. PPPoE (RFC 2516) carries PPP inside Ethernet frames, and each PPP frame there starts directly with its protocol number, with no flags and no escaping, because Ethernet already marks and checks the frame. What remains are 6 bytes of PPPoE header and 2 bytes of PPP protocol number, taken from Ethernet’s 1,500-byte payload, which is why a PPPoE connection carries IP packets of at most 1,492 bytes.

Framing in the GATE CS syllabus

The GATE 2026 syllabus for Computer Science listed “framing” under the data link layer. The GATE 2027 syllabus (Section 10) names “Data link layer: error detection, Medium Access Control, Ethernet” and no longer lists framing on its own, but you still need it to follow how Ethernet frames are delimited and checked. The next two lessons cover error detection, which the syllabus does list.

Text to Binary & Hex Converter Turn a short text into its bits, then try bit stuffing on them by hand and check your answer with the example above.

Interview questions

The physical layer already delivers bits. Why does a link layer still need framing? Bits on their own carry no boundaries, and the layers above work with whole packets. Framing lets the receiver find where each frame starts and ends, so that it can check each frame’s CRC, read its addresses and hand exactly one packet up. Good framing also lets a receiver that joined mid-stream, or lost bits to noise, find the next frame by itself: with flags, the next flag is always a boundary, while a single damaged length field can lose every boundary after it.

Key takeaways

  • The link layer moves one frame over one link; every router builds a new frame, with new addresses and a new CRC, for the next link.
  • Its possible services are framing, addressing, error detection, reliable delivery, flow control and medium access, and each link picks the ones that suit its errors and its stations: Wi-Fi acknowledges frames, wired Ethernet does not.
  • The network card adds and checks the preamble and the CRC, the driver moves frames between the card and memory, and the operating system builds headers and reads the type field.
  • A length field is cheap, but one damaged length loses every later boundary; it suits protocols on top of TCP.
  • PPP’s byte stuffing escapes 0x7E and 0x7D with 0x7D and an XOR with 0x20: about 0.78 % extra on random data, up to double in the worst case.
  • HDLC’s bit stuffing inserts a 0 after five 1s, so the flag 01111110 never appears in data: at most 20 % extra.
  • Ethernet marks frames in its physical layer, with a preamble, a start frame delimiter and special line-code groups, and needs no stuffing.

Exercise

Exercise · Easy · Python

Byte stuffing and bit stuffing, both ways

Write the four functions of framing.py, the two halves of byte stuffing and of bit stuffing:

  • byte_stuff(payload) takes bytes and returns the whole frame as bytes: the flag 0x7E, the payload with every 0x7E and every 0x7D replaced by 0x7D followed by the byte XOR 0x20, and a closing 0x7E. So byte_stuff(b"A~B") returns b"\x7eA\x7d\x5eB\x7e".
  • byte_unstuff(frame) undoes it: it drops the two flags and turns every 0x7D and the byte after it back into that byte XOR 0x20.
  • bit_stuff(bits) takes a string of "0" and "1" characters and inserts a "0" after every run of five "1"s, so that six 1s in a row (the flag 01111110) can never appear: bit_stuff("0111111") returns "01111101".
  • bit_unstuff(bits) removes every "0" that directly follows five "1"s.

The sample tests import the functions from framing.py. The last test sends 200 random payloads through each pair and checks that every one comes back unchanged.

Starter code · framing.py

FLAG = 0x7E
ESC = 0x7D


def byte_stuff(payload):
    """Return the frame for payload: FLAG, the payload with every FLAG and ESC byte escaped, FLAG."""
    # Replace this line with your code.
    return b""


def byte_unstuff(frame):
    """Return the payload of a frame made by byte_stuff()."""
    # Replace this line with your code.
    return b""


def bit_stuff(bits):
    """Insert a "0" after every run of five "1"s in a string of "0" and "1" characters."""
    # Replace this line with your code.
    return ""


def bit_unstuff(bits):
    """Remove every "0" that directly follows five "1"s."""
    # Replace this line with your code.
    return ""
The sample tests · test_framing.py
import random

from framing import bit_stuff, bit_unstuff, byte_stuff, byte_unstuff


def test_plain_bytes():
    """puts a flag at each end and leaves ordinary bytes alone"""
    assert byte_stuff(b"AB") == b"\x7eAB\x7e"
    assert byte_stuff(b"") == b"\x7e\x7e"


def test_flag_byte_is_escaped():
    """sends a 0x7E inside the payload as 0x7D 0x5E"""
    assert byte_stuff(b"\x7e") == b"\x7e\x7d\x5e\x7e"
    assert byte_stuff(b"A~B") == b"\x7eA\x7d\x5eB\x7e"


def test_escape_byte_is_escaped():
    """sends a 0x7D inside the payload as 0x7D 0x5D"""
    assert byte_stuff(b"\x7d") == b"\x7e\x7d\x5d\x7e"
    assert byte_stuff(b"\x7d\x7e") == b"\x7e\x7d\x5d\x7d\x5e\x7e"


def test_byte_unstuff():
    """restores flag and escape bytes and drops the two flags"""
    assert byte_unstuff(b"\x7e\x41\x7d\x5e\x42\x7d\x5d\x43\x7e") == b"\x41\x7e\x42\x7d\x43"
    assert byte_unstuff(b"\x7e\x7e") == b""
    assert byte_unstuff(b"\x7e\x5e\x5d\x7e") == b"\x5e\x5d"


def test_bit_stuff_after_five_ones():
    """inserts a 0 after every five 1s in a row, and nowhere else"""
    assert bit_stuff("11111") == "111110"
    assert bit_stuff("0111111") == "01111101"
    assert bit_stuff("1111011110") == "1111011110"
    assert bit_stuff("") == ""


def test_bit_stuff_hides_the_flag():
    """never lets six 1s in a row appear"""
    assert bit_stuff("01111110") == "011111010"
    assert bit_stuff("1" * 12) == "11111011111011"
    assert "111111" not in bit_stuff("1" * 40)


def test_bit_unstuff():
    """removes exactly the bits bit_stuff() inserted"""
    assert bit_unstuff("0111110101111101111100") == "0111111011111111110"
    assert bit_unstuff("111110") == "11111"
    assert bit_unstuff("0101") == "0101"


def test_frames_from_the_lesson():
    """matches the frames of the lesson's examples"""
    assert byte_stuff(bytes([0x41, 0x7E, 0x42, 0x7D, 0x43])).hex(" ") == "7e 41 7d 5e 42 7d 5d 43 7e"
    assert bit_stuff("0111111011111111110") == "0111110101111101111100"


def test_round_trip_200_random_payloads():
    """gives back every one of 200 random payloads unchanged, and never puts a flag inside a frame"""
    rng = random.Random(200)
    for _ in range(200):
        n = rng.randrange(0, 40)
        payload = bytes(rng.choice([0x7E, 0x7D, 0x20, 0x5E, 0x00, rng.randrange(256)]) for _ in range(n))
        frame = byte_stuff(payload)
        assert 0x7E not in frame[1:-1], payload
        assert byte_unstuff(frame) == payload, payload
        bits = "".join(rng.choice("0111") for _ in range(rng.randrange(0, 60)))
        stuffed = bit_stuff(bits)
        assert "111111" not in stuffed, bits
        assert bit_unstuff(stuffed) == bits, bits
A hint

For byte_stuff, build a bytearray that starts with the flag, loop over the payload, and append either the byte or the two bytes 0x7D, b ^ 0x20. For bit_stuff, keep a counter of the "1"s seen in a row: reset it to 0 on every "0", and when it reaches 5, append an extra "0" and reset it. bit_unstuff uses the same counter, but skips the character that comes right after the fifth "1".

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 6 Why is a length field on its own a fragile way to mark frames on a noisy link?

    Choose one answer.

    Show the answer to question 1

    Answer: One damaged length byte puts every later boundary in the wrong place, and nothing in the stream shows where the next frame starts

    In length_prefix.py one flipped bit turned a length of 7 into 6, and the receiver then read a data byte as the next length and merged the rest of the stream into one message. Flags are different: the next flag always starts the next frame, so only the damaged frame is lost.

  2. Question 2 of 6 A PPP link uses byte stuffing as RFC 1662 describes it. How does a payload byte 0x7D go out on the link?

    Choose one answer.

    Show the answer to question 2

    Answer: As the two bytes 7D 5D

    0x7D is the escape byte itself, so it must be escaped too: the sender sends 0x7D and then the original byte XOR 0x20, and 0x7D XOR 0x20 is 0x5D. The receiver removes the 0x7D and XORs the next byte with 0x20 again.

  3. Question 3 of 6 HDLC bit stuffing is applied to a run of twelve 1 bits. How many 0 bits does the sender insert?

    Type a number.

    Show the answer to question 3

    Answer: 2 bits

    A 0 goes in after the first five 1s and again after the next five, and the last two 1s need nothing: 11111 0 11111 0 11. No run of more than five 1s is left, so the flag 01111110 cannot appear.

  4. Question 4 of 6 How many bytes does byte_stuff() from byte_stuffing.py return for the payload bytes([0x7E, 0x41, 0x7D])?

    Type a number.

    Show the answer to question 4

    Answer: 7 bytes

    The frame is the opening flag 7E, then 7D 5E for the 0x7E, 41 unchanged, 7D 5D for the 0x7D, and the closing flag 7E: seven bytes for a three-byte payload.

  5. Question 5 of 6 Which of these does wired Ethernet (IEEE 802.3) provide at the link layer?

    Choose every answer that is right.

    Show the answer to question 5

    Answer:

    • Framing, with a preamble and start frame delimiter on the wire
    • Addressing with 48-bit MAC addresses
    • Error detection with a 32-bit CRC

    Ethernet frames, addresses and checks every frame, but drops a damaged frame without telling anyone and leaves recovery to TCP; Wi-Fi is the link that acknowledges and resends. Ethernet needs no stuffing because its physical layer marks where frames start and end.

  6. Question 6 of 6 A computer receives an Ethernet frame with a correct CRC. Where is the CRC (the FCS) usually checked and removed?

    Choose one answer.

    Show the answer to question 6

    Answer: In the network card, before the operating system sees the frame

    The card checks the CRC of every frame, drops frames that fail and normally strips the FCS, so the driver and the operating system get whole, good frames. On Linux the rx-fcs and rx-all settings ask the card to keep the FCS and the damaged frames for capture tools.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.