blob: 6369e101b471c78f5c9793a381f269f3b21a9d88 [file] [log] [blame]
/*
Copyright (c) 2013, The Linux Foundation. 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 The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission. from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "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
IPACM_Main.cpp
@brief
This file implements the IPAM functionality.
@Author
Skylar Chang
*/
/******************************************************************************
IP_MAIN.C
******************************************************************************/
#include <sys/socket.h>
#include <signal.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <fcntl.h>
#include <sys/inotify.h>
#include <stdlib.h>
#include "IPACM_CmdQueue.h"
#include "IPACM_EvtDispatcher.h"
#include "IPACM_Defs.h"
#include "IPACM_Neighbor.h"
#include "IPACM_IfaceManager.h"
#include "IPACM_Log.h"
#include "IPACM_ConntrackListener.h"
#define IPA_DRIVER "/dev/ipa"
#define IPACM_DIR_NAME "/etc"
#define IPACM_FILE_NAME "mobileap_firewall.xml"
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
#define INOTIFY_BUF_LEN (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FILE_NAME))
#define IPA_DRIVER_WLAN_EVENT_SIZE (sizeof(struct ipa_wlan_msg))
#define IPA_DRIVER_WLAN_META_MSG (sizeof(struct ipa_msg_meta))
#define IPA_DRIVER_WLAN_BUF_LEN (IPA_DRIVER_WLAN_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
//char *log_buf = (char *)malloc(LOG_SIZE);
int ipa_get_if_index(char *if_name, int *if_index);
/* start netlink socket monitor*/
void* netlink_start(void *param)
{
ipa_nl_sk_fd_set_info_t sk_fdset;
int ret_val = 0;
memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
IPACMDBG("netlink starter memset sk_fdset succeeds\n");
ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
RTNLGRP_IPV6_PREFIX),
&sk_fdset, ipa_nl_recv_msg);
if (ret_val != IPACM_SUCCESS)
{
IPACMERR("Failed to initialize IPA netlink event listener\n");
return NULL;
}
return NULL;
}
/* start firewall-rule monitor*/
void* firewall_monitor(void *param)
{
int length;
int wd;
char buffer[INOTIFY_BUF_LEN];
int inotify_fd;
ipacm_cmd_q_data evt_data;
uint32_t mask = IN_MODIFY;
inotify_fd = inotify_init();
if (inotify_fd < 0)
{
PERROR("inotify_init");
}
IPACMDBG("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
wd = inotify_add_watch(inotify_fd,
IPACM_DIR_NAME,
mask);
while (1)
{
length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
struct inotify_event *event = (struct inotify_event *)buffer;
if (length < 0)
{
IPACMDBG("inotify read() error return length: %d and mask: 0x%x 0x%x\n", length, event->mask, mask);
return NULL;
}
if (event->len > 0)
{
if (event->mask & IN_MODIFY)
{
if (event->mask & IN_ISDIR)
{
IPACMDBG("The directory %s was 0x%x\n", event->name, event->mask);
}
else if (!strncmp(event->name, IPACM_FILE_NAME, event->len))
{
IPACMDBG("File \"%s\" was 0x%x\n", event->name, event->mask);
IPACMDBG("The interested file %s .\n", IPACM_FILE_NAME);
evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
evt_data.evt_data = NULL;
/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
}
IPACMDBG("Received monitoring event %s.\n", event->name);
}
}
(void)inotify_rm_watch(inotify_fd, wd);
(void)close(inotify_fd);
return NULL;
}
/* start IPACM WLAN-driver notifier */
void* ipa_driver_wlan_notifier(void *param)
{
int length, fd;
char buffer[IPA_DRIVER_WLAN_BUF_LEN];
struct ipa_msg_meta *event_hdr = NULL;
struct ipa_wlan_msg *event = NULL;
ipacm_cmd_q_data evt_data;
ipacm_event_data_mac *data;
fd = open(IPA_DRIVER, O_RDWR);
if (fd == 0)
{
IPACMERR("Failed opening %s.\n", IPA_DRIVER);
}
while (1)
{
IPACMDBG("Waiting for nofications from IPA driver \n");
memset(buffer, 0, sizeof(buffer));
length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
if (length < 0)
{
PERROR("didn't read IPA_driver correctly");
return NULL;
}
event_hdr = (struct ipa_msg_meta *)buffer;
IPACMDBG("Message type: %d\n", event_hdr->msg_type);
IPACMDBG("Event header length received: %d\n",event_hdr->msg_len);
if (event_hdr->msg_len > 0)
{
event = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
}
/* Insert WLAN_DRIVER_EVENT to command queue */
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if (data == NULL)
{
PERROR("unable to allocate memory for event data\n");
return NULL;
}
switch (event_hdr->msg_type)
{
case SW_ROUTING_ENABLE:
IPACMDBG("Received SW_ROUTING_ENABLE\n");
evt_data.event = IPA_SW_ROUTING_ENABLE;
evt_data.evt_data = NULL;
break;
case SW_ROUTING_DISABLE:
IPACMDBG("Received SW_ROUTING_DISABLE\n");
evt_data.event = IPA_SW_ROUTING_DISABLE;
evt_data.evt_data = NULL;
break;
case WLAN_CLIENT_CONNECT:
IPACMDBG("Received WLAN_CLIENT_CONNECT\n");
IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
evt_data.evt_data = data;
ipa_get_if_index(event->name, &(data->if_index));
memcpy(data->mac_addr,
event->mac_addr,
sizeof(event->mac_addr));
break;
case WLAN_CLIENT_DISCONNECT:
IPACMDBG("Received WLAN_CLIENT_DISCONNECT\n");
IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
memcpy(data->mac_addr,
event->mac_addr,
sizeof(event->mac_addr));
ipa_get_if_index(event->name, &(data->if_index));
evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
evt_data.evt_data = data;
break;
case WLAN_CLIENT_POWER_SAVE_MODE:
IPACMDBG("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
ipa_get_if_index(event->name, &(data->if_index));
evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
evt_data.evt_data = data;
memcpy(data->mac_addr,
event->mac_addr,
sizeof(event->mac_addr));
break;
case WLAN_CLIENT_NORMAL_MODE:
IPACMDBG("Received WLAN_CLIENT_NORMAL_MODE\n");
IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
memcpy(data->mac_addr,
event->mac_addr,
sizeof(event->mac_addr));
ipa_get_if_index(event->name, &(data->if_index));
evt_data.evt_data = data;
evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
break;
default:
IPACMDBG("Invalid message\n");
free(data);
continue;
}
/* finish command queue */
if (evt_data.evt_data == NULL)
{
free(data);
}
IPACMDBG("Posting event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
(void)close(fd);
return NULL;
}
int main(int argc, char **argv)
{
int ret;
pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
pthread_t cmd_queue_thread = 0;
IPACM_Neighbor *neigh = new IPACM_Neighbor();
IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
IPACMDBG("Staring IPA main\n");
IPACMDBG("ipa_cmdq_successful\n");
if (IPACM_SUCCESS == cmd_queue_thread)
{
ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to command queue thread\n");
return ret;
}
IPACMDBG("created command queue thread\n");
}
if (IPACM_SUCCESS == netlink_thread)
{
ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create netlink thread\n");
return ret;
}
IPACMDBG("created netlink thread\n");
}
if (IPACM_SUCCESS == monitor_thread)
{
ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create monitor thread\n");
return ret;
}
IPACMDBG("created firewall monitor thread\n");
}
if (IPACM_SUCCESS == ipa_driver_thread)
{
ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_wlan_notifier, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create ipa_driver_wlan thread\n");
return ret;
}
IPACMDBG("created ipa_driver_wlan thread\n");
}
pthread_join(cmd_queue_thread, NULL);
pthread_join(netlink_thread, NULL);
pthread_join(monitor_thread, NULL);
pthread_join(ipa_driver_thread, NULL);
return IPACM_SUCCESS;
}
/*===========================================================================
FUNCTION ipa_get_if_index
===========================================================================*/
/*!
@brief
get ipa interface index by given the interface name
@return
IPACM_SUCCESS or IPA_FALUIRE
@note
- Dependencies
- None
- Side Effects
- None
*/
/*=========================================================================*/
int ipa_get_if_index
(
char *if_name,
int *if_index
)
{
int fd;
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
PERROR("get interface index socket create failed");
return IPACM_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
(void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
{
PERROR("call_ioctl_on_dev: ioctl failed:");
close(fd);
return IPACM_FAILURE;
}
*if_index = ifr.ifr_ifindex;
close(fd);
return IPACM_SUCCESS;
}