android 修改ip的scope的作用,Android Netd分析

1.文章介绍

Netd模块是Android中专门负责网络管理和控制的后台守护进程,本篇文章主要分析Netd的工作流程,对Netd有一个在框架层次上的理解。

2.干货

1.Netd模块源码位置

源码位置根目录/system/netd/

2.入口函数

/system/netd/main.cpp

int main() {

CommandListener *cl;

NetlinkManager *nm;

DnsProxyListener *dpl;

MDnsSdListener *mdnsl;

blockSigpipe();

if (!(nm = NetlinkManager::Instance())) {

ALOGE("Unable to create NetlinkManager");

exit(1);

};

UidMarkMap *rangeMap = new UidMarkMap();

cl = new CommandListener(rangeMap);

nm->setBroadcaster((SocketListener *) cl);

if (nm->start()) {

ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));

exit(1);

}

setenv("ANDROID_DNS_MODE", "local", 1);

dpl = new DnsProxyListener(rangeMap);

if (dpl->startListener()) {

ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));

exit(1);

}

mdnsl = new MDnsSdListener();

if (mdnsl->startListener()) {

ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));

exit(1);

}

/*

* Now that we're up, we can respond to commands

*/

if (cl->startListener()) {

ALOGE("Unable to start CommandListener (%s)", strerror(errno));

exit(1);

}

// Eventually we'll become the monitoring thread

while(1) {

sleep(1000);

}

ALOGI("Netd exiting");

exit(0);

}

可以看出以下类的重要性:

NetlinkManager *nm;

CommandListener *cl;

DnsProxyListener、MDnsSdListener涉及到Android DNS模块的处理,本文暂不作分析。

1.NetlinkManager分析

首先了解下NetLink是什么,在linux下NetLink是一个异步通信机制的socket,区别于系统调用和ioctl的同步调用机制。

可以看到/system/netd/NetlinkManager .cpp这种懒汉单实例模式:

NetlinkManager *NetlinkManager::sInstance = NULL;

NetlinkManager *NetlinkManager::Instance() {

if (!sInstance)

sInstance = new NetlinkManager();

return sInstance;

}

NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,

int groups, int format) {

struct sockaddr_nl nladdr;

int sz = 64 * 1024;

int on = 1;

memset(&nladdr, 0, sizeof(nladdr));

nladdr.nl_family = AF_NETLINK;

nladdr.nl_pid = getpid();

nladdr.nl_groups = groups;

if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {

ALOGE("Unable to create netlink socket: %s", strerror(errno));

return NULL;

}

if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {

ALOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));

close(*sock);

return NULL;

}

if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {

SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));

close(*sock);

return NULL;

}

if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {

ALOGE("Unable to bind netlink socket: %s", strerror(errno));

close(*sock);

return NULL;

}

NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);

if (handler->start()) {

ALOGE("Unable to start NetlinkHandler: %s", strerror(errno));

close(*sock);

return NULL;

}

return handler;

}

int NetlinkManager::start() {

if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,

0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {

return -1;

}

if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,

RTMGRP_LINK |

RTMGRP_IPV4_IFADDR |

RTMGRP_IPV6_IFADDR,

NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {

return -1;

}

if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,

NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {

ALOGE("Unable to open quota2 logging socket");

// TODO: return -1 once the emulator gets a new kernel.

}

return 0;

}

NetlinkManager主要是向kernel注册三个用于接收UEvent事件的socket

1.NETLINK_KOBJECT_UEVENT

一般是/sys/class/net模块下的加载和卸载消息

2.RTMGRP_LINK、RTMGRP_IPV4_IFADDR、RTMGRP_IPV6_IFADDR

一般是网络链路接通或断开时的消息

3.NETLINK_NFLOG

一般和带宽控制有关

从上面源码中可以看到三个UEvent事件分别对应了mUeventHandler 、mRouteHandler 、mQuotaHandler,而这三个事件在Netd模块都声明为NetlinkHandler。

void NetlinkHandler::onEvent(NetlinkEvent *evt) {

const char *subsys = evt->getSubsystem();

if (!subsys) {

ALOGW("No subsystem found in netlink event");

return;

}

if (!strcmp(subsys, "net")) {

int action = evt->getAction();

const char *iface = evt->findParam("INTERFACE");

if (action == evt->NlActionAdd) {

notifyInterfaceAdded(iface);

}

...

}

}

