Android13 wificond scan流程分析

我们通过代码分析wificond的scan流程,在WifiScanningService的startScan流程分析中我们分析了HAL层以上的流程,下面我们继续分析HAL层的流程,首先是ScannerImpl的scan方法:

//system/connectivity/wificond/scanning/ScannerImpl.h
class ScannerImpl : public android::net::wifi::nl80211::BnWifiScannerImpl {
 private:
ScanUtils* const scan_utils_;
}
//system/connectivity/wificond/scanning/ScannerImpl.cpp
class ScannerImpl : public android::net::wifi::nl80211::BnWifiScannerImpl {
Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
                         bool* out_success) {
  if (!CheckIsValid()) {
    *out_success = false;
    return Status::ok();
  }


  if (scan_started_) {
    LOG(WARNING) << "Scan already started";
  }
  // Only request MAC address randomization when station is not associated.
  bool request_random_mac =
      wiphy_features_.supports_random_mac_oneshot_scan &&
      !client_interface_->IsAssociated();
  int scan_type = scan_settings.scan_type_;
          //wiphy_features_是硬件层直接返回的当前WLAN芯片支持的扫描类型
          //如果请求的类型不被硬件支持,则回落为SCAN_TYPE_DEFAULT
  if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) {
    LOG(DEBUG) << "Ignoring scan type because device does not support it";
    scan_type = SCAN_TYPE_DEFAULT;
  }


  // Initialize it with an empty ssid for a wild card scan.
  vector<vector<uint8_t>> ssids = {{}};


          //wiphy_features_是硬件层直接返回的当前WLAN芯片支持的扫描类型
          //如果请求的类型不被硬件支持,则回落为SCAN_TYPE_DEFAULT
  vector<vector<uint8_t>> skipped_scan_ssids;
  vector<vector<uint8_t>> skipped_long_ssids;
  for (auto& network : scan_settings.hidden_networks_) {
    if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
      skipped_scan_ssids.emplace_back(network.ssid_);
      continue;
    }
    if (network.ssid_.size() > 32) {
        skipped_long_ssids.emplace_back(network.ssid_);
        continue;
    }
    ssids.push_back(network.ssid_);
  }


  LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
  LogSsidList(skipped_long_ssids, "Skip too long ssid");


  //将扫描需要覆盖的信道频率添加到freqs向量中
  vector<uint32_t> freqs;
  for (auto& channel : scan_settings.channel_settings_) {
    freqs.push_back(channel.frequency_);
  }


  int error_code = 0;
  if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
                         scan_settings.enable_6ghz_rnr_, ssids, freqs, &error_code)) { //调用ScanUtils的Scan方法
    if (error_code == ENODEV) {
        nodev_counter_ ++;
        LOG(WARNING) << "Scan failed with error=nodev. counter=" << nodev_counter_;
    }
    CHECK(error_code != ENODEV || nodev_counter_ <= 3)
        << "Driver is in a bad state, restarting wificond";
    *out_success = false;
    return Status::ok();
  }
  nodev_counter_ = 0;
  scan_started_ = true;
  *out_success = true;
  return Status::ok();
}
}

上面的函数实现,由如下几个关键点:

  • 扫描请求中设定的扫描类型,如果与硬件上报支持的类型不匹配,则后续扫描类型会回落为SCAN_TYPE_DEFAULT;

  • 隐藏网络扫描数量有限制,最大为max_num_scan_ssids(通过NL80211_ATTR_MAX_NUM_SCAN_SSIDS属性获取)

  • 信道频率直接转存到freqs中,没有过滤;

  • 处理完数据后,将参数传入scan_utils_->Scan的函数调用中,继续后面的逻辑;

