1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef SHILL_WIFI_MAC80211_MONITOR_H_
18#define SHILL_WIFI_MAC80211_MONITOR_H_
19
20#include <time.h>
21
22#include <string>
23#include <vector>
24
25#include <base/callback.h>
26#include <base/cancelable_callback.h>
27#include <base/files/file_path.h>
28#include <base/macros.h>
29#include <base/memory/weak_ptr.h>
30#include <gtest/gtest_prod.h>  // for FRIEND_TEST
31
32namespace shill {
33
34class EventDispatcher;
35class Metrics;
36class Time;
37
38class Mac80211Monitor {
39 public:
40  struct QueueState {
41    QueueState(size_t queue_number_in,
42               uint32_t stop_flags_in,
43               size_t queue_length_in)
44    : queue_number(queue_number_in), stop_flags(stop_flags_in),
45      queue_length(queue_length_in) {}
46
47    size_t queue_number;
48    uint32_t stop_flags;
49    size_t queue_length;
50  };
51
52  Mac80211Monitor(EventDispatcher* dispatcher,
53                  const std::string& link_name,
54                  size_t queue_length_limit,
55                  const base::Closure& on_repair_callback,
56                  Metrics* metrics);
57  virtual ~Mac80211Monitor();
58
59  virtual void Start(const std::string& phy_name);
60  virtual void Stop();
61  virtual void UpdateConnectedState(bool new_state);
62
63  const std::string& link_name() const { return link_name_; }
64
65 private:
66  friend class Mac80211MonitorTest;
67  FRIEND_TEST(Mac80211MonitorTest, CheckAreQueuesStuckMultipleReasons);
68  FRIEND_TEST(Mac80211MonitorTest, CheckAreQueuesStuckMultipleQueues);
69  FRIEND_TEST(Mac80211MonitorTest, CheckAreQueuesStuckNotStuck);
70  FRIEND_TEST(Mac80211MonitorTest, CheckAreQueuesStuckQueueLength);
71  FRIEND_TEST(Mac80211MonitorTest,
72              CheckAreQueuesStuckQueueLengthIgnoresUnstopped);
73  FRIEND_TEST(Mac80211MonitorTest, CheckAreQueuesStuckSingleReason);
74  FRIEND_TEST(Mac80211MonitorTest, ParseQueueStateBadInput);
75  FRIEND_TEST(Mac80211MonitorTest, ParseQueueStateSimple);
76  FRIEND_TEST(Mac80211MonitorTest, ParseQueueStateStopped);
77
78  static const size_t kMaxQueueStateSizeBytes;
79  static const char kQueueStatusPathFormat[];
80  static const char kWakeQueuesPathFormat[];
81  static const time_t kQueueStatePollIntervalSeconds;
82  static const time_t kMinimumTimeBetweenWakesSeconds;
83
84  // Values must be kept in sync with ieee80211_i.h.
85  enum QueueStopReason {
86    kStopReasonDriver,
87    kStopReasonPowerSave,
88    kStopReasonChannelSwitch,
89    kStopReasonAggregation,
90    kStopReasonSuspend,
91    kStopReasonBufferAdd,
92    kStopReasonChannelTypeChange,
93    kStopReasonMax = kStopReasonChannelTypeChange
94  };
95  enum QueueStopFlag {
96    kStopFlagDriver = 1 << kStopReasonDriver,
97    kStopFlagPowerSave = 1 << kStopReasonPowerSave,
98    kStopFlagChannelSwitch = 1 << kStopReasonChannelSwitch,
99    kStopFlagAggregation = 1 << kStopReasonAggregation,
100    kStopFlagSuspend = 1 << kStopReasonSuspend,
101    kStopFlagBufferAdd = 1 << kStopReasonBufferAdd,
102    kStopFlagChannelTypeChange = 1 << kStopReasonChannelTypeChange,
103    kStopFlagInvalid
104  };
105
106  void StartTimer();
107  void StopTimer();
108
109  // Check if queues need to be woken. If so, and we haven't woken them
110  // too recently, then wake them now.
111  void WakeQueuesIfNeeded();
112
113  // Check |queue_states|, to determine if any queues are stuck.
114  // Returns a bitmask of QueueStopFlags. A flag will be set if
115  // any of the queues has that flag set, and is non-empty.
116  // A return value if 0 indicates no queues are stuck.
117  uint32_t CheckAreQueuesStuck(const std::vector<QueueState>& queue_states);
118
119  static std::vector<QueueState> ParseQueueState(
120      const std::string& state_string);
121  static QueueStopFlag GetFlagForReason(QueueStopReason reason);
122
123  Time* time_;  // for mocking in tests
124  EventDispatcher* dispatcher_;
125  const std::string link_name_;
126  size_t queue_length_limit_;
127  base::Closure on_repair_callback_;
128  Metrics* metrics_;
129  std::string phy_name_;
130  time_t last_woke_queues_monotonic_seconds_;
131  bool is_running_;
132  bool have_ever_read_queue_state_file_;
133  base::FilePath queue_state_file_path_;
134  base::FilePath wake_queues_file_path_;
135  base::CancelableClosure check_queues_callback_;
136  bool is_device_connected_;
137  base::WeakPtrFactory<Mac80211Monitor> weak_ptr_factory_;  // keep last
138
139  DISALLOW_COPY_AND_ASSIGN(Mac80211Monitor);
140};
141
142}  // namespace shill
143
144#endif  // SHILL_WIFI_MAC80211_MONITOR_H_
145