NetlinkHandler收到的socket消息就是通过onEvent回调处理的。

例如:

void NetlinkHandler::notifyInterfaceAdded(const char *name) {

char msg[255];

snprintf(msg, sizeof(msg), "Iface added %s", name);

mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,

msg, false);

}

这里间接调用了SocketListener发送一个消息。

源码位置:\system\core\libsysutils\src:

f752b2019c97

image.png

void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {

mListen = listen;

mSocketName = socketName;

mSock = socketFd;

mUseCmdNum = useCmdNum;

pthread_mutex_init(&mClientsLock, NULL);

mClients = new SocketClientCollection();

}

int SocketListener::startListener() {

...

if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {

SLOGE("pthread_create (%s)", strerror(errno));

return -1;

}

return 0;

}

void *SocketListener::threadStart(void *obj) {

SocketListener *me = reinterpret_cast(obj);

me->runListener();

pthread_exit(NULL);

return NULL;

}

void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {

pthread_mutex_lock(&mClientsLock);

SocketClientCollection::iterator i;

for (i = mClients->begin(); i != mClients->end(); ++i) {

// broadcasts are unsolicited and should not include a cmd number

if ((*i)->sendMsg(code, msg, addErrno, false)) {

SLOGW("Error sending broadcast (%s)", strerror(errno));

}

}

pthread_mutex_unlock(&mClientsLock);

}

...

每一个SockectListener都会单独创建一个线程用于接收socket消息。当Kernel发送UEvent消息后,就可以通过子类onDataAvailable函数回调回去处理。

void SocketListener::runListener() {

SocketClientCollection *pendingList = new SocketClientCollection();

while(1) {

SocketClientCollection::iterator it;

fd_set read_fds;

int rc = 0;

int max = -1;

FD_ZERO(&read_fds);

if (mListen) {

max = mSock;

FD_SET(mSock, &read_fds);

}

...

if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {

...

}

if (!onDataAvailable(c) && mListen) {

...

}

}

比如NetlinkListener是SocketListener的派生,在接收到Kernel的Uevent消息后,先通过NetlinkEvent解析消息,然后通过onEvent接口回调处理,在NetlinkHandler中最终江通过Broadcaster转发出去。

NetlinkListener::NetlinkListener(int socket) :

SocketListener(socket, false) {

mFormat = NETLINK_FORMAT_ASCII;

}

bool NetlinkListener::onDataAvailable(SocketClient *cli)

{

int socket = cli->getSocket();

ssize_t count;

uid_t uid = -1;

count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(

socket, mBuffer, sizeof(mBuffer), &uid));

if (count < 0) {

if (uid > 0)

LOG_EVENT_INT(65537, uid);

SLOGE("recvmsg failed (%s)", strerror(errno));

return false;

}

NetlinkEvent *evt = new NetlinkEvent();

if (!evt->decode(mBuffer, count, mFormat)) {

SLOGE("Error decoding NetlinkEvent");

} else {

onEvent(evt);

}

delete evt;

return true;

}

从SocketListener::sendBroadcast方法中可以看到,消息是通过FrameworkClient转发的:

FrameworkClient::FrameworkClient(int socket) {

mSocket = socket;

pthread_mutex_init(&mWriteMutex, NULL);

}

int FrameworkClient::sendMsg(const char *msg) {

int ret;

if (mSocket < 0) {

errno = EHOSTUNREACH;

return -1;

}

pthread_mutex_lock(&mWriteMutex);

ret = TEMP_FAILURE_RETRY(write(mSocket, msg, strlen(msg) +1));

if (ret < 0) {

SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));

}

pthread_mutex_unlock(&mWriteMutex);

return 0;

}

int FrameworkClient::sendMsg(const char *msg, const char *data) {

size_t bufflen = strlen(msg) + strlen(data) + 1;

char *buffer = (char *) alloca(bufflen);

if (!buffer) {

errno = -ENOMEM;

return -1;

}

snprintf(buffer, bufflen, "%s%s", msg, data);

return sendMsg(buffer);

}

而在Android Framework层的NetworkManagementService实现中,可以看到通过NativeDaemonConnector对netd的sockect监听,当FrameworkClient转发消息到socket时,NativeDaemonConnector就会取出消息然后通过java层的Observer转发出去,进而实现底层消息的上报:

