blob: e957bd2e36b6cefa31a7b60dbf49e0964729e6a6 [file] [log] [blame]
/*
*
* Copyright (C) 2007 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIFI_ENABLE
#include "cmm.h"
#include "itf.h"
//#include <net/if.h>
#include <linux/sockios.h>
//#include <linux/wireless.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <module_wifi.h>
#define WIFI_FF_SYSCTL_PATH "/proc/sys/net/"
#define WIFI_FF_SYSCTL_ENTRY "wifi_fast_path_enable"
static int cmmFeWiFiGetBridge( FCI_CLIENT *fci_handle, int fd, struct interface *witf );
//static unsigned char wifi_sysctl[128];
#define SIOCVAPUPDATE (0x6401)
#define WIFI_FF_MASTER_IF "/dev/vwd0"
extern struct wifi_ff_entry glbl_wifi_ff_ifs[MAX_WIFI_FF_IFS];
void __cmmGetWiFi(int fd, struct interface *itf)
{
//struct iwreq pwrq;
char ifname[IFNAMSIZ];
int ii;
itf->itf_flags &= ~ITF_WIFI;
____itf_get_name(itf, ifname, IFNAMSIZ);
cmm_print(DEBUG_INFO, "%s: %s index:%d\n", __func__, ifname, itf->ifindex);
//strncpy(pwrq.ifr_name, ifname, IFNAMSIZ);
//if( ioctl(fd, SIOCGIWMODE, &pwrq) < 0 )
//{
// return;
//}
for( ii = 0; ii < MAX_WIFI_FF_IFS; ii++ )
{
if ( glbl_wifi_ff_ifs[ii].used )
if( !strcmp(glbl_wifi_ff_ifs[ii].ifname, ifname) )
{
cmm_print(DEBUG_INFO, "%s: wifi if is up %s \n", __func__, itf->ifname);
cmm_print(DEBUG_INFO, "%s: mac:%s:%d %x:%x:%x:%x:%x:%x \n", __func__,
itf->ifname, itf->macaddr_len, itf->macaddr[0], itf->macaddr[1],
itf->macaddr[2],itf->macaddr[3],itf->macaddr[4],itf->macaddr[5] );
itf->itf_flags |= ITF_WIFI;
itf->wifi_if = &glbl_wifi_ff_ifs[ii];
memcpy(glbl_wifi_ff_ifs[ii].macaddr, itf->macaddr, 6);
}
}
return;
}
static int cmmResetVWD()
{
vwd_cmd_t cmd;
int sfd;
memset(&cmd, 0, sizeof(cmd));
sfd = open(WIFI_FF_MASTER_IF, O_RDONLY);
if ( sfd <= 0 )
{
cmm_print(DEBUG_ERROR, "%s: failed to open vwd device: %s\n", __func__, strerror(errno));
return -1;
}
cmd.action = FPP_VWD_VAP_RESET;
if ( ioctl(sfd, SIOCVAPUPDATE, &cmd) < 0)
{
close(sfd);
cmm_print(DEBUG_ERROR, "%s::%d: ioctl() %s\n", __func__, __LINE__, strerror(errno));
return -1;
}
close(sfd);
return 0;
}
static int cmmUpdateVWD(struct interface *itf, int req)
{
vwd_cmd_t cmd;
// struct ifreq ifr;
int sfd;
memset(&cmd, 0, sizeof(cmd));
sfd = open(WIFI_FF_MASTER_IF, O_RDONLY);
if ( sfd <= 0 )
{
cmm_print(DEBUG_ERROR, "%s: failed to open vwd device: %s\n", __func__, strerror(errno));
return -1;
}
cmd.action = req;
cmd.ifindex = itf->ifindex;
memcpy( cmd.ifname, itf->ifname, 12);
memcpy( cmd.macaddr, itf->macaddr, 6);
cmd.vap_id = itf->wifi_if->vapid;
cmd.direct_path_rx = itf->wifi_if->direct_path_rx;
cmm_print(DEBUG_INFO, "%s: mac:%s:%d %x:%x:%x:%x:%x:%x \n", __func__,
itf->ifname, itf->ifindex, itf->macaddr[0], itf->macaddr[1],
itf->macaddr[2],itf->macaddr[3],itf->macaddr[4],itf->macaddr[5] );
if ( ioctl(sfd, SIOCVAPUPDATE, &cmd) < 0)
{
close(sfd);
cmm_print(DEBUG_ERROR, "%s::%d: ioctl() %s\n", __func__, __LINE__, strerror(errno));
return -1;
}
close(sfd);
return 0;
}
int cmmFeWiFiUpdate(FCI_CLIENT *fci_handle, int fd, int request, struct interface *itf)
{
struct fpp_wifi_cmd cmd;
short ret = 0;
int action;
switch (request)
{
default:
case ADD:
if ((itf->flags & (FPP_PROGRAMMED | FPP_NEEDS_UPDATE)) == FPP_PROGRAMMED)
goto out;
if ((itf->flags & (FPP_PROGRAMMED | FPP_NEEDS_UPDATE)) == (FPP_PROGRAMMED | FPP_NEEDS_UPDATE))
{
cmm_print(DEBUG_ERROR, "%s: trying to update wifi interface(%d)\n", __func__, itf->ifindex);
ret = -1;
goto out;
}
cmmFeWiFiGetBridge( fci_handle, fd, itf );
action = FPP_VWD_VAP_ADD;
break;
case UPDATE:
if (!(itf->flags & FPP_PROGRAMMED))
{
cmm_print(DEBUG_ERROR, "%s: trying to update non FF iface(%s)\n", __func__, itf->ifname);
goto out;
}
action = FPP_VWD_VAP_UPDATE;
break;
case REMOVE:
if (!(itf->flags & FPP_PROGRAMMED))
{
cmm_print( DEBUG_ERROR, "%s: Called remove, but not programmed\n", __func__);
goto out;
}
action = FPP_VWD_VAP_REMOVE;
break;
}
cmd.action = action;
cmd.vap_id = itf->wifi_if->vapid;
if (____itf_get_name(itf, cmd.ifname, sizeof(cmd.ifname)) < 0)
{
cmm_print(DEBUG_ERROR, "%s: ____itf_get_name(%d) failed\n", __func__, itf->ifindex);
goto out;
}
memcpy( cmd.mac_addr, itf->macaddr, 6);
//cmm_print(DEBUG_ERROR, "%s: mac:%s:%d %x:%x:%x:%x:%x:%x \n", __func__,
// cmd.ifname, cmd.vap_id,cmd.mac_addr[0], cmd.mac_addr[1],
// cmd.mac_addr[2],cmd.mac_addr[3],cmd.mac_addr[4],cmd.mac_addr[5] );
//Send VAP entry command to FPP
ret = fci_write(fci_handle, FPP_CMD_WIFI_VAP_ENTRY,
sizeof(fpp_wifi_cmd_t), (unsigned short *) &cmd);
if ( ret != FPP_ERR_OK )
{
cmm_print(DEBUG_ERROR, "%s: Failed command FPP_CMD_WIFI_VAP_ENTRY, action:error %d:%d\n",
__func__, action, ret);
goto out;
}
if( ! cmmUpdateVWD(itf, action) )
{
switch (action)
{
case FPP_VWD_VAP_UPDATE:
case FPP_VWD_VAP_ADD:
itf->flags |= FPP_PROGRAMMED;
itf->flags &= ~FPP_NEEDS_UPDATE;
break;
case FPP_VWD_VAP_REMOVE:
itf->flags &= ~FPP_PROGRAMMED;
itf->flags &= ~FPP_NEEDS_UPDATE;
break;
}
}
out:
return ret;
}
int cmmFeWiFiBridgeUpdate( FCI_CLIENT *fci_handle, int fd, int request, struct interface *bitf)
{
struct list_head *entry;
struct interface *itf;
short ret = 0;
int i, j;
/* Search through interface table if there are any
* WiFi interface and they are part of bridge then
* update the WiFi interfce in FPP with bridge MAC
* MAC address.
*/
for (i = 0; i < ITF_HASH_TABLE_SIZE; i++)
{
for (entry = list_first(&itf_table.hash[i]); entry != &itf_table.hash[i]; entry = list_next(entry))
{
itf = container_of(entry, struct interface, list);
if (!__itf_is_wifi(itf))
continue;
for( j = 0; j < MAX_PORTS; j++ )
{
//cmm_print(DEBUG_ERROR, "%s: index: %d:%d\n ", __func__,
//bitf->ifindices[j], itf->ifindex );
if(bitf->ifindices[j] == itf->ifindex )
break;
}
if( (j < MAX_PORTS) && (itf->flags & FPP_PROGRAMMED) && __itf_is_up(itf) )
{
cmm_print(DEBUG_INFO, "%s: wifi mac: %x:%x:%x:%x:%x:%x bridge mac: %x:%x:%x:%x:%x:%x\n ", __func__,
itf->macaddr[0], itf->macaddr[1], itf->macaddr[2],
itf->macaddr[3],itf->macaddr[4],itf->macaddr[5],
bitf->macaddr[0], bitf->macaddr[1], bitf->macaddr[2],
bitf->macaddr[3],bitf->macaddr[4],bitf->macaddr[5]
);
if ( (itf->macaddr[0] ^ bitf->macaddr[0]) ||
(itf->macaddr[1] ^ bitf->macaddr[1]) ||
(itf->macaddr[2] ^ bitf->macaddr[2]) ||
(itf->macaddr[3] ^ bitf->macaddr[3]) ||
(itf->macaddr[4] ^ bitf->macaddr[4]) ||
(itf->macaddr[5] ^ bitf->macaddr[5]) )
{
memcpy( itf->macaddr, bitf->macaddr, 6 );
ret = cmmFeWiFiUpdate(fci_handle, fd, UPDATE, itf);
}
}
}
}
return ret;
}
static int cmmFeWiFiGetBridge( FCI_CLIENT *fci_handle, int fd, struct interface *witf )
{
struct list_head *entry;
struct interface *itf;
int i, j;
/* Search through interface table if there are any
* bridge interface and it has given WiFi interface
* as one of its port and they are part of bridge then
* update the WiFi interfce in FPP with bridge MAC
* MAC address.
*/
for (i = 0; i < ITF_HASH_TABLE_SIZE; i++)
{
for (entry = list_first(&itf_table.hash[i]); entry != &itf_table.hash[i]; entry = list_next(entry))
{
itf = container_of(entry, struct interface, list);
if (!__itf_is_bridge(itf->ifindex))
continue;
for( j = 0; j < MAX_PORTS; j++ )
{
//cmm_print(DEBUG_ERROR, "%s: index: %d:%d\n ", __func__,
//bitf->ifindices[j], itf->ifindex );
if(itf->ifindices[j] == witf->ifindex )
break;
}
if( (j < MAX_PORTS) && __itf_is_up(witf) )
{
cmm_print(DEBUG_INFO, "%s: wifi mac: %x:%x:%x:%x:%x:%x bridge mac: %x:%x:%x:%x:%x:%x\n ", __func__,
witf->macaddr[0], witf->macaddr[1], witf->macaddr[2],
witf->macaddr[3],witf->macaddr[4],witf->macaddr[5],
itf->macaddr[0], itf->macaddr[1], itf->macaddr[2],
itf->macaddr[3],itf->macaddr[4],itf->macaddr[5]
);
if ( (itf->macaddr[0] ^ witf->macaddr[0]) ||
(itf->macaddr[1] ^ witf->macaddr[1]) ||
(itf->macaddr[2] ^ witf->macaddr[2]) ||
(itf->macaddr[3] ^ witf->macaddr[3]) ||
(itf->macaddr[4] ^ witf->macaddr[4]) ||
(itf->macaddr[5] ^ witf->macaddr[5]) )
{
memcpy( witf->macaddr, itf->macaddr, 6 );
}
}
}
}
return 0;
}
/*****************************************************************
* cmmWiFiReset
*
*
*
******************************************************************/
void cmmWiFiReset(FCI_CLIENT *fci_handle)
{
struct list_head *entry;
struct interface *itf;
short ret;
int i;
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_WIFI_VAP_RESET\n");
__pthread_mutex_lock(&itf_table.lock);
ret = fci_write(fci_handle, FPP_CMD_WIFI_VAP_RESET, 0, NULL);
if (ret == FPP_ERR_OK)
{
if (cmmResetVWD())
cmm_print(DEBUG_ERROR, "%s: Failed to reset VAPs with VWD\n", __func__);
for (i = 0; i < ITF_HASH_TABLE_SIZE; i++)
{
for (entry = list_first(&itf_table.hash[i]); entry != &itf_table.hash[i]; entry = list_next(entry))
{
itf = container_of(entry, struct interface, list);
if (!__itf_is_wifi(itf))
continue;
itf->flags &= ~FPP_PROGRAMMED;
}
}
}
else
{
cmm_print(DEBUG_ERROR, "%s: Error %d while sending CMD_WIFI_VAP_RESET\n", __func__, ret);
}
__pthread_mutex_unlock(&itf_table.lock);
}
#endif //WIFI_ENABLE