//system/connectivity/wificond/scan_utils.h
class ScanUtils {
 private:
  NetlinkManager* netlink_manager_;
}
//system/connectivity/wificond/scan_utils.cpp
bool ScanUtils::Scan(uint32_t interface_index,
                     bool request_random_mac,
                     int scan_type,
                     bool enable_6ghz_rnr,
                     const vector<vector<uint8_t>>& ssids,
                     const vector<uint32_t>& freqs,
                     int* error_code) {
  //构造一个NL80211Packet,命令为NL80211_CMD_TRIGGER_SCAN
  NL80211Packet trigger_scan(
      netlink_manager_->GetFamilyId(),
      NL80211_CMD_TRIGGER_SCAN,
      netlink_manager_->GetSequenceNumber(),
      getpid());
  // If we do not use NLM_F_ACK, we only receive a unicast repsonse
  // when there is an error. If everything is good, scan results notification
  // will only be sent through multicast.
  // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
  // ERROR or an ACK message. The handler will always be called and removed by
  // NetlinkManager.
  trigger_scan.AddFlag(NLM_F_ACK);
  //构造NL80211Attr,key为NL80211_ATTR_IFINDEX,value为interface_index
  NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);


  //构造NL80211Attr,key为NL80211_ATTR_IFINDEX,value为interface_index
  NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
  for (size_t i = 0; i < ssids.size(); i++) {
    ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
  }


  //频率添加方式与上面ssids_attr类似
  NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
  for (size_t i = 0; i < freqs.size(); i++) {
    freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
  }
  //将上面构造的NL80211Attr/NL80211NestedAttr添加进trigger_scan这个NL80211Packet
  trigger_scan.AddAttribute(if_index_attr);
  trigger_scan.AddAttribute(ssids_attr);
  // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
  // scan all supported frequencies.
  if (!freqs.empty()) {
    trigger_scan.AddAttribute(freqs_attr);
  }


  uint32_t scan_flags = 0;
  //ScannerImpl::scan中处理过的一些参数,在这里以scan_flags传递
  if (request_random_mac) {
    scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
  }
  switch (scan_type) {
    case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN:
      scan_flags |= NL80211_SCAN_FLAG_LOW_SPAN;
      break;
    case IWifiScannerImpl::SCAN_TYPE_LOW_POWER:
      scan_flags |= NL80211_SCAN_FLAG_LOW_POWER;
      break;
    case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY:
      scan_flags |= NL80211_SCAN_FLAG_HIGH_ACCURACY;
      break;
    case IWifiScannerImpl::SCAN_TYPE_DEFAULT:
      break;
    default:
      CHECK(0) << "Invalid scan type received: " << scan_type;
  }
  if (enable_6ghz_rnr) {
    scan_flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
  }
  //最后,将scan_flags封装进trigger_scan这个NL80211Packet
  if (scan_flags) {
    trigger_scan.AddAttribute(
        NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
                              scan_flags));
    LOG(DEBUG) << "Triggering scan with scan_flag=" << scan_flags;
  }
  // We are receiving an ERROR/ACK message instead of the actual
  // scan results here, so it is OK to expect a timely response because
  // kernel is supposed to send the ERROR/ACK back before the scan starts.
  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
                                                     error_code)) { //调用NetlinkManager的SendMessageAndGetAckOrError方法
    // Logging is done inside |SendMessageAndGetAckOrError|.
    return false;
  }
  if (*error_code != 0) {
    LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
    return false;
  }
  return true;
}

可见,ScanUtils::Scan大部分逻辑还是参数的处理、封装,最后整合到名为trigger_scan的一个NL80211Packet结构体中,并通过netlink_manager_->SendMessageAndGetAckOrError发送出去;

//system/connectivity/wificond/net/netlink_manager.h
class NetlinkManager {
}
//system/connectivity/wificond/net/netlink_manager.cpp
bool NetlinkManager::SendMessageAndGetAckOrError(const NL80211Packet& packet,
                                                 int* error_code) {
  unique_ptr<const NL80211Packet> response;
  if (!SendMessageAndGetSingleResponseOrError(packet, &response)) {
    return false;
  }
  uint16_t type = response->GetMessageType();
  if (type != NLMSG_ERROR) {
    LOG(ERROR) << "Receive unexpected message type :" << type;
    return false;
  }


  *error_code = response->GetErrorCode();
  return true;
}


bool NetlinkManager::SendMessageAndGetSingleResponseOrError(
    const NL80211Packet& packet,
    unique_ptr<const NL80211Packet>* response) {
  vector<unique_ptr<const NL80211Packet>> response_vec;
  if (!SendMessageAndGetResponses(packet, &response_vec)) {
    return false;
  }
  if (response_vec.size() != 1) {
    LOG(ERROR) << "Unexpected response size: " << response_vec.size();
    return false;
  }


  *response = std::move(response_vec[0]);
  return true;
}




bool NetlinkManager::SendMessageAndGetResponses(
    const NL80211Packet& packet,
    vector<unique_ptr<const NL80211Packet>>* response) {
  if (!SendMessageInternal(packet, sync_netlink_fd_.get(), sync_netlink_destination_)) {
    return false;
  }
  // Polling netlink socket, waiting for GetFamily reply.
  struct pollfd netlink_output;
  memset(&netlink_output, 0, sizeof(netlink_output));
  netlink_output.fd = sync_netlink_fd_.get();
  netlink_output.events = POLLIN;


  uint32_t sequence = packet.GetMessageSequence();


  int time_remaining = kMaximumNetlinkMessageWaitMilliSeconds;
  // Multipart messages may come with seperated datagrams, ending with a
  // NLMSG_DONE message.
  // ReceivePacketAndRunHandler() will remove the handler after receiving a
  // NLMSG_DONE message.
  message_handlers_[sequence] = std::bind(AppendPacket, response, _1);


  while (time_remaining > 0 &&
      message_handlers_.find(sequence) != message_handlers_.end()) {
    nsecs_t interval = systemTime(SYSTEM_TIME_MONOTONIC);
    int poll_return = poll(&netlink_output,
                           1,
                           time_remaining);


    if (poll_return == 0) {
      LOG(ERROR) << "Failed to poll netlink fd:" << sync_netlink_fd_.get() << "time out ";
      message_handlers_.erase(sequence);
      return false;
    } else if (poll_return == -1) {
      PLOG(ERROR) << "Failed to poll netlink fd";
      message_handlers_.erase(sequence);
      return false;
    }
    ReceivePacketAndRunHandler(sync_netlink_fd_.get()); 
    interval = systemTime(SYSTEM_TIME_MONOTONIC) - interval;
    time_remaining -= static_cast<int>(ns2ms(interval));
  }
  if (time_remaining <= 0) {
    LOG(ERROR) << "Timeout waiting for netlink reply messages";
    message_handlers_.erase(sequence);
    return false;
  }
  return true;
}