private static final String NETD_SOCKET_NAME = "netd";

public static NetworkManagementService create(Context context) throws InterruptedException {

return create(context, NETD_SOCKET_NAME);

}

static NetworkManagementService create(Context context,

String socket) throws InterruptedException {

final NetworkManagementService service = new NetworkManagementService(context, socket);

final CountDownLatch connectedSignal = service.mConnectedSignal;

if (DBG) Slog.d(TAG, "Creating NetworkManagementService");

service.mThread.start();

if (DBG) Slog.d(TAG, "Awaiting socket connection");

connectedSignal.await();

if (DBG) Slog.d(TAG, "Connected");

return service;

}

private NetworkManagementService(Context context, String socket) {

mContext = context;

if ("simulator".equals(SystemProperties.get("ro.product.device"))) {

return;

}

mConnector = new NativeDaemonConnector(

new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);

mThread = new Thread(mConnector, NETD_TAG);

// Add ourself to the Watchdog monitors.

Watchdog.getInstance().addMonitor(this);

}

private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {

...

@Override

public boolean onEvent(int code, String raw, String[] cooked) {

switch (code) {

case NetdResponseCode.InterfaceChange:

...

case NetdResponseCode.InterfaceClassActivity:

/*

* An network interface class state changed (active/idle)

* Format: "NNN IfaceClass "

*/

if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {

throw new IllegalStateException(

String.format("Invalid event from daemon (%s)", raw));

}

boolean isActive = cooked[2].equals("active");

notifyInterfaceClassActivity(cooked[3], isActive);

return true;

...

}

}

}

/**

* Notify our observers of a change in the data activity state of the interface

*/

private void notifyInterfaceClassActivity(String label, boolean active) {

final int length = mObservers.beginBroadcast();

for (int i = 0; i < length; i++) {

try {

mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(label, active);

} catch (RemoteException e) {

} catch (RuntimeException e) {

}

}

mObservers.finishBroadcast();

}

final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {

NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,

int responseQueueSize, String logTag, int maxLogSize) {

mCallbacks = callbacks;

mSocket = socket;

mResponseQueue = new ResponseQueue(responseQueueSize);

mSequenceNumber = new AtomicInteger(0);

TAG = logTag != null ? logTag : "NativeDaemonConnector";

mLocalLog = new LocalLog(maxLogSize);

}

@Override

public void run() {

mCallbackHandler = new Handler(FgThread.get().getLooper(), this);

while (true) {

try {

listenToSocket();

} catch (Exception e) {

loge("Error in NativeDaemonConnector: " + e);

SystemClock.sleep(5000);

}

}

}

private void listenToSocket() throws IOException {

LocalSocket socket = null;

try {

socket = new LocalSocket();

LocalSocketAddress address = determineSocketAddress();

socket.connect(address);

InputStream inputStream = socket.getInputStream();

synchronized (mDaemonLock) {

mOutputStream = socket.getOutputStream();

}

mCallbacks.onDaemonConnected();

byte[] buffer = new byte[BUFFER_SIZE];

int start = 0;

while (true) {

...

mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(

event.getCode(), event.getRawEvent()));

...

}

}

Android Framework层核心类ConnectivityService中,事件的广播:

public ConnectivityService(Context context, INetworkManagementService netManager,

INetworkStatsService statsService, INetworkPolicyManager policyManager,

NetworkFactory netFactory) {

...

try {

mNetd.registerObserver(mTethering);

mNetd.registerObserver(mDataActivityObserver);

mNetd.registerObserver(mClat);

} catch (RemoteException e) {

loge("Error registering observer :" + e);

}

}

private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {

@Override

public void interfaceClassDataActivityChanged(String label, boolean active) {

int deviceType = Integer.parseInt(label);

sendDataActivityBroadcast(deviceType, active);

}

};

private void sendDataActivityBroadcast(int deviceType, boolean active) {

Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);

intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);

intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);

final long ident = Binder.clearCallingIdentity();

try {

mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,

RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);

} finally {

Binder.restoreCallingIdentity(ident);

}

}

