1package App::Netdisco::Worker::Plugin::Discover::Wireless;
2
3use Dancer ':syntax';
4use App::Netdisco::Worker::Plugin;
5use aliased 'App::Netdisco::Worker::Status';
6
7use App::Netdisco::Transport::SNMP ();
8use Dancer::Plugin::DBIC 'schema';
9
10register_worker({ phase => 'main', driver => 'snmp' }, sub {
11  my ($job, $workerconf) = @_;
12
13  my $device = $job->device;
14  return unless $device->in_storage;
15  my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
16    or return Status->defer("discover failed: could not SNMP connect to $device");
17
18  my $ssidlist = $snmp->i_ssidlist;
19  return unless scalar keys %$ssidlist;
20
21  # cache the device ports to save hitting the database for many single rows
22  my $device_ports = vars->{'device_ports'}
23    || { map {($_->port => $_)} $device->ports->all };
24
25  my $interfaces = $snmp->interfaces;
26  my $ssidbcast  = $snmp->i_ssidbcast;
27  my $ssidmac    = $snmp->i_ssidmac;
28  my $channel    = $snmp->i_80211channel;
29  my $power      = $snmp->dot11_cur_tx_pwr_mw;
30
31  # build device ssid list suitable for DBIC
32  my @ssids;
33  foreach my $entry (keys %$ssidlist) {
34      (my $iid = $entry) =~ s/\.\d+$//;
35      my $port = $interfaces->{$iid};
36
37      if (not $port) {
38          debug sprintf ' [%s] wireless - ignoring %s (no port mapping)',
39            $device->ip, $iid;
40          next;
41      }
42
43      if (!defined $device_ports->{$port}) {
44          debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
45            $device->ip, $port;
46          next;
47      }
48
49      push @ssids, {
50          port      => $port,
51          ssid      => $ssidlist->{$entry},
52          broadcast => $ssidbcast->{$entry},
53          bssid     => $ssidmac->{$entry},
54      };
55  }
56
57  schema('netdisco')->txn_do(sub {
58    my $gone = $device->ssids->delete;
59    debug sprintf ' [%s] wireless - removed %d SSIDs',
60      $device->ip, $gone;
61    $device->ssids->populate(\@ssids);
62    debug sprintf ' [%s] wireless - added %d new SSIDs',
63      $device->ip, scalar @ssids;
64  });
65
66  # build device channel list suitable for DBIC
67  my @channels;
68  foreach my $entry (keys %$channel) {
69      my $port = $interfaces->{$entry};
70
71      if (not $port) {
72          debug sprintf ' [%s] wireless - ignoring %s (no port mapping)',
73            $device->ip, $entry;
74          next;
75      }
76
77      if (!defined $device_ports->{$port}) {
78          debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
79            $device->ip, $port;
80          next;
81      }
82
83      push @channels, {
84          port    => $port,
85          channel => $channel->{$entry},
86          power   => $power->{$entry},
87      };
88  }
89
90  schema('netdisco')->txn_do(sub {
91    my $gone = $device->wireless_ports->delete;
92    debug sprintf ' [%s] wireless - removed %d wireless channels',
93      $device->ip, $gone;
94    $device->wireless_ports->populate(\@channels);
95
96    return Status->info(sprintf ' [%s] wireless - added %d new wireless channels',
97      $device->ip, scalar @channels);
98  });
99});
100
101true;
102