- 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