public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub {

@Override

public void interfaceStatusChanged(String iface, boolean up) {

// default no-op

}

@Override

public void interfaceRemoved(String iface) {

// default no-op

}

@Override

public void addressUpdated(String address, String iface, int flags, int scope) {

// default no-op

}

@Override

public void addressRemoved(String address, String iface, int flags, int scope) {

// default no-op

}

@Override

public void interfaceLinkStateChanged(String iface, boolean up) {

// default no-op

}

@Override

public void interfaceAdded(String iface) {

// default no-op

}

@Override

public void interfaceClassDataActivityChanged(String label, boolean active) {

// default no-op

}

@Override

public void limitReached(String limitName, String iface) {

// default no-op

}

}

分析到这一步,已经可以看到sendOrderedBroadcastAsUser这个接口,同学你应该很开心了吧!其他如interfaceAdded、interfaceRemoved、interfaceStatusChanged、interfaceLinkStateChanged等接口的事件上报亦可以按以上思路在源码中找到对应的实现。

以下是参考了深入理解Andoriod卷画的NetLinkManager工作流程图:

f752b2019c97

NetLinkManager工作流程

2.CommandListener

主要作用是把从Framework层NetworkManageService接收的指令转交到对应的指令对象去处理。

CommandListener::CommandListener(UidMarkMap *map) :

FrameworkListener("netd", true) {

registerCmd(new InterfaceCmd());

registerCmd(new IpFwdCmd());

registerCmd(new TetherCmd());

registerCmd(new NatCmd());

registerCmd(new ListTtysCmd());

registerCmd(new PppdCmd());

registerCmd(new SoftapCmd());

registerCmd(new BandwidthControlCmd());

registerCmd(new IdletimerControlCmd());

registerCmd(new ResolverCmd());

registerCmd(new FirewallCmd());

registerCmd(new ClatdCmd());

registerCmd(new SambaControlCmd());

registerCmd(new TraceRouteControlCmd());

registerCmd(new BridgeControlCmd());

if (!sSecondaryTableCtrl)

sSecondaryTableCtrl = new SecondaryTableController(map);

if (!sTetherCtrl)

sTetherCtrl = new TetherController();

if (!sNatCtrl)

sNatCtrl = new NatController(sSecondaryTableCtrl);

if (!sPppCtrl)

sPppCtrl = new PppController();

if (!sSoftapCtrl)

sSoftapCtrl = new SoftapController();

if (!sBandwidthCtrl)

sBandwidthCtrl = new BandwidthController();

if (!sIdletimerCtrl)

sIdletimerCtrl = new IdletimerController();

if (!sResolverCtrl)

sResolverCtrl = new ResolverController();

if (!sFirewallCtrl)

sFirewallCtrl = new FirewallController();

if (!sInterfaceCtrl)

sInterfaceCtrl = new InterfaceController();

if (!sClatdCtrl)

sClatdCtrl = new ClatdController();

if (!sSambaCtrl)

sSambaCtrl = new SambaController();

if (!sTraceRouteCtrl)

sTraceRouteCtrl = new TraceRouteController();

if (!sBridgeCtrl)

sBridgeCtrl = new BridgeController();

// Create chains for children modules

createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);

createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);

createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);

createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);

createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);

createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT);

createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);

createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);

// Let each module setup their child chains

setupOemIptablesHook();

sFirewallCtrl->setupIptablesHooks();

/* Does DROPs in FORWARD by default */

sNatCtrl->setupIptablesHooks();

/*

* Does REJECT in INPUT, OUTPUT. Does counting also.

* No DROP/REJECT allowed later in netfilter-flow hook order.

*/

sBandwidthCtrl->setupIptablesHooks();

/*

* Counts in nat: PREROUTING, POSTROUTING.

* No DROP/REJECT allowed later in netfilter-flow hook order.

*/

sIdletimerCtrl->setupIptablesHooks();

sBandwidthCtrl->enableBandwidthControl(false);

sSecondaryTableCtrl->setupIptablesHooks();

}

CommandListener是从FrameworkListener派生,在FrameworkListener内部有一个数组mCommands来存储注册到FrameworkListener中的命令处理对象。

FrameworkListener从SocketListener派生,在第一节分析SocketListener时就已经说过每一个SocketListener就是一个单独的线程用于接收sockect消息,当接收到sockect端消息时,就会回调onDataAvailable接口:

FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :

SocketListener(socketName, true, withSeq) {

init(socketName, withSeq);

}

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {

mCommands->push_back(cmd);

}

bool FrameworkListener::onDataAvailable(SocketClient *c) {

...

dispatchCommand(c, buffer + offset);

...

}

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {

...

FrameworkCommand *c = *i;

if (!strcmp(argv[0], c->getCommand())) {

if (c->runCommand(cli, argc, argv)) {

SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));

}

goto out;

}

...

}

从CommandListener源码中可以看到类似InterfaceCmd、IpFwdCmd等和网络相关的Command类,这些类都是从NetdCommand派生的:

CommandListener::InterfaceCmd::InterfaceCmd() :

NetdCommand("interface") {

}

int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,

int argc, char **argv) {

if (argc < 2) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);

return 0;

}

if (!strcmp(argv[1], "list")) {

...

}

CommandListener::IpFwdCmd::IpFwdCmd() :

NetdCommand("ipfwd") {

}

int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,

int argc, char **argv) {

int rc = 0;

char value[PROPERTY_VALUE_MAX];

if (argc < 2) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);

return 0;

}

if (!strcmp(argv[1], "status")) {

...

}

...

而NetdCommand又是从FrameworkCommand派生的:

NetdCommand::NetdCommand(const char *cmd) :

FrameworkCommand(cmd) {

}

class FrameworkCommand {

private:

const char *mCommand;

public:

FrameworkCommand(const char *cmd);

virtual ~FrameworkCommand() { }

virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;

const char *getCommand() { return mCommand; }

};

#include

FrameworkCommand::FrameworkCommand(const char *cmd) {

mCommand = cmd;

}

int FrameworkCommand::runCommand(SocketClient *c, int argc, char **argv) {

SLOGW("Command %s has no run handler!", getCommand());

errno = ENOSYS;

return -1;

}

因此,当Framework中有类似interface、ipfwd、softap等sockect指令时,在netd模块中就会通过sockect的select查选到(可以看之前对SockectListener的分析),进而回调到FrameworkListener的OnDataAvialable接口,由于是派生的NetdCommand类,进而调用对应的runCommand接口,实现对指令的特殊处理。

f752b2019c97

Command指令

例如通过Android的系统设置打开AP热点(打开AP在Framework层的流程和源码本文暂不做分析),SoftapController.cpp:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define LOG_TAG "SoftapController"

#include

#include

#include

#include "wifi.h"

#include "ResponseCode.h"

#include "SoftapController.h"

static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf";

static const char HOSTAPD_BIN_FILE[] = "/system/bin/hostapd";

SoftapController::SoftapController() {

mPid = 0;

mSock = socket(AF_INET, SOCK_DGRAM, 0);

if (mSock < 0)

ALOGE("Failed to open socket");

memset(mIface, 0, sizeof(mIface));

}

SoftapController::~SoftapController() {

}

int SoftapController::startSoftap() {

pid_t pid = 1;

int wifi_device = wifi_get_device_id();

if (WIFI_RALINK_RT3070 == wifi_device || WIFI_RALINK_RT5370 == wifi_device

|| WIFI_RALINK_RT5372 == wifi_device || WIFI_RALINK_RT5572 == wifi_device

|| WIFI_RALINK_MT7601U == wifi_device)

return 0;

if (mPid) {

ALOGE("SoftAP is already running");

return ResponseCode::SoftapStatusResult;

}

if ((pid = fork()) < 0) {

ALOGE("fork failed (%s)", strerror(errno));

return ResponseCode::ServiceStartFailed;

}

if (!pid) {

ensure_entropy_file_exists();

if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE,

"-e", WIFI_ENTROPY_FILE,

HOSTAPD_CONF_FILE, (char *) NULL)) {

ALOGE("execl failed (%s)", strerror(errno));

}

ALOGE("SoftAP failed to start");

return ResponseCode::ServiceStartFailed;

} else {

mPid = pid;

ALOGD("SoftAP started successfully");

usleep(AP_BSS_START_DELAY);

}

return ResponseCode::SoftapStatusResult;

}

