diff options
Diffstat (limited to 'cnd')
-rwxr-xr-x | cnd/inc/cnd.h | 52 | ||||
-rwxr-xr-x | cnd/inc/cnd_commands.h | 33 | ||||
-rwxr-xr-x | cnd/inc/cnd_event.h | 53 | ||||
-rwxr-xr-x | cnd/inc/cnd_iproute2.h | 186 | ||||
-rwxr-xr-x | cnd/inc/cnd_unsol_messages.h | 29 | ||||
-rwxr-xr-x | cnd/src/Android.mk | 39 | ||||
-rwxr-xr-x | cnd/src/cnd.c | 46 | ||||
-rwxr-xr-x | cnd/src/cnd_event.cpp | 256 | ||||
-rwxr-xr-x | cnd/src/cnd_iproute2.cpp | 1084 | ||||
-rwxr-xr-x | cnd/src/cnd_process.cpp | 1123 |
10 files changed, 2901 insertions, 0 deletions
diff --git a/cnd/inc/cnd.h b/cnd/inc/cnd.h new file mode 100755 index 0000000..f6e9e65 --- /dev/null +++ b/cnd/inc/cnd.h @@ -0,0 +1,52 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+#ifndef CND_H
+#define CND_H
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include "cne_svc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef void * CND_Token;
+
+typedef enum {
+ CND_E_SUCCESS = 0,
+ CND_E_RADIO_NOT_AVAILABLE = 1, /* If radio did not start or is resetting */
+ CND_E_GENERIC_FAILURE = 2,
+ CND_E_INVALID_RESPONSE
+
+} CND_Errno;
+
+
+
+
+void cnd_init(void);
+void cnd_startEventLoop(void);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CND_H */
+
diff --git a/cnd/inc/cnd_commands.h b/cnd/inc/cnd_commands.h new file mode 100755 index 0000000..f5351df --- /dev/null +++ b/cnd/inc/cnd_commands.h @@ -0,0 +1,33 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ {0, NULL, NULL}, //none
+ {CNE_REQUEST_INIT_CMD, dispatchVoid, responseVoid},
+ {CNE_REQUEST_REG_ROLE_CMD, dispatchInts, responseInts},
+ {CNE_REQUEST_GET_COMPATIBLE_NWS_CMD, dispatchInts, responseInts},
+ {CNE_REQUEST_CONFIRM_NW_CMD, dispatchInts, responseInts},
+ {CNE_REQUEST_DEREG_ROLE_CMD, dispatchInts, responseInts},
+ {CNE_REQUEST_REG_NOTIFICATIONS_CMD, dispatchInts, responseInts},
+ {CNE_REQUEST_UPDATE_BATTERY_INFO_CMD, dispatchInts, responseVoid},
+ {CNE_REQUEST_UPDATE_WLAN_INFO_CMD, dispatchWlanInfo, responseVoid},
+ {CNE_REQUEST_UPDATE_WWAN_INFO_CMD, dispatchInts, responseVoid},
+ {CNE_NOTIFY_RAT_CONNECT_STATUS_CMD, dispatchInts, responseInts},
+ {CNE_NOTIFY_DEFAULT_NW_PREF_CMD, dispatchInts, responseVoid},
+ {CNE_REQUEST_UPDATE_WLAN_SCAN_RESULTS_CMD, dispatchWlanScanResults, responseVoid},
+ {CNE_NOTIFY_SENSOR_EVENT_CMD, dispatchVoid, responseVoid},
+ {CNE_REQUEST_CONFIG_IPROUTE2_CMD, dispatchStrings, responseVoid}
+
+
diff --git a/cnd/inc/cnd_event.h b/cnd/inc/cnd_event.h new file mode 100755 index 0000000..fd05181 --- /dev/null +++ b/cnd/inc/cnd_event.h @@ -0,0 +1,53 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+// Max number of fd's we watch at any one time. Increase if necessary.
+#define MAX_FD_EVENTS 8
+
+typedef void (*cnd_event_cb)(int fd, void *userdata);
+
+struct cnd_event {
+ struct cnd_event *next;
+ struct cnd_event *prev;
+
+ int fd;
+ int index;
+ int persist;
+ cnd_event_cb func;
+ void *param;
+};
+
+// Initialize internal data structs
+void cnd_event_init();
+
+// Initialize an event
+void cnd_event_set(struct cnd_event * ev, int fd, int persist, cnd_event_cb func, void * param);
+
+// Add event to watch list
+void cnd_event_add(struct cnd_event * ev);
+
+
+// Remove event from watch list
+void cnd_event_del(struct cnd_event * ev);
+
+// Event loop
+void cnd_event_loop();
+
+
+// Dump watch table for debugging
+void cnd_dump_watch_table();
+
diff --git a/cnd/inc/cnd_iproute2.h b/cnd/inc/cnd_iproute2.h new file mode 100755 index 0000000..e12778d --- /dev/null +++ b/cnd/inc/cnd_iproute2.h @@ -0,0 +1,186 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef CND_IPROUTE2_H
+#define CND_IPROUTE2_H
+
+/**----------------------------------------------------------------------------
+ @file cnd_iproute2.h
+
+ cnd_iproute2 is an interface to make the necessary calls to iproute2
+ in order to set up and take down routing tables. Defines APIS so that
+ a routing table associated with a RAT can be added or deleted. Also
+ allows the user to change the default routing table when a given
+ source address is not already associated with a RAT.
+-----------------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------------
+ * Include Files
+ * -------------------------------------------------------------------------*/
+#include <sys/types.h>
+
+/*----------------------------------------------------------------------------
+ * Preprocessor Definitions and Constants
+ * -------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ * Type Declarations
+ * -------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ * Class Definitions
+ * -------------------------------------------------------------------------*/
+
+class cnd_iproute2
+{
+ public:
+ /**
+ * @brief Returns an instance of the Cnd_iproute2 class.
+
+ The user of this class will call this function to get an
+ instance of the class. All other public functions will be
+ called on this instance
+
+ * @param None
+ * @see None
+ * @return An instance of the Cnd_iproute2 class is returned.
+ */
+ static cnd_iproute2* getInstance
+ (
+ void
+ );
+
+ /**
+ * @brief Create a routing table for a RAT using iproute2
+ *
+ * The user of this function passes in the name of the RAT that
+ * matches the name already defined in the Android system. The
+ * user also needs to locate the gateway address and source
+ * prefix assocated with that RAT device. If a table is added
+ * when no another tables exist, it will automatically become the
+ * default table.
+ *
+ * @param deviceName The name of the device whose table
+ * will be added (Such as wlan or wwan)
+ * @param sourcePrefix The source network prefix or address
+ * that will be routed to the device
+ * (Such as 37.214.21/24 or 10.156.45.1)
+ * @param gatewayAddress The gateway address of the device.
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool addRoutingTable
+ (
+ uint8_t *deviceName,
+ uint8_t *sourcePrefix,
+ uint8_t *gatewayAddress
+ );
+
+ /**
+ * @brief Change the default routing table that is associated
+ * with any source addresses not bound to another table.
+ *
+ * The user of this function passes in the name of the RAT that
+ * matches the name already defined in the Android system. That
+ * device will become the new default. If this RAT is already the
+ * default, this function simply returns true.
+ *
+ * @param deviceName The name of the device whose table
+ * will be added (Such as wlan or wwan)
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool changeDefaultTable
+ (
+ uint8_t *deviceName
+ );
+
+ /**
+ * @brief Deletes a routing table from the system along with the
+ * rule corresponding to that table.
+ *
+ * @param deviceName The name of the device whose table will be
+ * deleted (Such as wlan or wwan)
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool deleteRoutingTable
+ (
+ uint8_t *deviceName
+ );
+
+ /**
+ * Displays the contents of all routing tables for debugging
+ * purposes.
+ *
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool showAllRoutingTables
+ (
+ void
+ );
+
+ /**
+ * Displays the contents of the routing table associated with
+ * the inputted device name.
+ *
+ * @param deviceName The name of the device to be displayed
+ * (Usually wlan or wwan)
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool showRoutingTable
+ (
+ uint8_t *deviceName
+ );
+
+ /**
+ * Displays the rules associated with all tables for debugging
+ * purposes.
+ *
+ * @return True if function is successful. False
+ * otherwise.
+ */
+ bool showRules
+ (
+ void
+ );
+
+ private:
+ /* constructor */
+ cnd_iproute2(){};
+ /* destructor */
+ ~cnd_iproute2(){};
+
+ static cnd_iproute2* instancePtr;
+};
+
+
+#endif /* CND_IPROUTE2_H*/
diff --git a/cnd/inc/cnd_unsol_messages.h b/cnd/inc/cnd_unsol_messages.h new file mode 100755 index 0000000..f77d7f3 --- /dev/null +++ b/cnd/inc/cnd_unsol_messages.h @@ -0,0 +1,29 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+ {0, NULL}, //none
+ {CNE_RESPONSE_REG_ROLE_MSG, responseInts},
+ {CNE_RESPONSE_GET_COMPATIBLE_NWS_MSG, responseInts},
+ {CNE_RESPONSE_CONFIRM_NW_MSG, responseInts},
+ {CNE_RESPONSE_DEREG_ROLE_MSG, responseInts},
+ {CNE_REQUEST_BRING_RAT_DOWN_MSG, eventRatChange},
+ {CNE_REQUEST_BRING_RAT_UP_MSG, eventRatChange},
+ {CNE_NOTIFY_MORE_PREFERED_RAT_AVAIL_MSG, responseInts},
+ {CNE_NOTIFY_RAT_LOST_MSG, responseInts},
+ {CNE_REQUEST_START_SCAN_WLAN_MSG, responseVoid},
+ {CNE_NOTIFY_INFLIGHT_STATUS_MSG, responseInts}
+
diff --git a/cnd/src/Android.mk b/cnd/src/Android.mk new file mode 100755 index 0000000..50a28a1 --- /dev/null +++ b/cnd/src/Android.mk @@ -0,0 +1,39 @@ +# For cnd binary
+# =======================
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+#this is needed to make sure that the path for stlport is specified before stdc++
+LOCAL_NO_DEFAULT_COMPILER_FLAGS :=true
+
+LOCAL_SRC_FILES:= \
+ cnd.c \
+ cnd_event.cpp \
+ cnd_process.cpp \
+ cnd_iproute2.cpp
+
+LOCAL_MODULE:= cnd
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libhardware_legacy \
+ libcne
+
+LOCAL_C_INCLUDES := \
+ external/connectivity/cnd/inc \
+ external/connectivity/include/cne \
+ external/STLport-5.2.1/stlport \
+ system/core/include \
+ frameworks/base/include \
+ bionic/libc/arch-arm/include \
+ bionic/libc/include \
+ bionic/libstdc++/include \
+ bionic/libc/kernel/common \
+ bionic/libc/kernel/arch-arm \
+ bionic/libm/include
+
+LOCAL_CFLAGS+= -fno-exceptions -fno-short-enums -include system/core/include/arch/linux-arm/AndroidConfig.h -DANDROID
+
+include $(BUILD_EXECUTABLE)
diff --git a/cnd/src/cnd.c b/cnd/src/cnd.c new file mode 100755 index 0000000..333ee96 --- /dev/null +++ b/cnd/src/cnd.c @@ -0,0 +1,46 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <cnd.h>
+#include "cutils/properties.h"
+
+#define LOG_TAG "CND"
+
+int main (int argc, char **argv)
+{
+ char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
+ int len = property_get("persist.cne.UseCne", prop_value, "FALSE");
+ prop_value[len] = '\0';
+ if((strcmp(prop_value, "TRUE") == 0) ||
+ (strcmp(prop_value, "true") == 0))
+ {
+ cnd_init();
+ cnd_startEventLoop();
+ while(1)
+ {
+ // sleep(UINT32_MAX) seems to return immediately on bionic
+ sleep(0x00ffffff);
+ }
+ }
+ return 0;
+}
+
+
diff --git a/cnd/src/cnd_event.cpp b/cnd/src/cnd_event.cpp new file mode 100755 index 0000000..8185d9f --- /dev/null +++ b/cnd/src/cnd_event.cpp @@ -0,0 +1,256 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "CND_EVENT"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <cnd_event.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pthread.h>
+
+static pthread_mutex_t listMutex;
+#define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex)
+#define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex)
+#define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL)
+#define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex)
+
+extern "C" void cne_svc_init(void);
+
+static fd_set readFds;
+static int nfds = 0;
+
+static struct cnd_event * watch_table[MAX_FD_EVENTS];
+static struct cnd_event pending_list;
+
+static void init_list(struct cnd_event * list)
+{
+ memset(list, 0, sizeof(struct cnd_event));
+ list->next = list;
+ list->prev = list;
+ list->fd = -1;
+}
+
+static void addToList(struct cnd_event * ev, struct cnd_event * list)
+{
+ ev->next = list;
+ ev->prev = list->prev;
+ ev->prev->next = ev;
+ list->prev = ev;
+
+}
+
+static void removeFromList(struct cnd_event * ev)
+{
+
+ ev->next->prev = ev->prev;
+ ev->prev->next = ev->next;
+ ev->next = NULL;
+ ev->prev = NULL;
+}
+
+
+static void removeWatch(struct cnd_event * ev, int index)
+{
+
+ LOGD ("removeWatch: fd=%d, index=%d", ev->fd, index);
+
+ watch_table[index] = NULL;
+ ev->index = -1;
+
+ FD_CLR(ev->fd, &readFds);
+
+ if (ev->fd+1 == nfds) {
+ int n = 0;
+
+ for (int i = 0; i < MAX_FD_EVENTS; i++) {
+ struct cnd_event * rev = watch_table[i];
+
+ if ((rev != NULL) && (rev->fd > n)) {
+ n = rev->fd;
+ }
+ }
+ nfds = n + 1;
+
+ }
+}
+
+static void processReadReadyEvent(fd_set * rfds, int n)
+{
+
+ LOGD ("processReadReadyEvent: n=%d, rfds0=%ld", n, rfds->fds_bits[0]);
+ MUTEX_ACQUIRE();
+
+ for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
+
+ struct cnd_event * rev = watch_table[i];
+
+ if (rev != NULL)
+ LOGD ("processReadReadyEvent: i=%d, fd=%d, rfds0=%ld", i, rev->fd, rfds->fds_bits[0]);
+ else
+ LOGD ("processReadReadyEvent: i=%d, rev is NULL", i);
+
+ if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
+ addToList(rev, &pending_list);
+ LOGD ("processReadReadyEvent: add to pendingList fd=%d", rev->fd);
+ if (rev->persist == 0) {
+ removeWatch(rev, i);
+ }
+ n--;
+ }
+ }
+
+ MUTEX_RELEASE();
+
+}
+
+static void firePendingEvent(void)
+{
+
+ struct cnd_event * ev = pending_list.next;
+ while (ev != &pending_list) {
+ struct cnd_event * next = ev->next;
+ removeFromList(ev);
+ ev->func(ev->fd, ev->param);
+ ev = next;
+ }
+
+}
+
+// Initialize internal data structs
+void cnd_event_init()
+{
+
+ MUTEX_INIT();
+ FD_ZERO(&readFds);
+ init_list(&pending_list);
+ memset(watch_table, 0, sizeof(watch_table));
+ cne_svc_init();
+}
+
+// Initialize an event
+void cnd_event_set(struct cnd_event * ev, int fd, int persist, cnd_event_cb func, void * param)
+{
+ memset(ev, 0, sizeof(struct cnd_event));
+
+ ev->fd = fd;
+ ev->index = -1;
+ ev->persist = persist;
+ ev->func = func;
+ ev->param = param;
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+}
+
+// Add event to watch list
+void cnd_event_add(struct cnd_event * ev)
+{
+
+ MUTEX_ACQUIRE();
+
+ for (int i = 0; i < MAX_FD_EVENTS; i++) {
+ if (watch_table[i] == NULL) {
+ watch_table[i] = ev;
+ ev->index = i;
+ LOGD ("cnd_event_add-before: add at i=%d for fd=%d, readFds0=%ld", i, ev->fd, readFds.fds_bits[0]);
+
+ FD_SET(ev->fd, &readFds);
+
+ if (ev->fd >= nfds)
+ nfds = ev->fd+1;
+ LOGD ("cnd_event_add-after: add at i=%d for fd=%d, readFds0=%ld", i, ev->fd, readFds.fds_bits[0]);
+
+ break;
+ }
+ }
+ MUTEX_RELEASE();
+
+
+}
+
+
+// Remove event from watch or timer list
+void cnd_event_del(struct cnd_event * ev)
+{
+
+
+ LOGD ("cnd_event_del: index=%d", ev->index);
+ MUTEX_ACQUIRE();
+
+ if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {
+ return;
+ }
+
+ removeWatch(ev, ev->index);
+
+ MUTEX_RELEASE();
+
+}
+
+
+void cnd_dump_watch_table(void)
+{
+ struct cnd_event * ev;
+ for (int i = 0; i < MAX_FD_EVENTS; i++) {
+ if (watch_table[i] != NULL) {
+ ev = watch_table[i];
+ LOGD ("cnd_dump_watch_table: at i=%d , fd=%d", i, ev->fd);
+ }
+ }
+
+ return;
+}
+
+void cnd_event_loop(void)
+{
+ int n;
+ fd_set rfds;
+ int s_fdCommand;
+
+ LOGD ("cnd_event_loop: started, nfds=%d",nfds);
+
+ for (;;) {
+ // make local copy of read fd_set
+ memcpy(&rfds, &readFds, sizeof(fd_set));
+
+ LOGD ("cnd_event_loop: waiting for select nfds=%d, rfds0=%ld", nfds, rfds.fds_bits[0]);
+
+ n = select(nfds, &rfds, NULL, NULL, NULL);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ LOGE("cnd_event_loop: select error (%d)", errno);
+ return;
+ }
+
+ if (n == 0)
+ LOGD ("cnd_event_loop: select timedout");
+ else if (n > 0)
+ LOGD ("cnd_event_loop: select ok,n=%d, rfds0=%ld",n, rfds.fds_bits[0]);
+
+ // Check for read-ready events
+ processReadReadyEvent(&rfds, n);
+ // Fire pending event
+ firePendingEvent();
+ }
+}
diff --git a/cnd/src/cnd_iproute2.cpp b/cnd/src/cnd_iproute2.cpp new file mode 100755 index 0000000..3d8ec45 --- /dev/null +++ b/cnd/src/cnd_iproute2.cpp @@ -0,0 +1,1084 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*============================================================================
+ FILE: cnd_iproute2.cpp
+
+ OVERVIEW: This program is an interface to make the necessary calls to
+ iproute2 in order to set up and take down routing tables.
+ These calls are made indirectly over the command line by using
+ a call to the C++ system() function. For each routing device
+ visible to the kernel, CneIproute2 allows one table. Each
+ table contains one entry, a path to the gateway address of the
+ routing device. A source address or network prefix is also
+ required in order to instantiate a table, so that packets from
+ that ip address are routed through the device.
+
+
+ DEPENDENCIES: None
+============================================================================*/
+
+/*----------------------------------------------------------------------------
+ * Include Files
+ * -------------------------------------------------------------------------*/
+#include "cnd_iproute2.h"
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <cstdarg>
+#include <map>
+#include <set>
+
+using namespace std;
+
+/*----------------------------------------------------------------------------
+ * Preprocessor Definitions and Constants
+ * -------------------------------------------------------------------------*/
+#undef LOG_TAG
+#define LOG_TAG "CNDIPROUTE2"
+
+/*----------------------------------------------------------------------------
+ * Type Declarations
+ * -------------------------------------------------------------------------*/
+// List of all actions supported from iproute2. Should match defintions
+// defined below prefixed with ACTIONS
+enum Cmd_line_actions
+{
+ ACTIONS_ADD_ENUM,
+ ACTIONS_DELETE_ENUM,
+ ACTIONS_FLUSH_ENUM,
+ ACTIONS_SHOW_ENUM
+};
+
+/** Stores information needed to create a routing table and a rule. This
+* allows the calling class to delete that table without needing to
+* keep track of any characteristics of the device other than its name.
+* Assumes that there can only be 1 rule associated with any defined
+* table.
+*/
+class DeviceInfo
+{
+ private:
+ // Variables relating to the routing table
+ int32_t tableNumber;
+ uint8_t *deviceName;
+ uint8_t *gatewayAddress;
+
+ // Variables relating to the corresponding rule.
+ uint8_t *sourcePrefix;
+ int32_t priorityNumber;
+
+ public:
+ DeviceInfo
+ (
+ uint8_t *deviceName,
+ int32_t tableNumber,
+ uint8_t *gatewayAddress,
+ uint8_t *sourcePrefix,
+ int32_t priorityNumber
+ )
+ {
+ DeviceInfo::deviceName = deviceName;
+ DeviceInfo::tableNumber = tableNumber;
+ DeviceInfo::gatewayAddress = gatewayAddress;
+ DeviceInfo::sourcePrefix = sourcePrefix;
+ DeviceInfo::priorityNumber = priorityNumber;
+ }
+
+ ~DeviceInfo();
+
+ uint8_t* getDeviceName(void)
+ {
+ return deviceName;
+ }
+
+ uint8_t* getGatewayAddress(void)
+ {
+ return gatewayAddress;
+ }
+
+ int32_t getPriorityNumber(void)
+ {
+ return priorityNumber;
+ }
+
+ uint8_t* getSourcePrefix(void)
+ {
+ return sourcePrefix;
+ }
+
+ int32_t getTableNumber(void)
+ {
+ return tableNumber;
+ }
+};
+
+/*----------------------------------------------------------------------------
+ * Global Data Definitions
+ * -------------------------------------------------------------------------*/
+//Set of all table numbers currently being used. Cannot contain more than
+//MAX_TABLE_SIZE - MIN_TABLE_SIZE elements
+set<int32_t> tableNumberSet;
+
+// Maps the name of a device to its corresponding routing characteristics
+map<uint8_t*, DeviceInfo*> deviceMap;
+
+// If a packet does not have an associated rule, it will go to the main
+// routing table and be routed to the following device by default
+DeviceInfo *defaultDevice;
+
+/*----------------------------------------------------------------------------
+ * Static Variable Definitions
+ * -------------------------------------------------------------------------*/
+// Commands to begin the command line string
+static const uint8_t *ROUTING_CMD = (uint8_t *)"ip route";
+static const uint8_t *RULE_CMD = (uint8_t *)"ip rule";
+
+// List of all actions supported from iproute2. These should match values in
+// above enumeration 'Cnd_line_actions'
+static const uint8_t *ACTIONS_ADD_STR = (uint8_t *)"add";
+static const uint8_t *ACTIONS_DELETE_STR = (uint8_t *)"delete";
+static const uint8_t *ACTIONS_FLUSH_STR = (uint8_t *)"flush";
+static const uint8_t *ACTIONS_SHOW_STR = (uint8_t *)"show";
+
+// Keywords used to refine calls to iproute2
+static const uint8_t *CMD_LINE_DEVICE_NAME = (uint8_t *)"dev";
+static const uint8_t *CMD_LINE_GATEWAY_ADDRESS = (uint8_t *)"via";
+static const uint8_t *CMD_LINE_PRIORITY_NUMBER = (uint8_t *)"priority";
+static const uint8_t *CMD_LINE_SOURCE_PREFIX = (uint8_t *)"from";
+static const uint8_t *CMD_LINE_TABLE_NUMBER = (uint8_t *)"table";
+
+// Keywords that refer to specific routes or tables
+static const uint8_t *ALL_TABLES = (uint8_t *)"all";
+static const uint8_t *CACHED_ENTRIES = (uint8_t *)"cache";
+static const uint8_t *DEFAULT_ADDRESS = (uint8_t *)"default";
+
+// Table #1 is the first usable routing table
+static const int32_t MIN_TABLE_NUMBER = 1;
+
+// Table #253 is the 'defined' default routing table, which should not
+// be overwritten
+static const int32_t MAX_TABLE_NUMBER = 252;
+
+// Priority number 32766 diverts packets to the main table (Table #254)
+static const int32_t MAX_PRIORITY_NUMBER = 32765;
+
+//Max number of digits in a table number is 3
+static const int32_t MAX_DIGITS_TABLE_NUMBER = 3;
+
+//Max number of digits in a priority number is 5
+static const int32_t MAX_DIGITS_PRIORITY_NUMBER = 5;
+
+cnd_iproute2* cnd_iproute2::instancePtr = NULL;
+
+/*-------------------------------------------------------------------------
+ * Declaration for a non-member method.
+ *-----------------------------------------------------------------------*/
+void flushCache
+(
+ void
+);
+
+uint8_t* cmdLineActionEnumToString
+(
+ Cmd_line_actions commandAction
+);
+
+bool modifyDefaultRoute
+(
+ uint8_t *deviceName,
+ Cmd_line_actions commandAction
+);
+
+bool modifyRoutingTable
+(
+ uint8_t *deviceName,
+ uint8_t *sourcePrefix,
+ uint8_t *gatewayAddress,
+ Cmd_line_actions commandAction
+);
+
+bool modifyRule
+(
+ DeviceInfo *currentDevice,
+ Cmd_line_actions commandAction
+);
+
+bool displayAllRoutingTables
+(
+ void
+);
+
+bool displayRoutingTable
+(
+ uint8_t *deviceName
+);
+
+bool displayRules
+(
+ void
+);
+
+bool cmdLineCaller
+(
+ const uint8_t* cmdLineFirstWord,
+ ...
+);
+
+/*----------------------------------------------------------------------------
+ * FUNCTION getInstance
+
+ DESCRIPTION Returns a pointer to an instance of the cnd_iproute2 such
+ that only 1 instance can be open at a time.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE cnd_iproute2*
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+cnd_iproute2* cnd_iproute2::getInstance
+(
+ void
+)
+{
+ if(NULL == instancePtr)
+ {
+ instancePtr = new cnd_iproute2;
+ }
+
+ return instancePtr;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION cmdLineActionEnumToString
+
+ * DESCRIPTION Helper function to converts values of Cmd_line_actions enum
+ to a string.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE uint8_t*
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+uint8_t* cmdLineActionEnumToString
+(
+ Cmd_line_actions commandAction
+)
+{
+ switch(commandAction)
+ {
+ case ACTIONS_ADD_ENUM:
+ return (uint8_t *)ACTIONS_ADD_STR;
+ break;
+ case ACTIONS_DELETE_ENUM:
+ return (uint8_t *)ACTIONS_DELETE_STR;
+ break;
+ case ACTIONS_FLUSH_ENUM:
+ return (uint8_t *)ACTIONS_FLUSH_STR;
+ break;
+ case ACTIONS_SHOW_ENUM:
+ return (uint8_t *)ACTIONS_SHOW_STR;
+ break;
+ default:
+ LOGE("Unsupported conversion of command action to string");
+ return '\0';
+ }
+}
+/*----------------------------------------------------------------------------
+ * FUNCTION flushCache
+
+ * DESCRIPTION Flushes the cache after routing table entries are changed
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE None
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+void flushCache
+(
+ void
+)
+{
+ if (!cmdLineCaller(ROUTING_CMD,
+ cmdLineActionEnumToString(ACTIONS_FLUSH_ENUM),
+ CACHED_ENTRIES))
+ {
+ LOGW("Attempt to flush the routing cache failed.");
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION modifyDefaultRoute
+
+ * DESCRIPTION Changes the default route given the name of the device that
+ will be either the new or old default. The default case
+ occurs if a packet is sent from some source address not
+ associated with a defined table. When this occurs, the main
+ table will route these undefined source addresses to the
+ gateway of the defined default device. This function will
+ add or delete that default route in the main table.
+
+ * DEPENDENCIES commandAction should be either ADD OR DELETE
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool modifyDefaultRoute
+(
+ uint8_t *deviceName,
+ Cmd_line_actions commandAction
+)
+{
+ if ('\0' == deviceName)
+ {
+ LOGE("A null device name was passed while changing the default table. ");
+ return false;
+ }
+
+ // If the upcoming command line call fails, revert to last default device
+ DeviceInfo *lastDefaultDevice = defaultDevice;
+
+ uint8_t *gatewayAddress;
+
+ switch(commandAction)
+ {
+ case ACTIONS_ADD_ENUM:
+ {
+ map<uint8_t*, DeviceInfo*>::iterator deviceMapIter;
+ deviceMapIter = deviceMap.find(deviceName);
+
+ if (deviceMapIter == deviceMap.end())
+ {
+ LOGE("Cannot make the nonexistant table %s the default.",
+ deviceName);
+ return false;
+ }
+
+ defaultDevice = deviceMapIter->second;
+ break;
+ }
+
+ case ACTIONS_DELETE_ENUM:
+ {
+ // The following case should only be entered if the default table is
+ // being deleted when no tables exist
+ if ('\0' == defaultDevice)
+ {
+ LOGE("Cannot delete a default table when none exists.");
+ return false;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ LOGE("Unsupported command action found while changing the default table");
+ return false;
+ }
+ }
+
+ gatewayAddress = defaultDevice->getGatewayAddress();
+
+ if (!cmdLineCaller(ROUTING_CMD,
+ cmdLineActionEnumToString(commandAction),
+ DEFAULT_ADDRESS,
+ CMD_LINE_GATEWAY_ADDRESS,
+ gatewayAddress,
+ CMD_LINE_DEVICE_NAME,
+ defaultDevice->getDeviceName()))
+ {
+ defaultDevice = lastDefaultDevice;
+ return false;
+ }
+
+ if (ACTIONS_DELETE_ENUM == commandAction)
+ {
+ // After a deletion, there should be default device defined
+ // in the main routing table
+ defaultDevice = '\0';
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION modifyRoutingTable
+
+ * DESCRIPTION Adds or deletes a routing table given the name of the device
+ associated with that table. This routing table has one route,
+ which will route all packets to some gateway address from
+ some inputted source address. Once the table has been
+ modified, modifyRoutingTable will call another function to
+ create or delete a rule that maps some source address'
+ packets to this table.
+
+ * DEPENDENCIES commandAction should be either ADD OR DELETE
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool modifyRoutingTable
+(
+ uint8_t *deviceName,
+ uint8_t *sourcePrefix,
+ uint8_t *gatewayAddress,
+ Cmd_line_actions commandAction
+)
+{
+ if ('\0' == deviceName)
+ {
+ LOGE("A null device name was passed while modifying a routing table");
+ return false;
+ }
+
+ int32_t tableNumber;
+ int32_t priorityNumber;
+
+ DeviceInfo *currentDevice;
+ map<uint8_t*, DeviceInfo*>::iterator deviceMapIter;
+ set<int32_t>::iterator tableNumberSetIter;
+
+ switch(commandAction)
+ {
+ case ACTIONS_ADD_ENUM:
+ {
+ if ('\0' == sourcePrefix)
+ {
+ LOGE("A null source prefix was passed when adding the %s table",
+ deviceName);
+ return false;
+ }
+
+ if ('\0' == gatewayAddress)
+ {
+ LOGE("A null gateway address was passed when adding the %s table",
+ deviceName);
+ return false;
+ }
+
+ deviceMapIter = deviceMap.find(deviceName);
+
+ // If a call to add a routing table overwrites an existing table, the
+ // new source and gateway addresses will overwrite the old ones.
+ // However, calls to add a duplicate table, where the source and
+ // gateway addresses do not change, are ignored and will not be
+ // considered a fatal error.
+ if (deviceMapIter != deviceMap.end())
+ {
+ DeviceInfo *existingDevice = deviceMapIter->second;
+
+ if ((0 != strcmp((char *)existingDevice->getGatewayAddress(),
+ (char *)gatewayAddress)) ||
+ (0 != strcmp((char *)existingDevice->getSourcePrefix(),
+ (char *)sourcePrefix)))
+ {
+ //Delete existing device with the same name
+ modifyRoutingTable(deviceName, '\0', '\0', ACTIONS_DELETE_ENUM);
+
+ //Delete default device that will be overwritten. New default will
+ //be added later
+ if (('\0' != defaultDevice) && (defaultDevice == existingDevice))
+ {
+ modifyDefaultRoute('\0', ACTIONS_DELETE_ENUM);
+ }
+ }
+
+ else {
+ LOGW("Adding a duplicate %s table with gateway %s and source %s",
+ deviceName, sourcePrefix, gatewayAddress);
+ return true;
+ }
+ }
+
+ // Instantiating more than 252 tables simultaneously is an error
+ if (MAX_TABLE_NUMBER - MIN_TABLE_NUMBER < tableNumberSet.size())
+ {
+ LOGE("Too many tables exist to add %s. %d tables are defined",
+ deviceName, tableNumberSet.size());
+ return false;
+ }
+
+ // Locate next available table number. If the previous check passed,
+ // there must be a table number available
+ for (int32_t nextTableNumber = MIN_TABLE_NUMBER;
+ nextTableNumber < MAX_TABLE_NUMBER; nextTableNumber++)
+ {
+ tableNumberSetIter = tableNumberSet.find(nextTableNumber);
+ if (tableNumberSetIter == tableNumberSet.end())
+ {
+ tableNumber = nextTableNumber;
+ }
+ }
+
+ // Always map the same rule to the same table number. This allows the
+ // reuse of priority numbers.
+ priorityNumber = MAX_PRIORITY_NUMBER - tableNumber;
+
+ currentDevice = new DeviceInfo(deviceName,
+ tableNumber,
+ gatewayAddress,
+ sourcePrefix,
+ priorityNumber);
+ break;
+ }
+
+ case ACTIONS_DELETE_ENUM:
+ {
+ if (deviceMap.empty())
+ {
+ LOGE("Deleting a table when no table exists.");
+ return false;
+ }
+
+ deviceMapIter = deviceMap.find(deviceName);
+
+ if (deviceMapIter == deviceMap.end())
+ {
+ LOGE("Cannot delete table %s that has not been created.", deviceName);
+ return false;
+ }
+
+ currentDevice = deviceMapIter->second;
+ gatewayAddress = currentDevice->getGatewayAddress();
+ tableNumber = currentDevice->getTableNumber();
+ break;
+ }
+
+ default:
+ {
+ LOGE("Unsupported command action found while modifying a table");
+ return false;
+ }
+ }
+
+ //Convert table number int to string, null-terminating the result
+ char tableNumberString[MAX_DIGITS_TABLE_NUMBER+1];
+ int32_t numberOfDigits = snprintf(tableNumberString,
+ MAX_DIGITS_TABLE_NUMBER,
+ "%d",
+ tableNumber);
+ tableNumberString[numberOfDigits] = '\0';
+
+ if (!cmdLineCaller(ROUTING_CMD,
+ cmdLineActionEnumToString(commandAction),
+ DEFAULT_ADDRESS,
+ CMD_LINE_GATEWAY_ADDRESS,
+ gatewayAddress,
+ CMD_LINE_DEVICE_NAME,
+ deviceName,
+ CMD_LINE_TABLE_NUMBER,
+ (uint8_t *)tableNumberString))
+ {
+ return false;
+ }
+
+ switch(commandAction)
+ {
+ case ACTIONS_ADD_ENUM:
+ {
+ deviceMap.insert(make_pair(deviceName, currentDevice));
+ tableNumberSet.insert(tableNumber);
+
+ // If there is no default table, the new device should be the default.
+ if ('\0' == defaultDevice)
+ {
+ modifyDefaultRoute(deviceName, ACTIONS_ADD_ENUM);
+ }
+
+ break;
+ }
+
+ case ACTIONS_DELETE_ENUM:
+ {
+ deviceMap.erase(deviceName);
+ tableNumberSet.erase(tableNumber);
+
+ // If there are no more tables, then there should be no default device.
+ if (0 == tableNumberSet.size())
+ {
+ modifyDefaultRoute('\0', ACTIONS_DELETE_ENUM);
+ }
+
+ // If the default table has been deleted and another device is available,
+ // set an arbitrary new device as the new default.
+ else if (defaultDevice == currentDevice)
+ {
+ uint8_t *newDefaultName = deviceMap.begin()->first;
+
+ modifyDefaultRoute('\0', ACTIONS_DELETE_ENUM);
+ modifyDefaultRoute(newDefaultName, ACTIONS_ADD_ENUM);
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return modifyRule(currentDevice, commandAction);
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION modifyRule
+
+ * DESCRIPTION Adds or deletes a rule given the actual device object of the
+ table associated with that rule. Every defined routing table
+ requires some rule to map packets from some given source
+ address to that routing table. This function takes an object
+ so that after a routing table has been removed, the source
+ prefix, table number, and priority number associated with that
+ table can still be accessed. This allows a call to be made to
+ iproute2 to delete the corresponding rule.
+
+ * DEPENDENCIES commandAction should be either ADD OR DELETE
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool modifyRule
+(
+ DeviceInfo *currentDevice,
+ Cmd_line_actions commandAction
+)
+{
+ if ('\0' == currentDevice)
+ {
+ LOGE("A null device was passed while modifying a rule");
+ return false;
+ }
+
+ uint8_t* deviceName = currentDevice->getDeviceName();
+ map<uint8_t*, DeviceInfo*>::iterator deviceMapIter;
+ deviceMapIter = deviceMap.find(deviceName);
+
+ // If a rule is being added, its corresponding table should exist in the map
+ // of all routing tables.
+ if ((ACTIONS_ADD_ENUM == commandAction) &&
+ (deviceMapIter == deviceMap.end()))
+ {
+ LOGE("Cannot %s a rule for nonexistant table %s",
+ cmdLineActionEnumToString(commandAction),
+ deviceName);
+ return false;
+ }
+
+ int32_t tableNumber = currentDevice->getTableNumber();
+ int32_t priorityNumber = currentDevice->getPriorityNumber();
+ uint8_t *sourcePrefix = currentDevice->getSourcePrefix();
+
+ //Convert table number & priority number ints to string, null-terminating
+ //the results
+ char tableNumberString[MAX_DIGITS_TABLE_NUMBER+1];
+ char priorityNumberString[MAX_DIGITS_PRIORITY_NUMBER+1];
+
+ int32_t numberOfDigits = snprintf(tableNumberString,
+ MAX_DIGITS_TABLE_NUMBER,
+ "%d",
+ tableNumber);
+ tableNumberString[numberOfDigits] = '\0';
+
+ numberOfDigits = snprintf(priorityNumberString,
+ MAX_DIGITS_PRIORITY_NUMBER,
+ "%d",
+ priorityNumber);
+ priorityNumberString[numberOfDigits] = '\0';
+
+ if (!cmdLineCaller(RULE_CMD,
+ cmdLineActionEnumToString(commandAction),
+ CMD_LINE_SOURCE_PREFIX,
+ sourcePrefix,
+ CMD_LINE_TABLE_NUMBER,
+ (uint8_t *)tableNumberString,
+ CMD_LINE_PRIORITY_NUMBER,
+ (uint8_t *)priorityNumberString))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION displayAllRoutingTables
+
+ * DESCRIPTION Displays contents of all routing tables
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool displayAllRoutingTables
+(
+ void
+)
+{
+ return cmdLineCaller(ROUTING_CMD,
+ cmdLineActionEnumToString(ACTIONS_SHOW_ENUM),
+ CMD_LINE_TABLE_NUMBER,
+ ALL_TABLES);
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION displayRoutingTable
+
+ * DESCRIPTION Displays contents of the inputted routing table
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool displayRoutingTable
+(
+ uint8_t *deviceName
+)
+{
+ if ('\0' == deviceName)
+ {
+ LOGE("A null argument was passed while displaying table %s.",
+ deviceName);
+ return false;
+ }
+
+ return cmdLineCaller(ROUTING_CMD,
+ cmdLineActionEnumToString(ACTIONS_SHOW_ENUM),
+ CMD_LINE_TABLE_NUMBER,
+ deviceName);
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION displayRules
+
+ * DESCRIPTION Displays all rules currently entered in the system
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool displayRules
+(
+ void
+)
+{
+ return cmdLineCaller(RULE_CMD,
+ cmdLineActionEnumToString(ACTIONS_SHOW_ENUM));
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION cmdLineCaller
+
+ * DESCRIPTION Sends a call to iproute2 over the command line. This function
+ takes in a list of an arbitrary number of words, which is
+ parsed together into one final string. This string is sent
+ over the command line using the C routine 'system'. Two
+ readers are instantiated to monitor any standard error and
+ standard output messages sent out by iproute2. These messages
+ are then passed to the Android log.
+
+ * DEPENDENCIES Should not be any spaces in any inputted argument
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cmdLineCaller
+(
+ const uint8_t* cmdLineFirstWord,
+ ...
+)
+{
+ size_t byteLength = 0;
+ size_t memLength;
+ va_list cmdLineWordList;
+ uint8_t *nextWord;
+ char *cmdLineString;
+
+ if ('\0' == cmdLineFirstWord)
+ {
+ LOGE("No actual command passed to build a command line.");
+ return false;
+ }
+
+ //Find length of overall command line string
+ byteLength = strlen((char *)cmdLineFirstWord);
+ va_start(cmdLineWordList, cmdLineFirstWord);
+
+ while((nextWord = va_arg(cmdLineWordList,uint8_t*)) != '\0')
+ {
+ byteLength += strlen((char *)nextWord);
+ }
+
+ va_end(cmdLineWordList);
+
+ //Allocate command line string
+ cmdLineString = new (nothrow) char[byteLength];
+
+ if (cmdLineString == '\0')
+ {
+ LOGE("Could not allocate memory to build command line string.");
+ return false;
+ }
+
+
+ memLength = strlcpy(cmdLineString,
+ (char *)cmdLineFirstWord,
+ strlen((char *)cmdLineFirstWord)*sizeof(uint8_t));
+ if (memLength > strlen((char *)cmdLineFirstWord) * sizeof(uint8_t))
+ {
+ LOGE("Failure building first word of command line string.");
+ delete [] cmdLineString;
+ return false;
+ }
+
+ //Build command line string containing each inputted word.
+ va_start(cmdLineWordList, cmdLineFirstWord);
+
+ while((nextWord = va_arg(cmdLineWordList,uint8_t*)) != '\0')
+ {
+ //Add white space
+ memLength = strlcat(cmdLineString,
+ " ",
+ sizeof(uint8_t));
+ if (memLength > sizeof(uint8_t))
+ {
+ LOGE("Failure building command line string.");
+ delete [] cmdLineString;
+ return false;
+ }
+
+ //Add next word
+ memLength = strlcat(cmdLineString,
+ (char *)nextWord,
+ strlen((char *)nextWord) * sizeof(uint8_t));
+ if (memLength > strlen((char *)nextWord) * sizeof(uint8_t))
+ {
+ LOGE("Failure building command line string.");
+ delete [] cmdLineString;
+ return false;
+ }
+ }
+
+ LOGI("Iproute2 has been called with: %s", cmdLineString);
+
+ int cmdLineExitValue = system(cmdLineString);
+
+ if (0 != cmdLineExitValue)
+ {
+ LOGE("Command line call to iproute2 failed with exitvalue %d.",
+ cmdLineExitValue);
+ delete [] cmdLineString;
+ return false;
+ }
+
+ delete [] cmdLineString;
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION addRoutingTable
+
+ * DESCRIPTION Adds a routing table to the system that contains a single
+ default entry, a route to the gateway address of a device.
+ It also adds a rule to route a given source network prefix or
+ address to the new table.
+
+ The parameter deviceName refers to the name of the device
+ whose table will be added (Such as wlan or wwan)
+ The parameter sourcePrefix refers to the source network prefix
+ or address that will be routed to the device (Such as
+ 37.214.21/24 or 10.156.45.1)
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::addRoutingTable
+(
+ uint8_t *deviceName,
+ uint8_t *sourcePrefix,
+ uint8_t *gatewayAddress
+)
+{
+ if (!modifyRoutingTable(deviceName,
+ sourcePrefix,
+ gatewayAddress,
+ ACTIONS_ADD_ENUM))
+ {
+ return false;
+ }
+
+ flushCache();
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION changeDefaultTable
+
+ * DESCRIPTION Changes the default device where packets are routed to. If
+ some source address does not match an already defined rule,
+ packets from that source address will be routed through the
+ main table to some default device. This function replaces the
+ default route to direct traffic to an inputted, already
+ defined device. A routing table associated with this device
+ must have been added through addRoutingTable() before it can
+ be the default.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::changeDefaultTable
+(
+ uint8_t *deviceName
+)
+{
+ // No need to perform function if the default device will not change
+ if (('\0' != defaultDevice) &&
+ (0 == strcmp((char *)defaultDevice->getDeviceName(),
+ (char *)deviceName)))
+ {
+ LOGW("The new default table %s is the same as the old.",
+ deviceName);
+ return true;
+ }
+
+ if (!modifyDefaultRoute('\0', ACTIONS_DELETE_ENUM))
+ {
+ return false;
+ }
+
+ if (!modifyDefaultRoute(deviceName, ACTIONS_ADD_ENUM))
+ {
+ return false;
+ }
+
+ flushCache();
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION deleteRoutingTable
+
+ * DESCRIPTION Deletes a routing table from the system along with the rule
+ corresponding to that table.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::deleteRoutingTable
+(
+ uint8_t *deviceName
+)
+{
+ if (!modifyRoutingTable(deviceName, '\0', '\0', ACTIONS_DELETE_ENUM))
+ {
+ return false;
+ }
+
+ flushCache();
+ return true;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION showAllRoutingTables
+
+ * DESCRIPTION Displays the contents of all routing tables for debugging
+ purposes.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::showAllRoutingTables
+(
+ void
+)
+{
+ return displayAllRoutingTables();
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION showRoutingTable
+
+ * DESCRIPTION Displays the contents of the routing table associated with
+ the inputted device name.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::showRoutingTable
+(
+ uint8_t *deviceName
+)
+{
+ return displayRoutingTable(deviceName);
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION showRoutingTable
+
+ * DESCRIPTION Displays the rules associated with all tables for debugging
+ purposes.
+
+ * DEPENDENCIES None
+
+ * RETURN VALUE bool - True if function is successful. False otherwise.
+
+ * SIDE EFFECTS None
+ *--------------------------------------------------------------------------*/
+bool cnd_iproute2::showRules
+(
+ void
+)
+{
+ return displayRules();
+}
diff --git a/cnd/src/cnd_process.cpp b/cnd/src/cnd_process.cpp new file mode 100755 index 0000000..45f687f --- /dev/null +++ b/cnd/src/cnd_process.cpp @@ -0,0 +1,1123 @@ +/*
+** Copyright 2006, The Android Open Source Project
+** Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+#define LOG_TAG "CND_PROCESS"
+
+#include <cutils/sockets.h>
+#include <cutils/jstring.h>
+#include <cutils/record_stream.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+#include <pthread.h>
+//#include <utils/Parcel.h>
+#include <binder/Parcel.h>
+#include <cutils/jstring.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <alloca.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <cutils/properties.h>
+#include <dirent.h>
+#include <cnd_event.h>
+#include <cnd.h>
+#include <cne_svc.h>
+
+
+
+
+namespace android {
+
+#define SOCKET_NAME_CND "cnd"
+
+// match with constant in .java
+#define MAX_COMMAND_BYTES (8 * 1024)
+
+// Basically: memset buffers that the client library
+// shouldn't be using anymore in an attempt to find
+// memory usage issues sooner.
+#define MEMSET_FREED 1
+
+#define NUM_ELEMS(a) (sizeof (a) / sizeof (a)[0])
+
+/* Constants for response types */
+#define SOLICITED_RESPONSE 0
+#define UNSOLICITED_MESSAGE 1
+
+typedef struct {
+ int commandNumber;
+ void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
+ int(*responseFunction) (Parcel &p, void *response, size_t responselen);
+} CommandInfo;
+
+typedef struct {
+ int messageNumber;
+ int (*responseFunction) (Parcel &p, void *response, size_t responselen);
+} UnsolMessageInfo;
+
+typedef struct RequestInfo {
+ int32_t token; //this is not CND_Token
+ int fd;
+ CommandInfo *pCI;
+ struct RequestInfo *p_next;
+ char cancelled;
+ char local; // responses to local commands do not go back to command process
+} RequestInfo;
+
+
+/*******************************************************************/
+
+static int s_registerCalled = 0;
+
+static pthread_t s_tid_dispatch;
+
+static int s_started = 0;
+
+static int s_fdListen = -1;
+static int s_fdCommand = -1;
+
+static int cnmSvcFd = -1;
+
+static struct cnd_event s_commands_event[MAX_FD_EVENTS];
+static struct cnd_event s_listen_event;
+static int command_index = 0;
+
+static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t s_writeMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_startupCond = PTHREAD_COND_INITIALIZER;
+
+static pthread_mutex_t s_dispatchMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_dispatchCond = PTHREAD_COND_INITIALIZER;
+
+static RequestInfo *s_pendingRequests = NULL;
+
+static RequestInfo *s_toDispatchHead = NULL;
+static RequestInfo *s_toDispatchTail = NULL;
+
+
+/*******************************************************************/
+static void dispatchVoid (Parcel& p, RequestInfo *pRI);
+static void dispatchString (Parcel& p, RequestInfo *pRI);
+static void dispatchStrings (Parcel& p, RequestInfo *pRI);
+static void dispatchInts (Parcel& p, RequestInfo *pRI);
+static void dispatchWlanInfo(Parcel &p, RequestInfo *pRI);
+static void dispatchWlanScanResults(Parcel &p, RequestInfo *pRI);
+static void dispatchRaw(Parcel& p, RequestInfo *pRI);
+static int responseInts(Parcel &p, void *response, size_t responselen);
+static int responseStrings(Parcel &p, void *response, size_t responselen);
+static int responseString(Parcel &p, void *response, size_t responselen);
+static int responseVoid(Parcel &p, void *response, size_t responselen);
+static int responseRaw(Parcel &p, void *response, size_t responselen);
+static int responseStartTrans(Parcel &p, void *response, size_t responselen);
+static int sendResponseRaw (const void *data, size_t dataSize, int fdCommand);
+static int sendResponse (Parcel &p, int fd);
+static int eventRatChange (Parcel &p, void *response, size_t responselen);
+static char *strdupReadString(Parcel &p);
+static void writeStringToParcel(Parcel &p, const char *s);
+static void memsetString (char *s);
+static int writeData(int fd, const void *buffer, size_t len);
+static void unsolicitedMessage(int unsolMessage, void *data, size_t datalen, int fd);
+static void processCommand (int command, void *data, size_t datalen, CND_Token t);
+static int processCommandBuffer(void *buffer, size_t buflen, int fd);
+static void invalidCommandBlock (RequestInfo *pRI);
+static void onCommandsSocketClosed(void);
+static void processCommandsCallback(int fd, void *param);
+static void listenCallback (int fd, void *param);
+static void *eventLoop(void *param);
+static int checkAndDequeueRequestInfo(struct RequestInfo *pRI);
+static void cnd_commandComplete(CND_Token t, CND_Errno e, void *response, size_t responselen);
+
+extern "C" const char * requestToString(int request);
+extern "C" void cne_processCommand (int command, void *data, size_t datalen);
+extern "C" void cne_regMessageCb(cne_messageCbType cbFn);
+
+/** Index == commandNumber */
+static CommandInfo s_commands[] = {
+#include "cnd_commands.h"
+};
+
+static UnsolMessageInfo s_unsolMessages[] = {
+#include "cnd_unsol_messages.h"
+};
+
+#define TEMP_BUFFER_SIZE (80)
+
+
+void cnd_sendUnsolicitedMsg(int targetFd, int msgType, int dataLen, void *data)
+{
+ int fd;
+
+ if (targetFd == 0) // TODO find the correct fd, who keeps track of it?
+ fd = cnmSvcFd;
+ else
+ fd = targetFd;
+
+ LOGD ("cnd_sendUnsolicitedMsg: Fd=%d, msgType=%d, datalen=%d\n",
+ targetFd, msgType, dataLen);
+
+ unsolicitedMessage(msgType, data, dataLen, fd);
+
+
+}
+
+static void
+processCommand (int command, void *data, size_t datalen, CND_Token t)
+{
+
+ LOGD ("processCommand: command=%d, datalen=%d", command, datalen);
+
+ /* Special handling for iproute2 command to setup iproute2 table */
+ if (command == CNE_REQUEST_CONFIG_IPROUTE2_CMD)
+ {
+ char **pStrings;
+ *pStrings = (char *)data;
+ LOGD ("processCommand: str1=%s, str2=%s", pStrings[0], pStrings[1]);
+ // Call iproute2 API
+
+ }
+ cne_processCommand(command, data, datalen);
+ cnd_commandComplete(t, CND_E_SUCCESS, NULL, 0);
+}
+
+static char *
+strdupReadString(Parcel &p)
+{
+ size_t stringlen;
+ const char16_t *s16;
+
+ s16 = p.readString16Inplace(&stringlen);
+
+ return strndup16to8(s16, stringlen);
+}
+
+static void writeStringToParcel(Parcel &p, const char *s)
+{
+ char16_t *s16;
+ size_t s16_len;
+ s16 = strdup8to16(s, &s16_len);
+ p.writeString16(s16, s16_len);
+ free(s16);
+}
+
+
+static void
+memsetString (char *s)
+{
+ if (s != NULL) {
+ memset (s, 0, strlen(s));
+ }
+}
+
+
+static void
+invalidCommandBlock (RequestInfo *pRI)
+{
+ //LOGE("invalid command block for token %d request %s",
+ // pRI->token, requestToString(pRI->pCI->commandNumber));
+}
+
+/** Callee expects NULL */
+static void
+dispatchVoid (Parcel& p, RequestInfo *pRI)
+{
+
+ processCommand(pRI->pCI->commandNumber, NULL, 0, pRI);
+}
+
+/** Callee expects const char * */
+static void
+dispatchString (Parcel& p, RequestInfo *pRI)
+{
+ status_t status;
+ size_t datalen;
+ size_t stringlen;
+ char *string8 = NULL;
+
+ string8 = strdupReadString(p);
+
+ processCommand(pRI->pCI->commandNumber, string8,
+ sizeof(char *), pRI);
+
+#ifdef MEMSET_FREED
+ memsetString(string8);
+#endif
+
+ free(string8);
+ return;
+}
+
+/** Callee expects const char ** */
+static void
+dispatchStrings (Parcel &p, RequestInfo *pRI)
+{
+ int32_t countStrings;
+ status_t status;
+ size_t datalen;
+ char **pStrings;
+
+ status = p.readInt32 (&countStrings);
+
+ if (status != NO_ERROR) {
+ goto invalid;
+ }
+
+
+ if (countStrings == 0) {
+ // just some non-null pointer
+ pStrings = (char **)alloca(sizeof(char *));
+ datalen = 0;
+ } else if (((int)countStrings) == -1) {
+ pStrings = NULL;
+ datalen = 0;
+ } else {
+ datalen = sizeof(char *) * countStrings;
+
+ pStrings = (char **)alloca(datalen);
+
+ for (int i = 0 ; i < countStrings ; i++) {
+ pStrings[i] = strdupReadString(p);
+
+ }
+ }
+
+ processCommand(pRI->pCI->commandNumber, pStrings, datalen, pRI);
+
+ if (pStrings != NULL) {
+ for (int i = 0 ; i < countStrings ; i++) {
+#ifdef MEMSET_FREED
+ memsetString (pStrings[i]);
+#endif
+ free(pStrings[i]);
+ }
+
+#ifdef MEMSET_FREED
+ memset(pStrings, 0, datalen);
+#endif
+ }
+
+ return;
+invalid:
+ invalidCommandBlock(pRI);
+ return;
+}
+
+/** Callee expects const int * */
+static void
+dispatchInts (Parcel &p, RequestInfo *pRI)
+{
+ int32_t count;
+ status_t status;
+ size_t datalen;
+ int *pInts;
+
+ status = p.readInt32 (&count);
+
+ LOGD ("dispatchInts: status=%d, count=%d", status, count);
+
+ if (status != NO_ERROR || count == 0) {
+ goto invalid;
+ }
+
+ datalen = sizeof(int) * count;
+ pInts = (int *)alloca(datalen);
+
+
+ for (int i = 0 ; i < count ; i++) {
+ int32_t t;
+
+ status = p.readInt32(&t);
+ pInts[i] = (int)t;
+
+
+ if (status != NO_ERROR) {
+ goto invalid;
+ }
+ }
+
+ processCommand(pRI->pCI->commandNumber, const_cast<int *>(pInts),
+ datalen, pRI);
+
+#ifdef MEMSET_FREED
+ memset(pInts, 0, datalen);
+#endif
+
+ return;
+invalid:
+ invalidCommandBlock(pRI);
+ return;
+}
+
+
+static void
+dispatchWlanInfo(Parcel &p, RequestInfo *pRI)
+{
+ int32_t t;
+ status_t status;
+ CneWlanInfoType args;
+
+ memset(&args, 0, sizeof(args));
+
+ status = p.readInt32 (&t);
+ args.status = (int)t;
+ status = p.readInt32 (&t);
+ args.rssi = (int)t;
+ args.ssid = strdupReadString(p);
+
+ LOGD ("dispatchWlanInfo: status=%ld, rssi=%ld, ssid=%s",
+ args.status, args.rssi, args.ssid);
+
+
+ processCommand(pRI->pCI->commandNumber, &args, sizeof(args), pRI);
+
+ return;
+}
+
+static void
+dispatchWlanScanResults(Parcel &p, RequestInfo *pRI)
+{
+ int32_t t;
+ status_t status;
+ CneWlanScanResultsType args;
+ int32_t numItems;
+
+ status = p.readInt32 (&t);
+ //args = (CneWlanScanResultsType *)malloc(sizeof(CneWlanScanResultsType)*numItems);
+ args.numItems = (int)t;
+ int max = (t < CNE_MAX_SCANLIST_SIZE)? t:CNE_MAX_SCANLIST_SIZE;
+
+ for (int i = 0; i < max; i++)
+ {
+ //args->numItems = numItems;
+ status = p.readInt32 (&t);
+ args.scanList[i].level = (int)t;
+ status = p.readInt32 (&t);
+ args.scanList[i].frequency = (int)t;
+ args.scanList[i].ssid = strdupReadString(p);
+ args.scanList[i].bssid = strdupReadString(p);
+ args.scanList[i].capabilities = strdupReadString(p);
+
+ LOGD ("dispatchWlanScanResults: max=%d, level=%ld, freq=%ld, ssid=%s, bssid=%s, cap=%s",
+ args.numItems, args.scanList[i].level, args.scanList[i].frequency,
+ args.scanList[i].ssid, args.scanList[i].bssid, args.scanList[i].capabilities);
+
+ }
+
+
+ processCommand(pRI->pCI->commandNumber, &args, sizeof(args), pRI);
+
+ return;
+}
+
+static void
+dispatchRaw(Parcel &p, RequestInfo *pRI)
+{
+ int32_t len;
+ status_t status;
+ const void *data;
+
+ status = p.readInt32(&len);
+
+ if (status != NO_ERROR) {
+ goto invalid;
+ }
+
+ // The java code writes -1 for null arrays
+ if (((int)len) == -1) {
+ data = NULL;
+ len = 0;
+ }
+
+ data = p.readInplace(len);
+
+ processCommand(pRI->pCI->commandNumber, const_cast<void *>(data), len, pRI);
+
+ return;
+invalid:
+ invalidCommandBlock(pRI);
+ return;
+}
+
+static int
+writeData(int fd, const void *buffer, size_t len)
+{
+ size_t writeOffset = 0;
+ const uint8_t *toWrite;
+
+ toWrite = (const uint8_t *)buffer;
+
+ LOGD ("writeData: len=%d",len);
+ while (writeOffset < len) {
+ ssize_t written;
+ do {
+ written = write (fd, toWrite + writeOffset,
+ len - writeOffset);
+ } while (written < 0 && errno == EINTR);
+
+ if (written >= 0) {
+ writeOffset += written;
+ } else { // written < 0
+ LOGE ("writeData: unexpected error on write errno:%d", errno);
+ close(fd);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+sendResponseRaw (const void *data, size_t dataSize, int fdCommand)
+{
+ int fd = fdCommand;
+ int ret;
+ uint32_t header;
+
+
+ LOGD ("sendResponseRaw: fdCommand=%d", fdCommand);
+ if (fdCommand < 0) {
+ return -1;
+ }
+
+ if (dataSize > MAX_COMMAND_BYTES) {
+ LOGE("sendResponseRaw: packet larger than %u (%u)",
+ MAX_COMMAND_BYTES, (unsigned int )dataSize);
+
+ return -1;
+ }
+
+ pthread_mutex_lock(&s_writeMutex);
+
+ header = htonl(dataSize);
+
+ ret = writeData(fd, (void *)&header, sizeof(header));
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ writeData(fd, data, dataSize);
+
+ if (ret < 0) {
+ pthread_mutex_unlock(&s_writeMutex);
+ return ret;
+ }
+
+ pthread_mutex_unlock(&s_writeMutex);
+
+ return 0;
+}
+
+static int
+sendResponse (Parcel &p, int fd)
+{
+
+ return sendResponseRaw(p.data(), p.dataSize(), fd);
+}
+
+static int
+responseStartTrans(Parcel &p, void *response, size_t responselen)
+{
+ int numInts;
+
+
+ LOGD ("responseStartTrans: len=%d",responselen);
+
+ if (response == NULL && responselen != 0) {
+ LOGE("invalid response: NULL");
+ return CND_E_INVALID_RESPONSE;
+ }
+
+
+ int *p_int = (int *) response;
+ //bool tmp = p_int[1];
+ char *p_char = (char *)response;
+
+ p.writeInt32(p_int[0]);
+ //writeStringToParcel(p, (const char *)p_char[4]);
+
+
+ //p.write(&tmp, 1);
+
+ LOGD ("responseStartTrans: int=%d, bool=%d",p_int[0], p_char[4]);
+
+ return 0;
+}
+
+/** response is an int* pointing to an array of ints*/
+
+static int
+responseInts(Parcel &p, void *response, size_t responselen)
+{
+ int numInts;
+
+
+ LOGD ("responseInts: len=%d",responselen);
+
+ if (response == NULL && responselen != 0) {
+ LOGE("invalid response: NULL");
+ return CND_E_INVALID_RESPONSE;
+ }
+ if (responselen % sizeof(int) != 0) {
+ LOGE("invalid response length %d expected multiple of %d\n",
+ (int)responselen, (int)sizeof(int));
+ return CND_E_INVALID_RESPONSE;
+ }
+
+ int *p_int = (int *) response;
+
+ numInts = responselen / sizeof(int *);
+ p.writeInt32 (numInts);
+
+ /* each int*/
+
+ for (int i = 0 ; i < numInts ; i++) {
+
+ p.writeInt32(p_int[i]);
+ }
+
+
+
+ return 0;
+}
+
+/** response is a char **, pointing to an array of char *'s */
+static int responseStrings(Parcel &p, void *response, size_t responselen)
+{
+ int numStrings;
+
+ if (response == NULL && responselen != 0) {
+ LOGE("invalid response: NULL");
+ return CND_E_INVALID_RESPONSE;
+ }
+ if (responselen % sizeof(char *) != 0) {
+ LOGE("invalid response length %d expected multiple of %d\n",
+ (int)responselen, (int)sizeof(char *));
+ return CND_E_INVALID_RESPONSE;
+ }
+
+ if (response == NULL) {
+ p.writeInt32 (0);
+ } else {
+ char **p_cur = (char **) response;
+
+ numStrings = responselen / sizeof(char *);
+ p.writeInt32 (numStrings);
+
+ /* each string*/
+
+ for (int i = 0 ; i < numStrings ; i++) {
+
+ writeStringToParcel (p, p_cur[i]);
+ }
+
+
+ }
+ return 0;
+}
+
+
+/**
+ * NULL strings are accepted
+ * FIXME currently ignores responselen
+ */
+static int responseString(Parcel &p, void *response, size_t responselen)
+{
+
+ LOGD ("responseString called");
+ /* one string only */
+ writeStringToParcel(p, (const char *)response);
+
+ return 0;
+}
+
+static int responseVoid(Parcel &p, void *response, size_t responselen)
+{
+ return 0;
+}
+
+static int responseRaw(Parcel &p, void *response, size_t responselen)
+{
+ if (response == NULL && responselen != 0) {
+ LOGE("invalid response: NULL with responselen != 0");
+ return CND_E_INVALID_RESPONSE;
+ }
+
+ // The java code reads -1 size as null byte array
+ if (response == NULL) {
+ p.writeInt32(-1);
+ } else {
+ p.writeInt32(responselen);
+ p.write(response, responselen);
+ }
+
+ return 0;
+}
+
+static int eventRatChange(Parcel &p, void *response, size_t responselen)
+{
+ if (response == NULL && responselen != 0)
+ {
+ LOGE("invalid response: NULL");
+ return CND_E_INVALID_RESPONSE;
+ }
+
+ CneRatInfoType *p_cur = ((CneRatInfoType *) response);
+ p.writeInt32((int)p_cur->rat);
+
+ /* if ((p_cur->rat == CNE_RAT_WLAN_HOME) ||
+ (p_cur->rat == CNE_RAT_WLAN_ENTERPRISE) ||
+ (p_cur->rat == CNE_RAT_WLAN_OPERATOR) ||
+ (p_cur->rat == CNE_RAT_WLAN_OTHER) ||
+ (p_cur->rat == CNE_RAT_WLAN_ANY))
+ {
+ writeStringToParcel (p, p_cur->wlan.ssid);
+ }
+ */
+ if (p_cur->rat == CNE_RAT_WLAN)
+ {
+ writeStringToParcel (p, p_cur->wlan.ssid);
+ }
+ return 0;
+}
+
+static int
+checkAndDequeueRequestInfo(struct RequestInfo *pRI)
+{
+ int ret = 0;
+
+ if (pRI == NULL) {
+ return 0;
+ }
+
+ pthread_mutex_lock(&s_pendingRequestsMutex);
+
+ for(RequestInfo **ppCur = &s_pendingRequests
+ ; *ppCur != NULL
+ ; ppCur = &((*ppCur)->p_next)
+ ) {
+ if (pRI == *ppCur) {
+ ret = 1;
+
+ *ppCur = (*ppCur)->p_next;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&s_pendingRequestsMutex);
+
+ return ret;
+}
+
+static void onCommandsSocketClosed()
+{
+ int ret;
+ RequestInfo *p_cur;
+
+ /* mark pending requests as "cancelled" so we dont report responses */
+
+ ret = pthread_mutex_lock(&s_pendingRequestsMutex);
+ assert (ret == 0);
+
+ p_cur = s_pendingRequests;
+
+ for (p_cur = s_pendingRequests
+ ; p_cur != NULL
+ ; p_cur = p_cur->p_next
+ ) {
+ p_cur->cancelled = 1;
+ }
+
+ ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
+ assert (ret == 0);
+}
+
+static void unsolicitedMessage(int unsolMessage, void *data, size_t datalen, int fd)
+{
+ int unsolMessageIndex;
+ int ret;
+
+ if (s_registerCalled == 0) {
+ // Ignore RIL_onUnsolicitedResponse before cnd_int
+ LOGW("unsolicitedMessage called before cnd_init");
+ return;
+ }
+
+ Parcel p;
+
+ p.writeInt32 (UNSOLICITED_MESSAGE);
+ p.writeInt32 (unsolMessage);
+
+ ret = s_unsolMessages[unsolMessage]
+ .responseFunction(p, data, datalen);
+
+ if (ret != 0) {
+ // Problem with the response. Don't continue;
+ LOGE("unsolicitedMessage: problem with response");
+ return;
+ }
+
+ LOGD ("unsolicitedMessage: sending Response");
+ ret = sendResponse(p, fd);
+
+ return;
+
+}
+
+static int
+processCommandBuffer(void *buffer, size_t buflen, int fd)
+{
+ Parcel p;
+ status_t status;
+ int32_t request;
+ int32_t token;
+ RequestInfo *pRI;
+ int ret;
+
+ p.setData((uint8_t *) buffer, buflen);
+
+ // status checked at end
+ status = p.readInt32(&request);
+ status = p.readInt32 (&token);
+
+ LOGD ("processCommandBuffer: request=%d, token=%d, fd=%d", request, token, fd);
+ if (status != NO_ERROR) {
+ LOGE("invalid request block");
+ return 0;
+ }
+
+ if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
+ LOGE("unsupported request code %d token %d", request, token);
+ // TBD: this should return a response
+ return 0;
+ }
+
+
+ pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
+
+ pRI->token = token;
+ pRI->fd = fd;
+ pRI->pCI = &(s_commands[request]);
+
+ ret = pthread_mutex_lock(&s_pendingRequestsMutex);
+ assert (ret == 0);
+
+ pRI->p_next = s_pendingRequests;
+ s_pendingRequests = pRI;
+
+ ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
+ assert (ret == 0);
+
+ pRI->pCI->dispatchFunction(p, pRI);
+
+ return 0;
+}
+
+static void processCommandsCallback(int fd, void *param)
+{
+ RecordStream *p_rs;
+ void *p_record;
+ size_t recordlen;
+ int ret;
+
+ LOGD ("processCommandsCallback: fd=%d, s_fdCommand=%d", fd, s_fdCommand);
+
+ p_rs = (RecordStream *)param;
+
+
+ for (;;) {
+ /* loop until EAGAIN/EINTR, end of stream, or other error */
+ ret = record_stream_get_next(p_rs, &p_record, &recordlen);
+
+ LOGD ("processCommandsCallback: len=%d, ret=%d", recordlen, ret);
+ if (ret == 0 && p_record == NULL) {
+ LOGD ("processCommandsCallback: end of stream");
+ /* end-of-stream */
+ break;
+ } else if (ret < 0) {
+ break;
+ } else if (ret == 0) { /* && p_record != NULL */
+ processCommandBuffer(p_record, recordlen, fd);
+
+ }
+ }
+
+ //LOGD ("processCommandsCallback: errno=%d, ret=%d", errno, ret);
+ if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
+ /* fatal error or end-of-stream */
+ if (ret != 0) {
+ LOGE("error on reading command socket errno:%d\n", errno);
+ } else {
+ LOGW("EOS. Closing command socket.");
+ }
+
+ LOGD ("processCommandsCallback: Closing");
+ close(s_fdCommand);
+ s_fdCommand = -1;
+
+ // cnd_event_del(&s_commands_event); // TODO - need to clean up properly
+
+ command_index = 0;
+
+ record_stream_free(p_rs);
+
+ /* start listening for new connections again */
+ cnd_event_add(&s_listen_event);
+
+ onCommandsSocketClosed();
+ }
+
+}
+
+static void listenCallback (int fd, void *param)
+{
+ int ret;
+ int err;
+ int is_cnm_svc_socket;
+ RecordStream *p_rs;
+ int i;
+ char tmpBuf[10];
+ int32_t pid, pid2, pid3, pid4;
+
+ struct sockaddr_un peeraddr;
+ socklen_t socklen = sizeof (peeraddr);
+
+ struct ucred creds;
+ socklen_t szCreds = sizeof(creds);
+
+
+ struct passwd *pwd = NULL;
+
+ assert (s_fdCommand < 0);
+ assert (fd == s_fdListen);
+
+ LOGD ("listenCallback: called");
+
+
+ s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
+
+
+ if (s_fdCommand < 0 ) {
+ LOGE("Error on accept() errno:%d", errno);
+ /* start listening for new connections again */
+ cnd_event_add(&s_listen_event);
+ return;
+ }
+
+ errno = 0;
+
+ err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
+
+ cnmSvcFd = s_fdCommand; // save command descriptor to be used for communication
+
+ ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK);
+
+ if (ret < 0) {
+ LOGE ("Error setting O_NONBLOCK errno = %d", errno);
+ }
+
+ LOGI("listenCallback: accept new connection, fd=%d", s_fdCommand);
+
+ p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
+
+
+ // note: persistent = 1, not removed from table
+ if (command_index >= MAX_FD_EVENTS)
+ {
+ LOGE ("Error: exceeding number of supported connection");
+ return;
+ }
+ cnd_event_set (&s_commands_event[command_index], s_fdCommand, 1, processCommandsCallback, p_rs);
+
+ cnd_event_add (&s_commands_event[command_index]);
+
+ command_index++;
+
+ return;
+
+}
+
+
+static void *
+eventLoop(void *param)
+{
+ int ret;
+ int filedes[2];
+
+ LOGD ("eventLoop: s_started=%d", s_started);
+
+ pthread_mutex_lock(&s_startupMutex);
+
+ s_started = 1;
+ pthread_cond_broadcast(&s_startupCond);
+
+ pthread_mutex_unlock(&s_startupMutex);
+
+ cnd_event_loop();
+
+
+ return NULL;
+}
+
+extern "C" void
+cnd_startEventLoop(void)
+{
+ int ret;
+ pthread_attr_t attr;
+
+ /* spin up eventLoop thread and wait for it to get started */
+ s_started = 0;
+ pthread_mutex_lock(&s_startupMutex);
+
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
+
+
+ while (s_started == 0) {
+ pthread_cond_wait(&s_startupCond, &s_startupMutex);
+ }
+
+
+ pthread_mutex_unlock(&s_startupMutex);
+
+ if (ret < 0) {
+ LOGE("Failed to create dispatch thread errno:%d", errno);
+ return;
+ }
+}
+
+extern "C" void
+cnd_init (void)
+{
+ int ret;
+
+ if (s_registerCalled > 0) {
+ LOGE("cnd_init has been called more than once. "
+ "Subsequent call ignored");
+ return;
+ }
+
+ s_registerCalled = 1;
+
+ cnd_event_init();
+
+ cne_regMessageCb(cnd_sendUnsolicitedMsg);
+
+
+ s_fdListen = android_get_control_socket(SOCKET_NAME_CND);
+ if (s_fdListen < 0) {
+ LOGE("Failed to get socket '" SOCKET_NAME_CND "'");
+ exit(-1);
+ }
+
+ ret = listen(s_fdListen, 4);
+
+ if (ret < 0) {
+ LOGE("Failed to listen on control socket '%d': %s",
+ s_fdListen, strerror(errno));
+ exit(-1);
+ }
+
+
+ LOGD ("cnd_init: adding listenCallback event, fd=%d",s_fdListen);
+
+ /* note: non-persistent to accept only one connection at a time */
+ //cnd_event_set (&s_listen_event, s_fdListen, 0, listenCallback, NULL);
+
+ // persistent to accept multiple connections at same time
+ cnd_event_set (&s_listen_event, s_fdListen, 1, listenCallback, NULL);
+
+ cnd_event_add (&s_listen_event);
+
+
+}
+
+
+//extern "C" void - TBD -may want to change this function to extern "C" and
+// be called from CneCet where Cne components (SRM/SPM/CDE) may send the
+// response to Cne java
+static void
+cnd_commandComplete(CND_Token t, CND_Errno e, void *response, size_t responselen)
+{
+ RequestInfo *pRI;
+ int ret;
+ size_t errorOffset;
+
+ pRI = (RequestInfo *)t;
+
+ LOGD ("cnd_commandComplete: started");
+
+ if (!checkAndDequeueRequestInfo(pRI)) {
+ LOGE ("cnd_commandComplete: invalid CND_Token");
+ return;
+ }
+
+ if (pRI->local > 0) {
+ goto done;
+ }
+
+
+ if (pRI->cancelled == 0) {
+ Parcel p;
+
+ p.writeInt32 (SOLICITED_RESPONSE);
+ p.writeInt32 (pRI->token);
+ errorOffset = p.dataPosition();
+
+ p.writeInt32 (e);
+
+
+ if (e == CND_E_SUCCESS) {
+ /* process response on success */
+ ret = pRI->pCI->responseFunction(p, response, responselen);
+ LOGD ("cnd_commandComplete: ret = %d", ret);
+ /* if an error occurred, rewind and mark it */
+ if (ret != 0) {
+ p.setDataPosition(errorOffset);
+ p.writeInt32 (ret);
+ }
+ } else {
+ LOGE ("cnd_commandComplete: Error");
+ }
+
+ if (pRI->fd < 0) {
+ LOGE ("cnd_commandComplete: Command channel closed");
+ }
+ LOGD ("cnd_commandComplete: sending Response");
+ sendResponse(p, pRI->fd);
+ }
+
+done:
+ free(pRI);
+}
+
+} /* namespace android */
+
+
|