File Coverage

blib/lib/POE/Filter/PPPHDLC.pm
Criterion Covered Total %
statement 43 43 100.0
branch 9 12 75.0
condition 2 6 33.3
subroutine 9 9 100.0
pod 0 4 0.0
total 63 74 85.1


line stmt bran cond sub pod time code
1             package POE::Filter::PPPHDLC;
2              
3 3     3   68800 use 5.006002;
  3         22  
4 3     3   15 use strict;
  3         6  
  3         56  
5 3     3   15 use warnings;
  3         4  
  3         2765  
6              
7             our $VERSION = '0.02';
8              
9             sub DEBUG () { 0 }
10              
11             sub HDLC_BUFFER () { 0 }
12              
13             sub new {
14 2     2 0 181 my $class = shift;
15 2         9 return bless [
16             '', # HDLC_BUFFER
17             ], $class;
18             }
19              
20             # only arg is an array ref of chunks
21             sub get_one_start {
22 2     2 0 9 my $self = shift;
23             # stick the chunks onto the buffer
24 2         7 $self->[HDLC_BUFFER] .= join '', @{$_[0]};
  2         11  
25             }
26              
27             sub get_pending {
28 2     2 0 565 my $self = shift;
29 2 100       14 return [ $self->[HDLC_BUFFER] ] if length $self->[HDLC_BUFFER];
30 1         5 return undef;
31             }
32              
33             sub get {
34 1     1 0 1516 my $self = shift;
35              
36             # add chunks to buffer
37 1         5 $self->get_one_start(@_);
38              
39 1         3 warn "buffer:" . join('', map sprintf("%02x", ord $_), split //, $self->[HDLC_BUFFER]) . "\n" if DEBUG;
40            
41             # remove anything in the buffer before the first flag, it's officially noise
42 1         6 $self->[HDLC_BUFFER] =~ s/^[^\x7e]+//;
43              
44 1         3 my @packets;
45 1   33     8 PACKET: while (defined $self->[HDLC_BUFFER] and length $self->[HDLC_BUFFER]) {
46             # first char is always a \x7e
47 4         12 my $end = index $self->[HDLC_BUFFER], "\x7e", 1;
48 4 100       10 last PACKET if $end == -1;
49              
50 3         8 my $packet = substr $self->[HDLC_BUFFER], 1, $end - 1;
51 3         6 substr $self->[HDLC_BUFFER], 0, $end, '';
52 3 100       10 next PACKET if length($packet) < 4;
53              
54 2         7 $packet =~ tr/\x00-\x1f//d;
55 2         11 $packet =~ s/\x7d(.)/chr(ord($1) ^ 0x20)/seg; # the /s is important
  40         100  
56 2 50       6 next PACKET if length($packet) < 4; # can be too short again
57              
58             # remove flags (done), address and control and check the FCS
59             # we discard the packet on errors
60 2         9 my ($frame_address, $frame_control) = unpack "CC", $packet;
61 2         3 printf STDERR "frame: address=%02x control=%02x\n",
62             $frame_address, $frame_control
63             if DEBUG;
64              
65 2 50 33     30 next PACKET unless $frame_address == 0xff and $frame_control == 0x03;
66 2 50       10 next PACKET unless _frame_check($packet);
67              
68 2         14 push @packets, substr $packet, 2, -2;
69             }
70              
71 1         4 return [@packets];
72             }
73              
74             # Algorithm lifted from RFC1662
75             my @fcstab = (
76             0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
77             0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
78             0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
79             0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
80             0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
81             0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
82             0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
83             0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
84             0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
85             0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
86             0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
87             0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
88             0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
89             0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
90             0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
91             0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
92             0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
93             0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
94             0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
95             0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
96              
97             0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
98             0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
99             0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
100             0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
101             0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
102             0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
103             0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
104             0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
105             0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
106             0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
107             0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
108             0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
109             );
110             sub PPPINITFCS16 () { 0xffff } # Initial FCS value
111             sub PPPGOODFCS16 () { 0xf0b8 } # Good final FCS value
112              
113             sub _pppfcs16 {
114 27     27   807 my $fcs = shift;
115             # BUGFIX: https://rt.cpan.org/Public/Bug/Display.html?id=141718
116             # As above, the /s is important. If it is omitted, the . will not match \n
117             # and the checksum calculation will be wrong.
118 27         1518 $fcs = ($fcs >> 8) ^ $fcstab[($fcs ^ ord($1)) & 0xff] while $_[0] =~ m/(.)/sg;
119 27         103 return $fcs & 0xffff;
120             }
121              
122             # not a method, one arg: the packet
123             sub _frame_check {
124 14     14   49 my $fcs = _pppfcs16(PPPINITFCS16, $_[0]);
125 14         23 printf STDERR "FCS: %04x on %d bytes\n", $fcs, length($_[0])
126             if DEBUG;
127 14         65 return $fcs == PPPGOODFCS16;
128             }
129              
130             1;
131             __END__