int SoftapController::stopSoftap() {

int wifi_device = wifi_get_device_id();

if (WIFI_RALINK_RT3070 == wifi_device || WIFI_RALINK_RT5370 == wifi_device

|| WIFI_RALINK_RT5372 == wifi_device || WIFI_RALINK_RT5572 == wifi_device

|| WIFI_RALINK_MT7601U == wifi_device) {

struct ifreq ifr;

int s;

/* configure WiFi interface down */

memset(&ifr, 0, sizeof(struct ifreq));

strcpy(ifr.ifr_name, mIface);

if((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {

if(ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {

ifr.ifr_flags = (ifr.ifr_flags & (~IFF_UP));

ioctl(s, SIOCSIFFLAGS, &ifr);

}

close(s);

}

usleep(200000);

return 0;

}

if (mPid == 0) {

ALOGE("SoftAP is not running");

return ResponseCode::SoftapStatusResult;

}

ALOGD("Stopping the SoftAP service...");

kill(mPid, SIGTERM);

waitpid(mPid, NULL, 0);

mPid = 0;

ALOGD("SoftAP stopped successfully");

usleep(AP_BSS_STOP_DELAY);

return ResponseCode::SoftapStatusResult;

}

bool SoftapController::isSoftapStarted() {

return (mPid != 0);

}

/* configure softap by sending private ioctls to driver directly */

int SoftapController::ap_config_with_iwpriv_cmd(int s, char *ifname, char **argv)

{

char tBuf[4096];

struct iwreq wrq;

struct iw_priv_args *priv_ptr;

int i, j;

int cmd = 0, sub_cmd = 0;

int device_id;

char mBuf[256];

int hidden_ssid = 0;

device_id = wifi_get_device_id();

/* get all private commands that driver supported */

strncpy(wrq.ifr_name, ifname, sizeof(wrq.ifr_name));

wrq.u.data.pointer = tBuf;

wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);

wrq.u.data.flags = 0;

if (ioctl(s, SIOCGIWPRIV, &wrq) < 0) {

return -1;

}

/* if driver don't support 'set' command, return failure */

priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;

for(i = 0; i < wrq.u.data.length; i++) {

if (strcmp(priv_ptr[i].name, "set") == 0) {

cmd = priv_ptr[i].cmd;

break;

}

}

if (i == wrq.u.data.length) {

return -1;

}

/* get the 'set' command's ID */

if (cmd < SIOCDEVPRIVATE) {

for(j = 0; j < i; j++) {

if ((priv_ptr[j].set_args == priv_ptr[i].set_args)

&& (priv_ptr[j].get_args == priv_ptr[i].get_args)

&& (priv_ptr[j].name[0] == '\0'))

break;

}

if (j == i) {

return -1;

}

sub_cmd = cmd;

cmd = priv_ptr[j].cmd;

}

/* configure AP, order should be as follow

* 1. Channel

* 2. AuthMode

* 3. EncrypType

* for WPAPSK/WPA2PSK:

* 4.Hidden/Broadcast SSID

* 5. SSID (must after AuthMode and before Password)

* 6. Password

*/

strncpy(wrq.ifr_name, ifname, sizeof(wrq.ifr_name));

wrq.u.data.pointer = mBuf;

wrq.u.data.flags = sub_cmd;

/* configure Channel */

sprintf(mBuf, "Channel=%s", argv[2]);

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

/* configure AuthMode */

if(!strcmp(argv[3], "wpa-psk"))

sprintf(mBuf, "AuthMode=WPAPSK");

else if (!strcmp(argv[3], "wpa2-psk"))

sprintf(mBuf, "AuthMode=WPA2PSK");

else

sprintf(mBuf, "AuthMode=OPEN");

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

/* configure EncrypType */

if (!strcmp(argv[3], "wpa-psk"))

sprintf(mBuf, "EncrypType=AES");

else if (!strcmp(argv[3], "wpa2-psk"))

sprintf(mBuf, "EncrypType=AES");

else

sprintf(mBuf, "EncrypType=NONE");

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

/* configure hide SSID */

if (!strcmp(argv[1], "hidden"))

hidden_ssid = 1;

sprintf(mBuf, "HideSSID=%d", hidden_ssid);

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

/* configure SSID */

sprintf(mBuf, "SSID=%s", argv[0]);

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

/* configure password of WPAPSK/WPA2PSK */

if (strcmp(argv[3], "open")) {

sprintf(mBuf, "WPAPSK=%s", argv[4]);

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

if (device_id == WIFI_RALINK_MT7601U) {

/* for MT7601U, configure SSID again */

sprintf(mBuf, "SSID=%s", argv[0]);

wrq.u.data.length = strlen(mBuf) + 1;

if(ioctl(s, cmd, &wrq) < 0)

return -1;

}

}

return 0;

}

/*

* Arguments:

* argv[2] - wlan interface

* argv[3] - SSID

* argv[4] - Broadcast/Hidden

* argv[5] - Channel

* argv[6] - Security

* argv[7] - Key

*/

int SoftapController::setSoftap(int argc, char *argv[]) {

char psk_str[2*SHA256_DIGEST_LENGTH+1];

int ret = ResponseCode::SoftapStatusResult;

int i = 0;

int fd;

int hidden = 0;

int channel = AP_CHANNEL_DEFAULT;

int wifi_device;

char hw_mode;

char ht40_capab[32];

char *wbuf = NULL;

char *fbuf = NULL;

if (argc < 5) {

ALOGE("Softap set is missing arguments. Please use:");

ALOGE("softap ");

return ResponseCode::CommandSyntaxError;

}

wifi_device = wifi_get_device_id();

if (!strcasecmp(argv[4], "hidden")) {

if (WIFI_ATHEROS_QCA1021X == wifi_device || WIFI_ATHEROS_QCA1021G == wifi_device

|| WIFI_ATHEROS_AR9374 == wifi_device)

hidden = 2;

else

hidden = 1;

}

if (argc >= 5) {

channel = atoi(argv[5]);

if (channel <= 0)

channel = AP_CHANNEL_DEFAULT;

}

memset(ht40_capab, 0, sizeof(ht40_capab));

if (channel >= 36) {

int ht40plus[] = {36, 44, 52, 60, 100, 108, 116, 124,

132, 149, 157};

int ht40minus[] = {40, 48, 56, 64, 104, 112, 120, 128,

136, 153, 161};

hw_mode = 'a';

for (i = 0; i < sizeof(ht40plus)/sizeof(ht40plus[0]); i++)

if (channel == ht40plus[i]) {

strcpy(ht40_capab, "[SHORT-GI-40][HT40+]");

break;

}

for (i = 0; i < sizeof(ht40minus)/sizeof(ht40minus[0]); i++)

if (channel == ht40minus[i]) {

strcpy(ht40_capab, "[SHORT-GI-40][HT40-]");

break;

}

} else {

hw_mode = 'g';

if (channel > 7)

strcpy(ht40_capab, "[SHORT-GI-40][HT40-]");

else

strcpy(ht40_capab, "[SHORT-GI-40][HT40+]");

}

char *ssid, *iface;

if (mSock < 0) {

ALOGE("Softap set - failed to open socket");

return -1;

}

strncpy(mIface, argv[2], sizeof(mIface));

iface = argv[2];

if (WIFI_RALINK_RT3070 == wifi_device || WIFI_RALINK_RT5370 == wifi_device

|| WIFI_RALINK_RT5372 == wifi_device || WIFI_RALINK_RT5572 == wifi_device

|| WIFI_RALINK_MT7601U == wifi_device) {

struct ifreq ifr;

int s;

/* RT3070/5370/5372/MT7601U don't use hostapd, driver reads RT2870AP.dat

* and configures WiFi to AP mode while intialize. After initialization

* complete, configure WiFi interface up will startup AP. Then

* reconfigure AP by private commands.

*/

memset(&ifr, 0, sizeof(struct ifreq));

strcpy(ifr.ifr_name, iface);

if((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {

if(ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {

ifr.ifr_flags = (ifr.ifr_flags | IFF_UP);

if (ioctl(s, SIOCSIFFLAGS, &ifr) >= 0) {

ret = ap_config_with_iwpriv_cmd(s, iface, argv + 3);

}

}

close(s);

}

return 0;

}

if (argc < 4) {

ALOGE("Softap set - missing arguments");

return -1;

}

if (argc > 3) {

ssid = argv[3];

} else {

ssid = (char *)"AndroidAP";

}

asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="

"/data/misc/wifi/hostapd\nssid=%s\nchannel=%d\nieee80211n=1\n"

"hw_mode=%c\nht_capab=[SHORT-GI-20]%s\nignore_broadcast_ssid=%d\n",

argv[2], argv[3], channel, hw_mode, ht40_capab, hidden);

if (argc > 7) {

if (!strcmp(argv[6], "wpa-psk")) {

generatePsk(argv[3], argv[7], psk_str);

asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);

} else if (!strcmp(argv[6], "wpa2-psk")) {

generatePsk(argv[3], argv[7], psk_str);

asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);

} else if (!strcmp(argv[6], "open")) {

asprintf(&fbuf, "%s", wbuf);

}

} else if (argc > 6) {

if (!strcmp(argv[6], "open")) {

asprintf(&fbuf, "%s", wbuf);

}

} else {

asprintf(&fbuf, "%s", wbuf);

}

fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660);

if (fd < 0) {

ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));

free(wbuf);

free(fbuf);

return ResponseCode::OperationFailed;

}

