blob: e69f2c0df63f951a966baf36d257ec43c6f1ed60 [file] [log] [blame]
San Mehatdc266072009-05-06 11:16:52 -07001/*
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 */
San Mehat1441e762009-05-07 11:37:10 -070016
17#include <stdlib.h>
San Mehat69772dc2009-05-10 09:27:07 -070018#include <sys/types.h>
19#include <fcntl.h>
San Mehatdc266072009-05-06 11:16:52 -070020#include <errno.h>
21
22#define LOG_TAG "Supplicant"
23#include <cutils/log.h>
24#include <cutils/properties.h>
25
San Mehat69772dc2009-05-10 09:27:07 -070026#include "private/android_filesystem_config.h"
27
San Mehat5d6d4172009-05-14 15:00:06 -070028#include <sysutils/ServiceManager.h>
San Mehatdc266072009-05-06 11:16:52 -070029
30#include "Supplicant.h"
31#include "SupplicantListener.h"
32#include "SupplicantState.h"
33#include "SupplicantEvent.h"
34#include "ScanResult.h"
San Mehat3c5a6f02009-05-22 15:36:13 -070035#include "PropertyManager.h"
San Mehat1441e762009-05-07 11:37:10 -070036#include "NetworkManager.h"
San Mehat8d3fc3f2009-05-12 14:36:32 -070037#include "ErrorCode.h"
San Mehat3c5a6f02009-05-22 15:36:13 -070038#include "WifiController.h"
San Mehatdc266072009-05-06 11:16:52 -070039
40#include "libwpa_client/wpa_ctrl.h"
41
42#define IFACE_DIR "/data/system/wpa_supplicant"
43#define DRIVER_PROP_NAME "wlan.driver.status"
San Mehat5d6d4172009-05-14 15:00:06 -070044#define SUPPLICANT_SERVICE_NAME "wpa_supplicant"
San Mehat69772dc2009-05-10 09:27:07 -070045#define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
46#define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
47
San Mehat3c5a6f02009-05-22 15:36:13 -070048Supplicant::Supplicant(WifiController *wc, PropertyManager *propmngr) {
49 mController = wc;
50 mPropMngr = propmngr;
51 mInterfaceName = NULL;
San Mehatdc266072009-05-06 11:16:52 -070052 mCtrl = NULL;
53 mMonitor = NULL;
54 mListener = NULL;
San Mehat3c5a6f02009-05-22 15:36:13 -070055
San Mehatdc266072009-05-06 11:16:52 -070056 mState = SupplicantState::UNKNOWN;
57
San Mehat5d6d4172009-05-14 15:00:06 -070058 mServiceManager = new ServiceManager();
San Mehatdc266072009-05-06 11:16:52 -070059
San Mehat5d6d4172009-05-14 15:00:06 -070060 mLatestScanResults = new ScanResultCollection();
San Mehatdc266072009-05-06 11:16:52 -070061 pthread_mutex_init(&mLatestScanResultsLock, NULL);
San Mehat3c5a6f02009-05-22 15:36:13 -070062
63 mNetworks = new WifiNetworkCollection();
64 pthread_mutex_init(&mNetworksLock, NULL);
San Mehatdc266072009-05-06 11:16:52 -070065}
66
San Mehat5d6d4172009-05-14 15:00:06 -070067Supplicant::~Supplicant() {
68 delete mServiceManager;
San Mehat3c5a6f02009-05-22 15:36:13 -070069 if (mInterfaceName)
70 free(mInterfaceName);
San Mehat5d6d4172009-05-14 15:00:06 -070071}
72
San Mehatdc266072009-05-06 11:16:52 -070073int Supplicant::start() {
San Mehat69772dc2009-05-10 09:27:07 -070074
75 if (setupConfig()) {
76 LOGW("Unable to setup supplicant.conf");
77 }
San Mehat3c5a6f02009-05-22 15:36:13 -070078
San Mehat5d6d4172009-05-14 15:00:06 -070079 if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
80 LOGE("Error starting supplicant (%s)", strerror(errno));
81 return -1;
San Mehatdc266072009-05-06 11:16:52 -070082 }
83
84 wpa_ctrl_cleanup();
San Mehatdc266072009-05-06 11:16:52 -070085 if (connectToSupplicant()) {
86 LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
87 return -1;
88 }
San Mehat3c5a6f02009-05-22 15:36:13 -070089
90 if (retrieveInterfaceName()) {
91 LOGE("Error retrieving interface name (%s)\n", strerror(errno));
92 return -1;
93 }
94
95 mPropMngr->registerProperty("wifi.supplicant.state", this);
San Mehatdc266072009-05-06 11:16:52 -070096 return 0;
97}
98
99int Supplicant::stop() {
San Mehatdc266072009-05-06 11:16:52 -0700100
San Mehat3c5a6f02009-05-22 15:36:13 -0700101 mPropMngr->unregisterProperty("wifi.supplicant.state");
102
San Mehatdc266072009-05-06 11:16:52 -0700103 if (mListener->stopListener()) {
104 LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
105 return -1;
106 }
107
San Mehat5d6d4172009-05-14 15:00:06 -0700108 if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
109 LOGW("Error stopping supplicant (%s)", strerror(errno));
San Mehatdc266072009-05-06 11:16:52 -0700110 }
111
112 if (mCtrl) {
113 wpa_ctrl_close(mCtrl);
114 mCtrl = NULL;
115 }
116 if (mMonitor) {
117 wpa_ctrl_close(mMonitor);
118 mMonitor = NULL;
119 }
120
San Mehatdc266072009-05-06 11:16:52 -0700121 return 0;
122}
123
124bool Supplicant::isStarted() {
San Mehat5d6d4172009-05-14 15:00:06 -0700125 return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
San Mehatdc266072009-05-06 11:16:52 -0700126}
127
San Mehat3c5a6f02009-05-22 15:36:13 -0700128int Supplicant::refreshNetworkList() {
129 char *reply;
130 size_t len = 4096;
131
132 if (!(reply = (char *) malloc(len))) {
133 errno = ENOMEM;
San Mehatdc266072009-05-06 11:16:52 -0700134 return -1;
135 }
136
San Mehat3c5a6f02009-05-22 15:36:13 -0700137 if (sendCommand("LIST_NETWORKS", reply, &len)) {
138 free(reply);
139 return -1;
140 }
141
142 char *linep;
143 char *linep_next = NULL;
144
145 if (!strtok_r(reply, "\n", &linep_next)) {
146 LOGW("Malformatted network list\n");
147 } else {
148 pthread_mutex_lock(&mNetworksLock);
149 if (!mNetworks->empty()) {
150 WifiNetworkCollection::iterator i;
151
152 for (i = mNetworks->begin(); i !=mNetworks->end(); ++i)
153 delete *i;
154 mNetworks->clear();
155 }
156
157 while((linep = strtok_r(NULL, "\n", &linep_next))) {
158 WifiNetwork *wn = new WifiNetwork(mController, this, linep);
159 mNetworks->push_back(wn);
160 if (wn->refresh())
161 LOGW("Unable to refresh network id %d", wn->getNetworkId());
162 }
163
164 LOGD("Loaded %d networks\n", mNetworks->size());
165 pthread_mutex_unlock(&mNetworksLock);
166 }
167
168 free(reply);
169 return 0;
170}
171
172int Supplicant::connectToSupplicant() {
173 if (!isStarted())
174 LOGW("Supplicant service not running");
175
176 mCtrl = wpa_ctrl_open("tiwlan0"); // XXX:
San Mehatdc266072009-05-06 11:16:52 -0700177 if (mCtrl == NULL) {
178 LOGE("Unable to open connection to supplicant on \"%s\": %s",
179 "tiwlan0", strerror(errno));
180 return -1;
181 }
182 mMonitor = wpa_ctrl_open("tiwlan0");
183 if (mMonitor == NULL) {
184 wpa_ctrl_close(mCtrl);
185 mCtrl = NULL;
186 return -1;
187 }
188 if (wpa_ctrl_attach(mMonitor) != 0) {
189 wpa_ctrl_close(mMonitor);
190 wpa_ctrl_close(mCtrl);
191 mCtrl = mMonitor = NULL;
192 return -1;
193 }
194
195 mListener = new SupplicantListener(this, mMonitor);
San Mehat3c5a6f02009-05-22 15:36:13 -0700196
San Mehatdc266072009-05-06 11:16:52 -0700197 if (mListener->startListener()) {
198 LOGE("Error - unable to start supplicant listener");
199 stop();
200 return -1;
201 }
202 return 0;
203}
204
205int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
206{
207 if (!mCtrl) {
208 errno = ENOTCONN;
209 return -1;
210 }
211
San Mehat5d6d4172009-05-14 15:00:06 -0700212// LOGD("sendCommand(): -> '%s'", cmd);
San Mehatdc266072009-05-06 11:16:52 -0700213
214 int rc;
San Mehat3c5a6f02009-05-22 15:36:13 -0700215 memset(reply, 0, *reply_len);
San Mehatdc266072009-05-06 11:16:52 -0700216 if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
217 errno = ETIMEDOUT;
218 return -1;
219 } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
San Mehat3c5a6f02009-05-22 15:36:13 -0700220 strcpy(reply, "FAIL");
San Mehatdc266072009-05-06 11:16:52 -0700221 errno = EIO;
222 return -1;
223 }
224
San Mehat3c5a6f02009-05-22 15:36:13 -0700225// LOGD("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700226 return 0;
227}
228
229int Supplicant::triggerScan(bool active) {
230 char reply[255];
231 size_t len = sizeof(reply);
232
233 if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
234 reply, &len)) {
235 LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
236 strerror(errno));
237 return -1;
238 }
239 len = sizeof(reply);
240
241 if (sendCommand("SCAN", reply, &len)) {
242 LOGW("triggerScan(%d): Error initiating scan", active);
243 return -1;
244 }
245 return 0;
246}
247
San Mehat3c5a6f02009-05-22 15:36:13 -0700248int Supplicant::set(const char *name, const char *value) {
249 const char *n = name + strlen("wifi.supplicant.");
250
251 errno = -EROFS;
252 return -1;
253}
254
255const char *Supplicant::get(const char *name, char *buffer, size_t max) {
256 const char *n = name + strlen("wifi.supplicant.");
257
258 if (!strcasecmp(n, "state"))
259 return SupplicantState::toString(mState, buffer, max);
260 errno = ENOENT;
261 return NULL;
262}
263
San Mehatdc266072009-05-06 11:16:52 -0700264int Supplicant::onConnectedEvent(SupplicantEvent *evt) {
265 LOGD("onConnectedEvent(%s)", evt->getEvent());
266 return 0;
267}
268
269int Supplicant::onDisconnectedEvent(SupplicantEvent *evt) {
270 LOGD("onDisconnectedEvent(%s)", evt->getEvent());
271 return 0;
272}
273
274int Supplicant::onTerminatingEvent(SupplicantEvent *evt) {
275 LOGD("onTerminatingEvent(%s)", evt->getEvent());
276 return 0;
277}
278
279int Supplicant::onPasswordChangedEvent(SupplicantEvent *evt) {
280 LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
281 return 0;
282}
283
284int Supplicant::onEapNotificationEvent(SupplicantEvent *evt) {
285 LOGD("onEapNotificationEvent(%s)", evt->getEvent());
286 return 0;
287}
288
289int Supplicant::onEapStartedEvent(SupplicantEvent *evt) {
290 LOGD("onEapStartedEvent(%s)", evt->getEvent());
291 return 0;
292}
293
294int Supplicant::onEapMethodEvent(SupplicantEvent *evt) {
295 LOGD("onEapMethodEvent(%s)", evt->getEvent());
296 return 0;
297}
298
299int Supplicant::onEapSuccessEvent(SupplicantEvent *evt) {
300 LOGD("onEapSuccessEvent(%s)", evt->getEvent());
301 return 0;
302}
303
304int Supplicant::onEapFailureEvent(SupplicantEvent *evt) {
305 LOGD("onEapFailureEvent(%s)", evt->getEvent());
306 return 0;
307}
308
309int Supplicant::onScanResultsEvent(SupplicantEvent *evt) {
San Mehatdc266072009-05-06 11:16:52 -0700310 if (!strcmp(evt->getEvent(), "Ready")) {
311 char *reply;
312
313 if (!(reply = (char *) malloc(4096))) {
San Mehat3c5a6f02009-05-22 15:36:13 -0700314 errno = ENOMEM;
San Mehatdc266072009-05-06 11:16:52 -0700315 return -1;
316 }
317
318 size_t len = 4096;
San Mehat3c5a6f02009-05-22 15:36:13 -0700319
San Mehatdc266072009-05-06 11:16:52 -0700320 if (sendCommand("SCAN_RESULTS", reply, &len)) {
321 LOGW("onScanResultsEvent(%s): Error getting scan results (%s)",
322 evt->getEvent(), strerror(errno));
323 free(reply);
324 return -1;
325 }
326
327 pthread_mutex_lock(&mLatestScanResultsLock);
328 if (!mLatestScanResults->empty()) {
329 ScanResultCollection::iterator i;
330
331 for (i = mLatestScanResults->begin();
332 i !=mLatestScanResults->end(); ++i) {
333 delete *i;
334 }
335 mLatestScanResults->clear();
336 }
337
338 char *linep;
339 char *linep_next = NULL;
340
341 if (!strtok_r(reply, "\n", &linep_next)) {
342 free(reply);
San Mehat1441e762009-05-07 11:37:10 -0700343 pthread_mutex_unlock(&mLatestScanResultsLock);
344 return 0;
San Mehatdc266072009-05-06 11:16:52 -0700345 }
346
347 while((linep = strtok_r(NULL, "\n", &linep_next)))
348 mLatestScanResults->push_back(new ScanResult(linep));
San Mehat3c5a6f02009-05-22 15:36:13 -0700349
San Mehat69772dc2009-05-10 09:27:07 -0700350 char tmp[128];
San Mehat82a21162009-05-12 17:26:28 -0700351 sprintf(tmp, "Scan results ready (%d)", mLatestScanResults->size());
San Mehat8d3fc3f2009-05-12 14:36:32 -0700352 NetworkManager::Instance()->getBroadcaster()->
353 sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
San Mehatdc266072009-05-06 11:16:52 -0700354 pthread_mutex_unlock(&mLatestScanResultsLock);
355 free(reply);
356 } else {
357 LOGW("Unknown SCAN_RESULTS event (%s)", evt->getEvent());
358 }
359 return 0;
360}
361
362int Supplicant::onStateChangeEvent(SupplicantEvent *evt) {
San Mehat1441e762009-05-07 11:37:10 -0700363 char *bword, *last;
364 char *tmp = strdup(evt->getEvent());
365
366 if (!(bword = strtok_r(tmp, " ", &last))) {
367 LOGE("Malformatted state update (%s)", evt->getEvent());
368 free(tmp);
369 return 0;
370 }
371
372 if (!(bword = strtok_r(NULL, " ", &last))) {
373 LOGE("Malformatted state update (%s)", evt->getEvent());
374 free(tmp);
375 return 0;
376 }
377
378 mState = atoi(&bword[strlen("state=")]);
379 LOGD("State changed to %d", mState);
380 free(tmp);
San Mehatdc266072009-05-06 11:16:52 -0700381 return 0;
382}
383
384int Supplicant::onLinkSpeedEvent(SupplicantEvent *evt) {
385 LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
386 return 0;
387}
388
389int Supplicant::onDriverStateEvent(SupplicantEvent *evt) {
390 LOGD("onDriverStateEvent(%s)", evt->getEvent());
391 return 0;
392}
393
394// XXX: Use a cursor + smartptr instead
San Mehat1441e762009-05-07 11:37:10 -0700395ScanResultCollection *Supplicant::createLatestScanResults() {
San Mehatdc266072009-05-06 11:16:52 -0700396 ScanResultCollection *d = new ScanResultCollection();
397 ScanResultCollection::iterator i;
398
399 pthread_mutex_lock(&mLatestScanResultsLock);
San Mehat3c5a6f02009-05-22 15:36:13 -0700400 for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i)
San Mehatdc266072009-05-06 11:16:52 -0700401 d->push_back((*i)->clone());
San Mehatdc266072009-05-06 11:16:52 -0700402
403 pthread_mutex_unlock(&mLatestScanResultsLock);
404 return d;
San Mehat69772dc2009-05-10 09:27:07 -0700405}
406
San Mehat3c5a6f02009-05-22 15:36:13 -0700407WifiNetwork *Supplicant::createNetwork() {
408 char reply[255];
San Mehat82a21162009-05-12 17:26:28 -0700409 size_t len = sizeof(reply) -1;
410
San Mehat82a21162009-05-12 17:26:28 -0700411 if (sendCommand("ADD_NETWORK", reply, &len))
San Mehat3c5a6f02009-05-22 15:36:13 -0700412 return NULL;
San Mehat82a21162009-05-12 17:26:28 -0700413
San Mehat3c5a6f02009-05-22 15:36:13 -0700414 if (reply[strlen(reply) -1] == '\n')
415 reply[strlen(reply) -1] = '\0';
416
417 WifiNetwork *wn = new WifiNetwork(mController, this, atoi(reply));
418 pthread_mutex_lock(&mNetworksLock);
419 mNetworks->push_back(wn);
420 pthread_mutex_unlock(&mNetworksLock);
421 return wn;
San Mehat82a21162009-05-12 17:26:28 -0700422}
423
San Mehat3c5a6f02009-05-22 15:36:13 -0700424int Supplicant::removeNetwork(WifiNetwork *wn) {
San Mehat82a21162009-05-12 17:26:28 -0700425 char req[64];
426
San Mehat3c5a6f02009-05-22 15:36:13 -0700427 sprintf(req, "REMOVE_NETWORK %d", wn->getNetworkId());
San Mehat82a21162009-05-12 17:26:28 -0700428 char reply[32];
429 size_t len = sizeof(reply) -1;
San Mehat3c5a6f02009-05-22 15:36:13 -0700430
San Mehat82a21162009-05-12 17:26:28 -0700431 if (sendCommand(req, reply, &len))
432 return -1;
San Mehat3c5a6f02009-05-22 15:36:13 -0700433
434 pthread_mutex_lock(&mNetworksLock);
435 WifiNetworkCollection::iterator it;
436 for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
437 if ((*it) == wn) {
438 mNetworks->erase(it);
439 break;
440 }
441 }
442 pthread_mutex_unlock(&mNetworksLock);
San Mehat82a21162009-05-12 17:26:28 -0700443 return 0;
444}
445
San Mehat3c5a6f02009-05-22 15:36:13 -0700446WifiNetwork *Supplicant::lookupNetwork(int networkId) {
447 pthread_mutex_lock(&mNetworksLock);
448 WifiNetworkCollection::iterator it;
449 for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
450 if ((*it)->getNetworkId() == networkId) {
451 pthread_mutex_unlock(&mNetworksLock);
452 return *it;
453 }
454 }
455 pthread_mutex_unlock(&mNetworksLock);
456 errno = ENOENT;
457 return NULL;
458}
459
460WifiNetworkCollection *Supplicant::createNetworkList() {
461 WifiNetworkCollection *d = new WifiNetworkCollection();
462 WifiNetworkCollection::iterator i;
463
464 pthread_mutex_lock(&mNetworksLock);
465 for (i = mNetworks->begin(); i != mNetworks->end(); ++i)
466 d->push_back((*i)->clone());
467
468 pthread_mutex_unlock(&mNetworksLock);
469 return d;
470}
471
San Mehat69772dc2009-05-10 09:27:07 -0700472int Supplicant::setupConfig() {
473 char buf[2048];
474 int srcfd, destfd;
475 int nread;
476
477 if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
478 return 0;
479 } else if (errno != ENOENT) {
480 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
481 return -1;
482 }
483
484 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
485 if (srcfd < 0) {
486 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
487 return -1;
488 }
489
490 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
491 if (destfd < 0) {
492 close(srcfd);
493 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
494 return -1;
495 }
496
497 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
498 if (nread < 0) {
499 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
500 close(srcfd);
501 close(destfd);
502 unlink(SUPP_CONFIG_FILE);
503 return -1;
504 }
505 write(destfd, buf, nread);
506 }
507
508 close(destfd);
509 close(srcfd);
510
511 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
512 LOGE("Error changing group ownership of %s to %d: %s",
513 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
514 unlink(SUPP_CONFIG_FILE);
515 return -1;
516 }
517 return 0;
518}
San Mehat3c5a6f02009-05-22 15:36:13 -0700519
520int Supplicant::setNetworkVar(int networkId, const char *var, const char *val) {
521 char reply[255];
522 size_t len = sizeof(reply) -1;
523
524 char *tmp;
525 asprintf(&tmp, "SET_NETWORK %d %s \"%s\"", networkId, var, val);
526 if (sendCommand(tmp, reply, &len)) {
527 free(tmp);
528 return -1;
529 }
530 free(tmp);
531 return 0;
532}
533
534const char *Supplicant::getNetworkVar(int networkId, const char *var,
535 char *buffer, size_t max) {
536 size_t len = max - 1;
537 char *tmp;
538
539 asprintf(&tmp, "GET_NETWORK %d %s", networkId, var);
540 if (sendCommand(tmp, buffer, &len)) {
541 free(tmp);
542 return NULL;
543 }
544 free(tmp);
545 return buffer;
546}
547
548int Supplicant::enableNetwork(int networkId, bool enabled) {
549 char req[64];
550
551 if (enabled)
552 sprintf(req, "ENABLE_NETWORK %d", networkId);
553 else
554 sprintf(req, "DISABLE_NETWORK %d", networkId);
555
556 char reply[16];
557 size_t len = sizeof(reply) -1;
558
559 if (sendCommand(req, reply, &len))
560 return -1;
561 return 0;
562}
563
564
565int Supplicant::retrieveInterfaceName() {
566 char reply[255];
567 size_t len = sizeof(reply) -1;
568
569 if (sendCommand("INTERFACES", reply, &len))
570 return -1;
571
572 reply[strlen(reply)-1] = '\0';
573 mInterfaceName = strdup(reply);
574 return 0;
575}