blob: 2d8a4de1eddce6b631cce9b9d5dbfa88d34022a2 [file] [log] [blame]
San Mehatd1830422010-01-15 08:02:39 -08001/*
2 * Copyright (C) 2008 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#include <stdio.h>
18#include <errno.h>
19
20#include <sys/socket.h>
21#include <sys/select.h>
22#include <sys/time.h>
23#include <sys/types.h>
24#include <sys/un.h>
25
26#include <linux/netlink.h>
Mike J. Chen564df4e2011-06-23 15:07:35 -070027#include <linux/rtnetlink.h>
San Mehatd1830422010-01-15 08:02:39 -080028
29#define LOG_TAG "Netd"
30
31#include <cutils/log.h>
32
33#include "NetlinkManager.h"
34#include "NetlinkHandler.h"
35
JP Abgralle0ebc462011-07-21 17:21:49 -070036const int NetlinkManager::NFLOG_QUOTA_GROUP = 1;
Ashish Sharma6337b882012-04-10 19:47:09 -070037const int NetlinkManager::IDLETIMER_GROUP = 1;
JP Abgralle0ebc462011-07-21 17:21:49 -070038
San Mehatd1830422010-01-15 08:02:39 -080039NetlinkManager *NetlinkManager::sInstance = NULL;
40
41NetlinkManager *NetlinkManager::Instance() {
42 if (!sInstance)
43 sInstance = new NetlinkManager();
44 return sInstance;
45}
46
47NetlinkManager::NetlinkManager() {
48 mBroadcaster = NULL;
49}
50
51NetlinkManager::~NetlinkManager() {
52}
53
JP Abgralle0ebc462011-07-21 17:21:49 -070054NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,
Mike J. Chen564df4e2011-06-23 15:07:35 -070055 int groups, int format) {
56
San Mehatd1830422010-01-15 08:02:39 -080057 struct sockaddr_nl nladdr;
58 int sz = 64 * 1024;
Nick Kralevich79b579c2011-04-18 15:54:13 -070059 int on = 1;
San Mehatd1830422010-01-15 08:02:39 -080060
61 memset(&nladdr, 0, sizeof(nladdr));
62 nladdr.nl_family = AF_NETLINK;
63 nladdr.nl_pid = getpid();
Mike J. Chen564df4e2011-06-23 15:07:35 -070064 nladdr.nl_groups = groups;
San Mehatd1830422010-01-15 08:02:39 -080065
JP Abgralle0ebc462011-07-21 17:21:49 -070066 if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +000067 ALOGE("Unable to create netlink socket: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -070068 return NULL;
San Mehatd1830422010-01-15 08:02:39 -080069 }
70
Mike J. Chen564df4e2011-06-23 15:07:35 -070071 if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +000072 ALOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -070073 close(*sock);
74 return NULL;
Nick Kralevich79b579c2011-04-18 15:54:13 -070075 }
76
Mike J. Chen564df4e2011-06-23 15:07:35 -070077 if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
Nick Kralevich79b579c2011-04-18 15:54:13 -070078 SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -070079 close(*sock);
80 return NULL;
San Mehatd1830422010-01-15 08:02:39 -080081 }
82
Mike J. Chen564df4e2011-06-23 15:07:35 -070083 if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +000084 ALOGE("Unable to bind netlink socket: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -070085 close(*sock);
86 return NULL;
San Mehatd1830422010-01-15 08:02:39 -080087 }
88
Mike J. Chen564df4e2011-06-23 15:07:35 -070089 NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
90 if (handler->start()) {
Steve Block5ea0c052012-01-06 19:18:11 +000091 ALOGE("Unable to start NetlinkHandler: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -070092 close(*sock);
93 return NULL;
94 }
95
96 return handler;
97}
98
99int NetlinkManager::start() {
100 if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
101 0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
102 return -1;
103 }
104
105 if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE, RTMGRP_LINK,
106 NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
San Mehatd1830422010-01-15 08:02:39 -0800107 return -1;
108 }
JP Abgralle0ebc462011-07-21 17:21:49 -0700109
110 if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
111 NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
Steve Block5ea0c052012-01-06 19:18:11 +0000112 ALOGE("Unable to open quota2 logging socket");
JP Abgrall8a412092011-07-26 15:36:40 -0700113 // TODO: return -1 once the emulator gets a new kernel.
JP Abgralle0ebc462011-07-21 17:21:49 -0700114 }
Ashish Sharma6337b882012-04-10 19:47:09 -0700115
116 if ((mIfaceIdleTimerHandler = setupSocket(&mIfaceIdleTimerSock, NETLINK_IDLETIMER,
117 IDLETIMER_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
118 // TODO: switch back to using NETLINK_NFLOG with a custom type.
119 ALOGE("Unable to open iface idletimer socket");
120 }
San Mehatd1830422010-01-15 08:02:39 -0800121 return 0;
122}
123
124int NetlinkManager::stop() {
Mike J. Chen564df4e2011-06-23 15:07:35 -0700125 int status = 0;
126
127 if (mUeventHandler->stop()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000128 ALOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -0700129 status = -1;
San Mehatd1830422010-01-15 08:02:39 -0800130 }
San Mehatd1830422010-01-15 08:02:39 -0800131
Mike J. Chen564df4e2011-06-23 15:07:35 -0700132 delete mUeventHandler;
133 mUeventHandler = NULL;
San Mehatd1830422010-01-15 08:02:39 -0800134
Mike J. Chen564df4e2011-06-23 15:07:35 -0700135 close(mUeventSock);
136 mUeventSock = -1;
137
138 if (mRouteHandler->stop()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000139 ALOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
Mike J. Chen564df4e2011-06-23 15:07:35 -0700140 status = -1;
141 }
142
143 delete mRouteHandler;
144 mRouteHandler = NULL;
145
146 close(mRouteSock);
147 mRouteSock = -1;
148
JP Abgrall8a412092011-07-26 15:36:40 -0700149 if (mQuotaHandler) {
150 if (mQuotaHandler->stop()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000151 ALOGE("Unable to stop quota NetlinkHandler: %s", strerror(errno));
JP Abgrall8a412092011-07-26 15:36:40 -0700152 status = -1;
153 }
154
155 delete mQuotaHandler;
156 mQuotaHandler = NULL;
157
158 close(mQuotaSock);
159 mQuotaSock = -1;
JP Abgralle0ebc462011-07-21 17:21:49 -0700160 }
Ashish Sharma6337b882012-04-10 19:47:09 -0700161
162 if (mIfaceIdleTimerHandler) {
163 if (mIfaceIdleTimerHandler->stop()) {
164 ALOGE("Unable to stop iface IDLETIMER NetlinkHandler: %s", strerror(errno));
165 status = -1;
166 }
167
168 delete mIfaceIdleTimerHandler;
169 mIfaceIdleTimerHandler = NULL;
170
171 close(mIfaceIdleTimerSock);
172 mIfaceIdleTimerSock = -1;
173 }
174
Mike J. Chen564df4e2011-06-23 15:07:35 -0700175 return status;
San Mehatd1830422010-01-15 08:02:39 -0800176}