blob: 638113949348d3dc155df076ae24b617de754392 [file] [log] [blame]
Rajat Jainebe88992021-03-05 10:52:55 -08001// Copyright 2021 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "pciguard/udev_monitor.h"
6#include "pciguard/daemon.h"
7
8namespace pciguard {
9
10namespace {
11
12const char kUdev[] = "udev";
13const char kThunderboltSubsystem[] = "thunderbolt";
14const char kThunderboltDevice[] = "thunderbolt_device";
15const char kPCISubsystem[] = "pci";
16
17} // namespace
18
19UdevMonitor::UdevMonitor(EventHandler* ev_handler, PcidevBlockedFn callback)
20 : event_handler_(ev_handler), pcidev_blocked_callback_(callback) {
21 udev_ = brillo::Udev::Create();
22 if (!udev_) {
23 PLOG(ERROR) << "Failed to initialize udev object.";
24 exit(EXIT_FAILURE);
25 }
26
27 udev_monitor_ = udev_->CreateMonitorFromNetlink(kUdev);
28 if (!udev_monitor_) {
29 PLOG(ERROR) << "Failed to create udev monitor.";
30 exit(EXIT_FAILURE);
31 }
32
33 if (!udev_monitor_->FilterAddMatchSubsystemDeviceType(kThunderboltSubsystem,
34 kThunderboltDevice)) {
35 PLOG(ERROR) << "Failed to add thunderbolt subsystem to udev monitor.";
36 exit(EXIT_FAILURE);
37 }
38
39 if (!udev_monitor_->FilterAddMatchSubsystemDeviceType(kPCISubsystem,
40 nullptr)) {
41 PLOG(ERROR) << "Failed to add PCI subsystem to udev monitor.";
42 exit(EXIT_FAILURE);
43 }
44
45 if (!udev_monitor_->EnableReceiving()) {
46 PLOG(ERROR) << "Failed to enable receiving for udev monitor.";
47 exit(EXIT_FAILURE);
48 }
49
50 int fd = udev_monitor_->GetFileDescriptor();
51 if (fd == brillo::UdevMonitor::kInvalidFileDescriptor) {
52 PLOG(ERROR) << "Failed to get udev monitor fd.";
53 exit(EXIT_FAILURE);
54 }
55
56 udev_monitor_watcher_ = base::FileDescriptorWatcher::WatchReadable(
57 fd,
58 base::BindRepeating(&UdevMonitor::OnUdevEvent, base::Unretained(this)));
59 if (!udev_monitor_watcher_) {
60 PLOG(ERROR) << "Failed to start watcher for udev monitor fd.";
61 exit(EXIT_FAILURE);
62 }
63}
64
65void UdevMonitor::OnUdevEvent() {
66 auto device = udev_monitor_->ReceiveDevice();
67 if (!device) {
68 LOG(ERROR) << "Udev receive device failed.";
69 return;
70 }
71
72 auto path = base::FilePath(device->GetSysPath());
73 if (path.empty()) {
74 LOG(ERROR) << "Failed to get device syspath.";
75 return;
76 }
77
78 auto action = std::string(device->GetAction());
79 if (action.empty()) {
80 LOG(ERROR) << "Failed to get device action.";
81 return;
82 }
83
84 auto subsystem = std::string(device->GetSubsystem());
85 if (subsystem.empty()) {
86 LOG(ERROR) << "Failed to get device subsystem";
87 return;
88 }
89
90 if (subsystem == "thunderbolt") {
91 if (action == "add" || action == "remove")
92 LOG(INFO) << "UdevEvent: " << subsystem << " " << action << " " << path;
93
94 if (action == "add")
95 event_handler_->OnNewThunderboltDev(path);
96
Rajat Jain079411e2021-05-19 18:54:12 +000097 } else if (subsystem == "pci" && action == "change") {
98 auto property = device->GetPropertyValue("EVENT");
99 auto event = std::string(property ? property : "");
Rajat Jainebe88992021-03-05 10:52:55 -0800100
Rajat Jain079411e2021-05-19 18:54:12 +0000101 property = device->GetPropertyValue("DRVR");
102 auto drvr = std::string(property ? property : "");
Rajat Jainebe88992021-03-05 10:52:55 -0800103
Rajat Jain079411e2021-05-19 18:54:12 +0000104 LOG(INFO) << "UdevEvent: " << subsystem << " " << action << " " << event
105 << " " << drvr << " " << path;
Rajat Jainebe88992021-03-05 10:52:55 -0800106
Rajat Jain079411e2021-05-19 18:54:12 +0000107 if (event == "BLOCKED")
108 pcidev_blocked_callback_(drvr);
Rajat Jainebe88992021-03-05 10:52:55 -0800109 }
110}
111
112} // namespace pciguard