|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Device::OUI;  | 
| 
2
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
418808
 | 
 use strict; use warnings;  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
21
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
372
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
383
 | 
    | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '1.04';  | 
| 
4
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
8490
 | 
 use IO::File ();  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2147267
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
279
 | 
    | 
| 
5
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
81
 | 
 use Carp qw( croak carp );  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
484
 | 
    | 
| 
6
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
9665
 | 
 use AnyDBM_File;  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68074
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
936
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 use overload (  | 
| 
8
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     '<=>' => 'overload_cmp',  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'cmp' => 'overload_cmp',  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '""'  => 'normalized',  | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     fallback => 1,  | 
| 
12
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
5547
 | 
 );  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3509
 | 
    | 
| 
13
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
1094
 | 
 use base qw( Class::Accessor::Grouped );  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20621
 | 
    | 
| 
14
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
126
 | 
 use Sub::Exporter -setup => {  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     exports => [qw( normalize_oui oui_cmp parse_oui_entry oui_to_integers )],  | 
| 
16
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
1678681
 | 
 };  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
145527
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->mk_group_accessors( inherited => qw(  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     cache_db cache_file  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     file_url search_url  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ) );  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $cache = $^O eq 'MSWin32' ? 'C:\device_oui' : '/var/cache/device_oui';  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->cache_db( $cache );  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->cache_file( $cache . '.txt' );  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->search_url( 'http://standards.ieee.org/cgi-bin/ouisearch?%s' );  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->file_url( 'http://standards.ieee.org/regauth/oui/oui.txt' );  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub cache_handle {  | 
| 
29
 | 
89
 | 
 
 | 
 
 | 
  
89
  
 | 
  
1
  
 | 
2597
 | 
     my $self = shift;  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
31
 | 
89
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
206
 | 
     if ( @_ ) { $self->set_inherited( 'cache_handle', @_ ) }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
32
 | 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
365
 | 
     my $handle = $self->get_inherited( 'cache_handle' );  | 
| 
33
 | 
89
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1909
 | 
     if ( $handle ) { return $handle }  | 
| 
 
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
256
 | 
    | 
| 
34
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
44
 | 
     $handle = {};  | 
| 
35
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
566
 | 
     if ( my $db = $self->cache_db ) {  | 
| 
36
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
         my $opts = Fcntl::O_RDWR | Fcntl::O_CREAT;  | 
| 
37
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
         my %cache;  | 
| 
38
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1910
 | 
         if ( tie( %cache, 'AnyDBM_File', $db, $opts, 0666 ) ) { ## no critic  | 
| 
39
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
             $handle = \%cache;  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
42
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
492
 | 
     $self->set_inherited( 'cache_handle', $handle );  | 
| 
43
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
291
 | 
     return $handle;  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub cache {  | 
| 
47
 | 
77
 | 
 
 | 
 
 | 
  
77
  
 | 
  
1
  
 | 
6582
 | 
     my $self = shift;  | 
| 
48
 | 
77
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
428
 | 
     my $oui = ( @_ && not ref $_[0] ) ? shift : $self->norm;  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
50
 | 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
186
 | 
     my $handle = $self->cache_handle;  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
52
 | 
77
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
355
 | 
     if ( @_ ) {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
53
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
         my %hash = %{ shift() };  | 
| 
 
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
324
 | 
    | 
| 
54
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
156
 | 
         for my $x ( keys %hash ) {  | 
| 
55
 | 
186
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
522
 | 
             if ( not defined $hash{ $x } ) { $hash{ $x } = '' }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
57
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1310
 | 
         return $handle->{ $oui } = join( "\0", %hash );  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ( my $x = $handle->{ $oui } ) {  | 
| 
59
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
224
 | 
         return { split( "\0", $x ) };  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
61
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
     return;  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
65
 | 
98
 | 
 
 | 
 
 | 
  
98
  
 | 
  
1
  
 | 
49984
 | 
     my $self = bless( {}, shift );  | 
| 
66
 | 
98
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
799
 | 
     $self->oui( shift ) if @_;  | 
| 
67
 | 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
399
 | 
     return $self;  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub oui {  | 
| 
71
 | 
102
 | 
 
 | 
 
 | 
  
102
  
 | 
  
1
  
 | 
2634
 | 
     my $self = shift;  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
73
 | 
102
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
335
 | 
     if ( @_ ) {  | 
| 
74
 | 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
120
 | 
         my $oui = shift;  | 
| 
75
 | 
96
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
196
 | 
         if ( my $norm = normalize_oui( $oui ) ) {  | 
| 
76
 | 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
817
 | 
             $self->{ 'oui' } = $oui;  | 
| 
77
 | 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
159
 | 
             $self->{ 'oui_norm' } = $norm;  | 
| 
78
 | 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
192
 | 
             delete $self->{ 'lookup' };  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
80
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
             croak "Invalid OUI format: $oui";  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
84
 | 
101
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
383
 | 
     if ( not $self->{ 'oui' } ) { croak "Object does not have an OUI" }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
86
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
193
 | 
     return $self->{ 'oui' };  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub oui_to_integers {  | 
| 
90
 | 
5159
 | 
 
 | 
  
100
  
 | 
  
5159
  
 | 
  
1
  
 | 
14226
 | 
     my $oui = shift || return;  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
5153
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
11605
 | 
     if ( ref $oui ) { return map { hex } split( '-', $oui->norm ) }  | 
| 
 
 | 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
764
 | 
    | 
| 
 
 | 
876
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1783
 | 
    | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 00-06-2A or 0:6:2a, etc. any non-hex delimiter will do  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
96
 | 
4861
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5445
 | 
         my @parts = grep { length } split( /[^a-f0-9]+/i, $oui );  | 
| 
 
 | 
4861
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31583
 | 
    | 
| 
 
 | 
13141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45532
 | 
    | 
| 
97
 | 
4861
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13632
 | 
         if ( @parts == 3 ) { return map { hex } @parts }  | 
| 
 
 | 
4140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8851
 | 
    | 
| 
 
 | 
12420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42258
 | 
    | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 00062a, requires exactly 6 hex characters  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
102
 | 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1109
 | 
         my @parts = ( $oui =~ /([a-f0-9])/ig );  | 
| 
 
 | 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6437
 | 
    | 
| 
103
 | 
721
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3061
 | 
         if ( @parts == 6 ) {  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return(  | 
| 
105
 | 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4622
 | 
                 hex( $parts[0].$parts[1] ),  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 hex( $parts[2].$parts[3] ),  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 hex( $parts[4].$parts[5] ),  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
111
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     return ();  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub normalize_oui {  | 
| 
115
 | 
3847
 | 
 
 | 
 
 | 
  
3847
  
 | 
  
1
  
 | 
2328077
 | 
     my $oui = shift;  | 
| 
116
 | 
3847
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
12364
 | 
     my @int = oui_to_integers( $oui ) or return;  | 
| 
117
 | 
3839
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38313
 | 
     return sprintf( '%02X-%02X-%02X', @int );  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
120
 | 
1223
 | 
 
 | 
 
 | 
  
1223
  
 | 
  
1
  
 | 
3550
 | 
 sub normalized { return shift->{ 'oui_norm' } }  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 *norm = \&normalized;  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
123
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
  
1
  
 | 
2913
 | 
 sub organization { return shift->lookup->{ 'organization' } }  | 
| 
124
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
3154
 | 
 sub company_id { return shift->lookup->{ 'company_id' } }  | 
| 
125
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
2681
 | 
 sub address { return shift->lookup->{ 'address' } }  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub is_private {  | 
| 
128
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
2747
 | 
     my $self = shift;  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
130
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
     return $self->organization eq 'PRIVATE' ? 1 : 0;  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub lookup {  | 
| 
134
 | 
28
 | 
 
 | 
 
 | 
  
28
  
 | 
  
1
  
 | 
46
 | 
     my $self = shift;  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
136
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
     my $x;  | 
| 
137
 | 
28
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
82
 | 
     if ( $x = $self->{ 'lookup' } ) { return $x }  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
    | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
139
 | 
13
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
     if ( $x = $self->cache ) { return $self->{ 'lookup' } = $x }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
140
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
38
 | 
     if ( $x = $self->update_from_file ) { return $self->{ 'lookup' } = $x }  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
    | 
| 
141
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ( $x = $self->update_from_web ) { return $self->{ 'lookup' } = $x }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
142
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ( $self->mirror_file ) {  | 
| 
143
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if ( $x = $self->update_from_file ) {  | 
| 
144
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             return $self->{ 'lookup' } = $x;  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $self->{ 'lookup' } = {};  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub update_from_file {  | 
| 
152
 | 
13
 | 
 
 | 
 
 | 
  
13
  
 | 
  
1
  
 | 
19
 | 
     my $self = shift;  | 
| 
153
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
     my $oui = $self->norm;  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
155
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
404
 | 
     my $cf = $self->cache_file;  | 
| 
156
 | 
13
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
323
 | 
     if ( ! $cf ) { return }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
157
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
     my $fh = IO::File->new( $cf, 'r' );  | 
| 
158
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1454
 | 
     if ( ! $fh ) { return }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
160
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
53
 | 
     local $/ = "";  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
162
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
309
 | 
     while ( my $entry = $fh->getline ) {  | 
| 
163
 | 
46
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2546
 | 
         if ( substr( $entry, 0, 8 ) eq $oui ) {  | 
| 
164
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
             my $data = $self->parse_oui_entry( $entry );  | 
| 
165
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
             $self->cache( $data );  | 
| 
166
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
239
 | 
             return $data;  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
169
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return;  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 {  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $HAVE_LWP_SIMPLE;  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub have_lwp_simple {  | 
| 
175
 | 
17
 | 
 
 | 
 
 | 
  
17
  
 | 
  
1
  
 | 
28
 | 
         my $self = shift;  | 
| 
176
 | 
17
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
         if ( defined $HAVE_LWP_SIMPLE ) { return $HAVE_LWP_SIMPLE }  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
177
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110970
 | 
         eval "require LWP::Simple"; ## no critic  | 
| 
178
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
         if ( $@ ) {  | 
| 
179
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             carp "Unable to load LWP::Simple, network access not available\n";  | 
| 
180
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $HAVE_LWP_SIMPLE = 0;  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
182
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
             $HAVE_LWP_SIMPLE = 1;  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub mirror_file {  | 
| 
188
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
  
1
  
 | 
6984
 | 
     my $self = shift;  | 
| 
189
 | 
14
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
291
 | 
     my $url  = shift || $self->file_url;  | 
| 
190
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
118
 | 
     if ( ! $url ) { return }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
191
 | 
12
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
101
 | 
     my $file = shift || $self->cache_file;  | 
| 
192
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
96
 | 
     if ( ! $file ) { return }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
193
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
75
 | 
     if ( ! $self->have_lwp_simple ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
195
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
     my $res = LWP::Simple::mirror( $url, $file );  | 
| 
196
 | 
11
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2365326
 | 
     if ( $res == LWP::Simple::RC_NOT_MODIFIED() ) { return 0 }  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
197
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
45
 | 
     if ( ! LWP::Simple::is_success( $res ) ) {  | 
| 
198
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         carp "Failed to mirror $url to $file ($res)";  | 
| 
199
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return;  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
201
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
84
 | 
     return 1;  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_url {  | 
| 
205
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
  
1
  
 | 
1184
 | 
     my $self = shift;  | 
| 
206
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $url = shift;  | 
| 
207
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     if ( ! $url ) { return }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
209
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
     return LWP::Simple::get( $url );  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub load_cache_from_web {  | 
| 
213
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
364189
 | 
     my $self = shift;  | 
| 
214
 | 
3
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
14
 | 
     my $url  = shift || $self->file_url;  | 
| 
215
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     if ( ! $url ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
216
 | 
3
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
89
 | 
     my $file = shift || $self->cache_file;  | 
| 
217
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
     if ( ! $file ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
219
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     if ( $self->mirror_file( $url, $file ) ) {  | 
| 
220
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
         return $self->load_cache_from_file( $file );  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
222
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return;  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub load_cache_from_file {  | 
| 
226
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
694
 | 
     my $self = shift;  | 
| 
227
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my $file = shift;  | 
| 
228
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     if ( ! $file ) { $file = $self->cache_file }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
229
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
32
 | 
     if ( ! $file ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
231
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     my $fh = IO::File->new( $file );  | 
| 
232
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
527
 | 
     local $/ = "";  | 
| 
233
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
196
 | 
     $fh->getline; # dump the header  | 
| 
234
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
231
 | 
     my $counter = 0;  | 
| 
235
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
198
 | 
     while ( my $entry = $fh->getline ) {  | 
| 
236
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
820
 | 
         my $data = $self->parse_oui_entry( $entry );  | 
| 
237
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
         $self->cache( $data->{ 'oui' } => $data );  | 
| 
238
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
754
 | 
         $counter++;  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
240
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
248
 | 
     return $counter;  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub search_url_for {  | 
| 
244
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
  
1
  
 | 
779
 | 
     my $self = shift;  | 
| 
245
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     my $oui = normalize_oui( shift );  | 
| 
246
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     if ( ! $oui ) { $oui = $self->norm }  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
248
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
270
 | 
     my $url_format = $self->search_url;  | 
| 
249
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
379
 | 
     if ( ! $url_format ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
251
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
32
 | 
     if ( $url_format =~ /%s/ ) {  | 
| 
252
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
         return sprintf( $url_format, $oui );  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
254
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return $url_format.$oui;  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub update_from_web {  | 
| 
259
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
  
1
  
 | 
27
 | 
     my $self = shift;  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
261
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     if ( not ref $self ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
262
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     if ( not $self->have_lwp_simple ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
264
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $url = $self->search_url_for;  | 
| 
265
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     if ( ! $url ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
267
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
     if ( my $page = $self->get_url( $url ) ) {  | 
| 
268
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
216
 | 
         if ( $page =~ /listing contains no match/ ) { return }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
269
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
         my @entries = ( $page =~ m{(.*?) }gs );  | 
| 
270
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
         if ( @entries > 1 ) { croak "Too many entries returned from $url\n" }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
271
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
         my $data = $self->parse_oui_entry( shift( @entries ) );  | 
| 
272
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
         $self->cache( $data );  | 
| 
273
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
         return $data;  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
275
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return;  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub parse_oui_entry {  | 
| 
279
 | 
52
 | 
 
 | 
 
 | 
  
52
  
 | 
  
1
  
 | 
8492
 | 
     local $_ = pop( @_ ); # pop in case we get called as a class method  | 
| 
280
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
31364
 | 
 use Carp qw( confess );  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7536
 | 
    | 
| 
281
 | 
52
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
153
 | 
     if ( ! $_ ) { confess "eh?" }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
282
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
162
 | 
     s{?b>}{}g;  | 
| 
283
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93
 | 
     s/\r//g;  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
285
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
305
 | 
     s/\s*\(hex\)\s*/\n/gm;  | 
| 
286
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
396
 | 
     s/\s*\(base 16\).*$//gm;  | 
| 
287
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1868
 | 
     s/^\s*|\s*$//gsm;  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
289
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
105
 | 
     my %data = ();  | 
| 
290
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
366
 | 
     @data{ qw( oui organization company_id address ) } = split( "\n", $_, 4 );  | 
| 
291
 | 
52
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
164
 | 
     delete $data{ 'address' } unless $data{ 'address' };  | 
| 
292
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
165
 | 
     return \%data;  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
295
 | 
146
 | 
  
 50
  
 | 
 
 | 
  
146
  
 | 
  
1
  
 | 
881
 | 
 sub overload_cmp { return oui_cmp( pop( @_ ) ? reverse @_ : @_ ) }  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub oui_cmp {  | 
| 
297
 | 
656
 | 
 
 | 
 
 | 
  
656
  
 | 
  
1
  
 | 
157823
 | 
     my @l = oui_to_integers( shift );  | 
| 
298
 | 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1639
 | 
     my @r = oui_to_integers( shift );  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
300
 | 
656
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
5433
 | 
     return ( $l[0] <=> $r[0] || $l[1] <=> $r[1] || $l[2] <=> $r[2] );  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub dump_cache {  | 
| 
304
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
9
 | 
     my $self = shift;  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
306
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
     my @lines = (  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "\n",  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "OUI\t\t\t\tOrganization\n",  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "company_id\t\t\tOrganization\n",  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "\t\t\t\tAddress\n",  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "\n", "\n",  | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
314
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my $db = $self->cache_handle;  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
316
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     foreach my $oui ( sort { $a cmp $b } keys %{ $db } ) {  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
194
 | 
    | 
| 
317
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
382
 | 
         my $d = { split( "\0", $db->{ $oui } ) };  | 
| 
318
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
         my $org = $d->{ 'organization' };  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
320
 | 
25
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
150
 | 
         push( @lines,   | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             sprintf( "%-10s (hex)\t\t%s\n", $d->{ 'oui' }, $org ),  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             sprintf(  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 "%-10s (base 16)\t\t%s\n",  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $d->{ 'company_id' },  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $org eq 'PRIVATE' ? '' : $org,  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             ),  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         );  | 
| 
328
 | 
25
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
48
 | 
         if ( my $a = $d->{ 'address' } ) {  | 
| 
329
 | 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
             for my $x ( split( "\n", $d->{ 'address' } ) ) {  | 
| 
330
 | 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
128
 | 
                 push( @lines, "\t\t\t\t$x\n" );  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
332
 | 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
             push( @lines, "\n" );  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
334
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
             push( @lines, "\t\t\t\t\n" );  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
338
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
     return join( "", @lines );  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |