- adb 通过网络连接很不方便
- 开机之后有时候不能自动获取到IP地址
- 不支持USB无线网卡
之前配置的kernel configuration只是保证Raspberrry Pi 2B(树莓派)能够运行起来并且当时手中并没有一块能用的USB网卡,所以无线网卡的驱动没有有包含进去。近日在网上买了个EDUP-EPN8508GS的usb无线网卡。重新配置了一下kernel的参数,相关的配置文件可以从这里下载:rpi2b-brillo-rtl8192cu-kconfig.gz。同时还需要修改一下kernel的代码(原来kernel中也有这个网卡的驱动,同时驱动中也包含所需的固件,无耐发现iw无法识别,只能使用另外一份驱动。相关的做法如下:
回退相关的patch:
$ cd hardware/bsp/kernel/hzak/rpi-4.1.y $ git revert ff0b85db2322f6454c4c10634678c0c8b0f8a9cd $ git revert 3dc2a38d0437635d471babdc78c99244aec06aaf $ git revert 6d4d3a978afbc332af02e548bd0e8ced16dff296
或者是直接修改drivers/net/wireless/kconfig文件,使用drivers/net/wireless/rtlwifi的驱动:
source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/mediatek/Kconfig" source "drivers/net/wireless/rtlwifi/Kconfig" #source "drivers/net/wireless/rtl8192cu/Kconfig" source "drivers/net/wireless/ti/Kconfig"
修改完之后,就可以用上面提交的kernel配置文件重新编译kernel了。运行之后,就可以用iw进行相关的操作了,如查看网卡的基本信息:
$ adb shell iw dev phy#0 Interface wlan0 ifindex 4 wdev 0x1 addr e8:4e:06:33:41:2e type managed
- USB无线网卡需要的固件没办法自动获取
之前kernel的配置同样没办法让kernel通知udev去加载固件(这个方法貌似不太好,kernel中有相关的文档说明 driver/base/Kconfig):
config FW_LOADER_USER_HELPER_FALLBACK bool "Fallback user-helper invocation for firmware loading" depends on FW_LOADER select FW_LOADER_USER_HELPER help This option enables / disables the invocation of user-helper (e.g. udev) for loading firmware files as a fallback after the direct file loading in kernel fails. The user-mode helper is no longer required unless you have a special firmware file that resides in a non-standard path. Moreover, the udev support has been deprecated upstream.
当有个这个配置,kernel就可以通过udev来加载固件了。
driver调用request firmware, 会先从指定的path或builtin中找,如果没有找到,再调用firmware_uevent()通知uevent进行加载固件,system/core/init/devices.cpp中包含相关的实现。
NOTE: 可以参考这里:https://wiki.ubuntu.com/Kernel/Firmware。
- kernel包含cfg80211/nl80211的代码后,需要更新world regulatory domain
在运行时,kernel log中会有这样的信息:cfg80211: Calling CRDA to update world regulatory domain
相关的文档可以看这里hardware/bsp/kernel/hzak/rpi-4.1.y/net/wireless/db.txt以及http://wireless.kernel.org/en/developers/Regulatory
- firewalld没办法调用iptables去更新防火墙
在logcat中会有如下信息:
12-20 09:15:22.591 +0000 177 177 I /system/bin/webservd: [INFO:server.cc(119)] Firewall service is on-line. Opening firewall for protocol handlers 12-20 09:15:22.595 +0000 148 148 I /system/bin/firewalld: Punching hole for TCP port 80 on interface '' 12-20 09:15:22.624 +0000 148 148 E /system/bin/firewalld: Could not add ACCEPT rule using '/system/bin/iptables' 12-20 09:15:22.625 +0000 148 148 E /system/bin/firewalld: Adding ACCEPT rules failed 12-20 09:15:22.627 +0000 177 177 E /system/bin/webservd: [ERROR:server.cc(53)] Failed to open up port 80, interface: 12-20 09:15:22.627 +0000 148 148 I /system/bin/firewalld: Punching hole for TCP port 443 on interface '' 12-20 09:15:22.656 +0000 148 148 E /system/bin/firewalld: Could not add ACCEPT rule using '/system/bin/iptables' 12-20 09:15:22.657 +0000 148 148 E /system/bin/firewalld: Adding ACCEPT rules failed 12-20 09:15:22.659 +0000 177 177 E /system/bin/webservd: [ERROR:server.cc(53)] Failed to open up port 443, interface:
从log可以知道,当firewalld运行的时候,webservd会通知firewalld去开放80和443端口,而firewalld收到信息后会去执行iptables程序开放这两个端口,但是很显然,iptables执行失败了。
在system/firewalld/iptables.cc中相关的代码如下:
bool IpTables::PunchTcpHole(uint16_t in_port, const std::string& in_interface) { return PunchHole(in_port, in_interface, &tcp_holes_, kProtocolTcp); } bool IpTables::PunchHole(uint16_t port, const std::string& interface, std::set<Hole>* holes, ProtocolEnum protocol) { if (port == 0) { // Port 0 is not a valid TCP/UDP port. return false; } if (!IsValidInterfaceName(interface)) { LOG(ERROR) << "Invalid interface name '" << interface << "'"; return false; } Hole hole = std::make_pair(port, interface); if (holes->find(hole) != holes->end()) { // We have already punched a hole for |port| on |interface|. // Be idempotent: do nothing and succeed. return true; } std::string sprotocol = protocol == kProtocolTcp ? "TCP" : "UDP"; LOG(INFO) << "Punching hole for " << sprotocol << " port " << port << " on interface '" << interface << "'"; if (!AddAcceptRules(protocol, port, interface)) { // If the 'iptables' command fails, this method fails. LOG(ERROR) << "Adding ACCEPT rules failed"; return false; } // Track the hole we just punched. holes->insert(hole); return true; } bool IpTables::AddAcceptRules(ProtocolEnum protocol, uint16_t port, const std::string& interface) { if (!AddAcceptRule(kIpTablesPath, protocol, port, interface)) { LOG(ERROR) << "Could not add ACCEPT rule using '" << kIpTablesPath << "'"; return false; } if (AddAcceptRule(kIp6TablesPath, protocol, port, interface)) { // This worked, record this fact and insist that it works thereafter. ip6_enabled_ = true; } else if (ip6_enabled_) { // It's supposed to work, fail. LOG(ERROR) << "Could not add ACCEPT rule using '" << kIp6TablesPath << "', aborting operation"; DeleteAcceptRule(kIpTablesPath, protocol, port, interface); return false; } else { // It never worked, just ignore it. LOG(WARNING) << "Could not add ACCEPT rule using '" << kIp6TablesPath << "', ignoring"; } return true; } bool IpTables::AddAcceptRule(const std::string& executable_path, ProtocolEnum protocol, uint16_t port, const std::string& interface) { std::vector<std::string> argv; argv.push_back(executable_path); argv.push_back("-I"); // insert argv.push_back("INPUT"); argv.push_back("-p"); // protocol argv.push_back(protocol == kProtocolTcp ? "tcp" : "udp"); argv.push_back("--dport"); // destination port argv.push_back(std::to_string(port)); if (!interface.empty()) { argv.push_back("-i"); // interface argv.push_back(interface); } argv.push_back("-j"); argv.push_back("ACCEPT"); argv.push_back("-w"); // Wait for xtables lock. // Use CAP_NET_ADMIN|CAP_NET_RAW. return ExecvNonRoot(argv, kIpTablesCapMask) == 0; }
在这里可以看到在AddAcceptRule的时候需要CAP_NET_ADMIN和CAP_NET_RAW,所以这时候就会用到minijail了(相关的文档可以看这里:https://www.chromium.org/chromium-os/chromiumos-design-docs/system-hardening):
const uint64_t kIpTablesCapMask = CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_RAW); int IpTables::ExecvNonRoot(const std::vector<std::string>& argv, uint64_t capmask) { brillo::Minijail* m = brillo::Minijail::GetInstance(); minijail* jail = m->New(); #if !defined(__ANDROID__) // TODO(garnold) This needs to be re-enabled once we figure out which // unprivileged user we want to use. m->DropRoot(jail, kUnprivilegedUser, kUnprivilegedUser); #endif // __ANDROID__ m->UseCapabilities(jail, capmask); std::vector<char*> args; for (const auto& arg : argv) { args.push_back(const_cast<char*>(arg.c_str())); } args.push_back(nullptr); int status; bool ran = m->RunSyncAndDestroy(jail, args, &status); return ran ? status : -1; }
minijail相关的代码在这里:
- external/libbrillo/brillo/minijail/minijail.cc
-
external/minijail
虽然fock出了iptables, 但是在执行到external/iptables/libiptc/libiptc.c
struct xtc_handle * TC_INIT(const char *tablename) { struct xtc_handle *h; STRUCT_GETINFO info; unsigned int tmp; socklen_t s; int sockfd; retry: iptc_fn = TC_INIT; if (strlen(tablename) >= TABLE_MAXNAMELEN) { errno = EINVAL; return NULL; } sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) return NULL; // ... }
在创建IPPROTO_RAW socket的时候,需要CAP_NET & CAP_NET_RAW capablity, 在执行到下面代码的时候会,会返回-EPERM
hardware/bsp/kernel/hzak/rpi-4.1.y/net/ipv4/af_inet.c
/* * Create an inet socket. */ static int inet_create(struct net *net, struct socket *sock, int protocol, int kern) { // ... err = -EPERM; if (sock->type == SOCK_RAW && !kern && !ns_capable(net->user_ns, CAP_NET_RAW)) goto out_rcu_unlock; // ... }
奇怪的是RPi 2B的代码与brilloemulator的代码基本一样,但是brilloemulator却没有这样的问题。
更新(2015-12-27 23:21:18):brilloemulator-x86没有这个问题,但brilloemulator-arm也有这样的问题, x86使用的是android-3.18的kernel, 而arm使用的是v4.1的kernel,kernel更新,不允许minijail这么做?), 看来要在device/generic/brillo/sepolicy中添加policy文件暂时解决这个问题了。
[2016-04-12 22:16:19] 已经找到原因: ->@<-
PS: 防火墙的配置可以通过如下命令查看:
$ adb shell iptables --list Chain INPUT (policy DROP) target prot opt source destination ACCEPT tcp -- anywhere anywhere tcp dpt:https ACCEPT tcp -- anywhere anywhere tcp dpt:http ACCEPT udp -- anywhere anywhere udp spts:bootps:bootpc dpts:bootps:bootpc ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT all -- anywhere anywhere ACCEPT tcp -- anywhere anywhere tcp dpt:https ACCEPT tcp -- anywhere anywhere tcp dpt:http ACCEPT tcp -- anywhere anywhere tcp dpt:5555 ACCEPT icmp -- anywhere anywhere ACCEPT udp -- anywhere 224.0.0.251 udp dpt:mdns Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination ACCEPT udp -- anywhere anywhere udp spts:bootps:bootpc dpts:bootps:bootpc ACCEPT all -- anywhere anywhere state NEW,RELATED,ESTABLISHED ACCEPT all -- anywhere anywhere