上面代码是比较多,但是调用路线很明显:SendMessageAndGetAckOrError -> SendMessageAndGetSingleResponseOrError -> SendMessageAndGetResponses -> SendMessageInternal & ReceivePacketAndRunHandler,其中SendMessageInternal的代码如下

//system/connectivity/wificond/net/netlink_manager.cpp
bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd,
    InterceptedSocket nl_destination) {
  const vector<uint8_t>& data = packet.GetConstData();
  struct sockaddr_nl sa = nl_destination;


  ssize_t bytes_sent = TEMP_FAILURE_RETRY(
      sendto(fd, data.data(), data.size(), 0, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa))
      ); //通过socket将封装好的消息数据发给内核
  if (bytes_sent == -1) {
    PLOG(ERROR) << "Failed to send netlink message";
    CHECK(!nlinterceptor::isEnabled()) << "Interceptor died, restarting wificond...";
    return false;
  }
  return true;
}

在SendMessageInternal中使用sendto函数将封装好的消息数据发给内核的wireless驱动,之后就是Linux内核的处理了。

ReceivePacketAndRunHandler的代码如下:

//system/connectivity/wificond/net/netlink_manager.cpp
void NetlinkManager::ReceivePacketAndRunHandler(int fd) {
  ssize_t len = read(fd, ReceiveBuffer, kReceiveBufferSize); //通过socket读取内部数据
  if (len == -1) {
    LOG(ERROR) << "Failed to read packet from buffer on fd: " << fd;
    perror(" netlink error ");
    return;
  }
  if (len == 0) {
    return;
  }
  // There might be multiple message in one datagram payload.
  uint8_t* ptr = ReceiveBuffer;
  while (ptr < ReceiveBuffer + len) {
    // peek at the header.
    if (ptr + sizeof(nlmsghdr) > ReceiveBuffer + len) {
      LOG(ERROR) << "payload is broken.";
      return;
    }
    const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(ptr);
    unique_ptr<NL80211Packet> packet(
        new NL80211Packet(vector<uint8_t>(ptr, ptr + nl_header->nlmsg_len)));
    ptr += nl_header->nlmsg_len;
    if (!packet->IsValid()) {
      LOG(ERROR) << "Receive invalid packet";
      return;
    }
    // Some document says message from kernel should have port id equal 0.
    // However in practice this is not always true so we don't check that.


    uint32_t sequence_number = packet->GetMessageSequence();


    // Handle multicasts.
    if (sequence_number == kBroadcastSequenceNumber) {
      BroadcastHandler(std::move(packet));
      continue;
    }


    auto itr = message_handlers_.find(sequence_number);
    // There is no handler for this sequence number.
    if (itr == message_handlers_.end()) {
      LOG(WARNING) << "No handler for message: " << sequence_number;
      return;
    }
    // A multipart message is terminated by NLMSG_DONE.
    // In this case we don't need to run the handler.
    // NLMSG_NOOP means no operation, message must be discarded.
    uint32_t message_type =  packet->GetMessageType();
    if (message_type == NLMSG_DONE || message_type == NLMSG_NOOP) {
      message_handlers_.erase(itr);
      return;
    }
    if (message_type == NLMSG_OVERRUN) {
      LOG(ERROR) << "Get message overrun notification";
      message_handlers_.erase(itr);
      return;
    }


    // In case we receive a NLMSG_ERROR message:
    // NLMSG_ERROR could be either an error or an ACK.
    // It is an ACK message only when error code field is set to 0.
    // An ACK could be return when we explicitly request that with NLM_F_ACK.
    // An ERROR could be received on NLM_F_ACK or other failure cases.
    // We should still run handler in this case, leaving it for the caller
    // to decide what to do with the packet.


    bool is_multi = packet->IsMulti();
    // Run the handler.
    itr->second(std::move(packet));
    // Remove handler after processing.
    if (!is_multi) {
      message_handlers_.erase(itr);
    }
  }
}

在ReceivePacketAndRunHandler中使用read函数读取内核的wireless驱动的消息数据,然后对消息的解析、分发、处理。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值