if (write(fd, fbuf, strlen(fbuf)) < 0) {

ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));

ret = ResponseCode::OperationFailed;

}

free(wbuf);

free(fbuf);

/* Note: apparently open can fail to set permissions correctly at times */

if (fchmod(fd, 0660) < 0) {

ALOGE("Error changing permissions of %s to 0660: %s",

HOSTAPD_CONF_FILE, strerror(errno));

close(fd);

unlink(HOSTAPD_CONF_FILE);

return ResponseCode::OperationFailed;

}

if (fchown(fd, AID_SYSTEM, AID_WIFI) < 0) {

ALOGE("Error changing group ownership of %s to %d: %s",

HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));

close(fd);

unlink(HOSTAPD_CONF_FILE);

return ResponseCode::OperationFailed;

}

close(fd);

return ret;

}

void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) {

unsigned char psk[SHA256_DIGEST_LENGTH];

int j;

// Use the PKCS#5 PBKDF2 with 4096 iterations

PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase),

reinterpret_cast(ssid), strlen(ssid),

4096, SHA256_DIGEST_LENGTH, psk);

for (j=0; j < SHA256_DIGEST_LENGTH; j++) {

sprintf(&psk_str[j*2], "%02x", psk[j]);

}

}

首先可以看看SoftapController的startSoftap、stopSoftap、setSoftap接口,然后就可以联想到CommandListener源码中对Softap的处理,当接收到Framework层的set指令时调用的SoftapController的setSoftap,配置好AP参数后,Framework层再调用startap指令,就可以成功开启AP热点了。

