Data that is tightly packed typically ignores 8 bit boundaries, which entails much shifting and masking. reprintf eliminates the need for the programmer to their own shifts and masks. The following code shows printing an IPv4 Header.
/*
\fN;ncw prints N bits of data from this pool (in decimal by default). */
const char test_reprint_ipv4[] =
"\f\r0=cq" // Specify packed data
// and load 16 bits; no printing
"Version: \f4;ncw\n" // Print 4 bits; 4 total
"Header Words: \f4;ncw\n" // Print 4 bits; 8 total
"DSCP: \f6;ncw\n" // Print 6 bits; 14 total
"ECN: \f2;cw\n" // Print 2 bits; 16 total
"Total Bytes: \fcnq\n" // Print 16 bit value
"Identification: \fcnq\n" // Print 16 bit value
"\f0=cq" // Load 16 bits; no printing
"Flags: \f&3;ncw\n" // Print 3 bits in binary; 3 total
"Fragment Offset: \f13;cw\n" // Print 13 bits; 16 total
"Protocol: \fcp\n" // Print 8 bit value
"TTL: \fcp\n" // Print 8 bit value
"Header Checksum: \fcnq\n" // Print 16 bit value
"Source IP: \fcp.\fcp.\fcp.\fcp\n" // Print 4 1 byte values
"Dest IP: \fcp.\fcp.\fcp.\fcp\n"; // Print 4 1 byte values
reprintf_ptr(test_reprint_ipv4, incoming_packet);
The packing directive "\r" indicates the data format is tightly packed, rather than struct packed.
The input specifier "cq" corresponds to "uint16_t", so exactly 16 bits are loaded into the Value register. The "0=" sequence specifically loads 0 into Register 4, which for formatted integer output governs the number of significant digits printed. Printing 0 significant digits is essentially a no-op but leaves the value loaded in the Value register. The input modifier "n" indicates the input datum is big endian formatted.
The input specifier "cw" specifically calls out bitfields and assumes the bit data was already loaded into the Value Register. The ';' character identifies Register 3, which is the parameter governing how many bits are output.
Using printf, the equivalent code (without the binary flag output of course) is:
/* Using printf. The format string may appear simpler, but correctly extracting
the data from the packet just to put it on the stack is a painful task.
I'm not even sure if that part is right... */
const char test_printf_ipv4[] =
"Version: %u\n"
"Header Words: %u\n"
"DSCP: %u\n"
"ECN: %u\n"
"Total Bytes: %u\n"
"Identification: %u\n"
"Flags: %x\n"
"Fragment Offset: %u\n"
"Protocol: %u\n"
"TTL: %u\n"
"Header Checksum: %u\n"
"Source IP: %u.%u.%u.%u\n"
"Dest IP: %u.%u.%u.%u\n";
printf(test_printf_ipv4
,incoming_packet[0] >> 4
,incoming_packet[0] & 0xF
,incoming_packet[1] >> 2
,incoming_packet[1] & 0x3
,*(uint16_t*)(incoming_packet + 2)
,*(uint16_t*)(incoming_packet + 4)
,incoming_packet[5] >> 5
,*(uint16_t*)(incoming_packet + 6) & 0x1FFF
,incoming_packet[8]
,incoming_packet[9]
,*(uint16_t*)(incoming_packet + 10)
,incoming_packet[12]
,incoming_packet[13]
,incoming_packet[14]
,incoming_packet[15]
,incoming_packet[16]
,incoming_packet[17]
,incoming_packet[18]
,incoming_packet[19]);
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
nice!
Are you sure? yes | no