int CommandListener::SoftapCmd::runCommand(SocketClient *cli,

int argc, char **argv) {

int rc = ResponseCode::SoftapStatusResult;

int flag = 0;

char *retbuf = NULL;

if (sSoftapCtrl == NULL) {

cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);

return -1;

}

if (argc < 2) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Missing argument in a SoftAP command", false);

return 0;

}

if (!strcmp(argv[1], "startap")) {

rc = sSoftapCtrl->startSoftap();

} else if (!strcmp(argv[1], "stopap")) {

rc = sSoftapCtrl->stopSoftap();

} else if (!strcmp(argv[1], "fwreload")) {

rc = sSoftapCtrl->fwReloadSoftap(argc, argv);

} else if (!strcmp(argv[1], "status")) {

asprintf(&retbuf, "Softap service %s running",

(sSoftapCtrl->isSoftapStarted() ? "is" : "is not"));

cli->sendMsg(rc, retbuf, false);

free(retbuf);

return 0;

} else if (!strcmp(argv[1], "set")) {

rc = sSoftapCtrl->setSoftap(argc, argv);

} else {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);

return 0;

}

if (rc >= 400 && rc < 600)

cli->sendMsg(rc, "SoftAP command has failed", false);

else

cli->sendMsg(rc, "Ok", false);

return 0;

}

源码中在setSoftap时分为

1.使用ioctls接口配置驱动( RT3070/5370/5372/MT7601U don't use hostapd, driver reads RT2870AP.dat)

2.通过hostapd方式配置AP,即把AP配置写入/data/misc/wifi/hostapd.conf,在执行/system/bin/hostapd时读取配置

以下是参考了深入理解Andoriod卷画的CommandListener工作流程图:

f752b2019c97

CommandListener工作流程图

3.结束语

Netd进程本身的代码不多,但是涉及的面比较广,本篇文章先只介绍一个骨架,并没有深入骨髓,文章会继续更新,谢谢关注!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值