wanpipe/patches/kdrivers/src/net/wanpipe_utils.c

1531 lines
41 KiB
C

/*
* Copyright (c) 1997, 1998, 1999
* Alex Feldman <al.feldman@sangoma.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Alex Feldman.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD
* 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.
*
* $Id: wanpipe_utils.c,v 1.93 2006/11/23 22:00:58 sangoma Exp $
*/
/*
****************************************************************************
* wan_utils.c WANPIPE(tm) Multiprotocol WAN Utilities.
*
* Author: Alex Feldman <al.feldman@sangoma.com>
*
* ===========================================================================
* July 29, 2002 Alex Feldman Initial version.
****************************************************************************
*/
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
# include <wanpipe_includes.h>
# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
# include <wanpipe_snmp.h>
# endif
# include <wanpipe_abstr.h>
# include <wanpipe.h> /* WANPIPE common user API definitions */
#elif (defined __WINDOWS__)
# include <wanpipe\wanpipe_include.h>
#elif (defined __KERNEL__)
# include <linux/wanpipe_includes.h>
# include <linux/wanpipe_defines.h>
# include <linux/wanpipe_abstr.h>
# include <linux/wanpipe.h>
# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
# include <linux/if_wanpipe_common.h>
# include <linux/if_wanpipe.h>
# include <linux/wanpipe_snmp.h>
# endif
#else
# error "Unsupported Operating System!"
#endif
#ifdef __OpenBSD__
# define read_eflags() ({ register u_long ef; \
__asm("pushfl; popl %0" : "=r" (ef)); \
ef;})
# define write_eflags(x)({register u_long ef = (x); \
__asm("pushl %0; popfl" : : "r" (ef));})
#endif
/*
** Function prototypes.
*/
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
static void wanpipe_debug_timer(void* arg);
#else
static void wanpipe_debug_timer(unsigned long arg);
#endif
extern sdla_t* wanpipe_debug;
int wan_get_dbg_msg(wan_device_t* wandev, void* u_dbg_msg);
unsigned char wp_brt[256];
static void wan_generate_bit_rev_table(void)
{
unsigned char util_char;
unsigned char misc_status_byte;
int i;
/* generate the bit-reversing table for all unsigned characters */
for(util_char = 0;; util_char ++) {
misc_status_byte = 0; /* zero the character to be 'built' */
/* process all 8 bits of the source byte and generate the */
for(i = 0; i <= 7; i ++) {
/* corresponding 'bit-flipped' character */
if(util_char & (1 << i)) {
misc_status_byte |= (1 << (7 - i));
}
}
/* insert the 'bit-flipped' character into the table
* at the appropriate location */
wp_brt[util_char] = misc_status_byte;
/* exit when all unsigned characters have been processed */
if(util_char == 0xFF) {
break;
}
}
}
/*============================================================================
* Convert decimal string to unsigned integer.
* If len != 0 then only 'len' characters of the string are converted.
*/
unsigned int wan_dec2uint (unsigned char* str, int len)
{
unsigned val;
if (!len)
len = strlen(str);
for (val = 0; len && is_digit(*str); ++str, --len)
val = (val * 10) + (*str - (unsigned)'0');
return val;
}
/*
* ============================================================================
* Get WAN device state.
*/
char* wanpipe_get_state_string (void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
switch(card->wandev.state){
case WAN_UNCONFIGURED:
return "Unconfigured";
case WAN_DISCONNECTED:
return "Disconnected";
case WAN_CONNECTING:
return "Connecting";
case WAN_CONNECTED:
return "Connected";
case WAN_DISCONNECTING:
return "disconnecting";
case WAN_FT1_READY:
return "FT1 Ready";
}
return "Unknown";
}
/*
* ============================================================================
* Get WAN device state.
*/
char wanpipe_get_state (void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
return card->wandev.state;
}
/*
* ============================================================================
* Get WAN device state.
*/
void wanpipe_set_baud (void* card_id, unsigned int baud)
{
sdla_t* card = (sdla_t*)card_id;
/* Setup for bps */
card->wandev.bps=baud*1000;
}
/*
* ============================================================================
* Set WAN device state.
*/
void wanpipe_set_state (void* card_id, int state)
{
sdla_t* card = (sdla_t*)card_id;
if (card->wandev.state != state){
switch (state){
case WAN_CONNECTED:
DEBUG_EVENT("%s: Link connected!\n", card->devname);
card->wan_debugging_state = WAN_DEBUGGING_NONE;
break;
case WAN_CONNECTING:
DEBUG_EVENT("%s: Link connecting...\n", card->devname);
break;
case WAN_DISCONNECTED:
DEBUG_EVENT("%s: Link disconnected!\n", card->devname);
break;
}
card->wandev.state = state;
}
card->state_tick = SYSTEM_TICKS;
}
/*
* ============================================================================
* Check if packet is UDP packet or not.
*/
int wan_udp_pkt_type(void* card_id, caddr_t ptr)
{
sdla_t* card = (sdla_t*)card_id;
wan_udp_pkt_t* wan_udp_pkt = (wan_udp_pkt_t*)ptr;
unsigned int udp_port = card->wandev.udp_port;
DEBUG_UDP("%s: Ver 0x%x Prot 0x%x UDP type %d Req 0x%x\n",
card->devname,
wan_udp_pkt->wan_ip_v,
wan_udp_pkt->wan_ip_p,
wan_udp_pkt->wan_udp_dport,
wan_udp_pkt->wan_udp_request_reply);
if (wan_udp_pkt->wan_ip_v == 0x04 &&
wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL &&
wan_udp_pkt->wan_udp_dport == ntohs(udp_port) &&
wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST){
if (!strncmp(wan_udp_pkt->wan_udp_signature,
GLOBAL_UDP_SIGNATURE,
GLOBAL_UDP_SIGNATURE_LEN)){
return 0;
}
}
return UDP_INVALID_TYPE;
}
/*
* ============================================================================
* Calculate packet checksum.
*/
unsigned short wan_calc_checksum(char *data, int len)
{
unsigned short temp;
u_int32_t sum = 0;
int i;
for(i=0; i < len; i += 2){
memcpy(&temp, &data[i], 2);
sum += (u_int32_t)temp;
}
while(sum >> 16){
sum = (sum & 0xffffUL) + (sum >> 16);
}
temp = (unsigned short)sum;
temp = ~temp;
if (temp == 0){
temp = 0xFFFF;
}
return temp;
}
/*
* ===========================================================================
* Reply to UDP Management system.
* Agruments:
* mbox_len - includes data length and trace_info_t (chdlc and dsl).
* Return length of reply.
*/
int wan_reply_udp(void* card_id, unsigned char *data, unsigned int mbox_len)
{
sdla_t* card = (sdla_t*)card_id;
wan_udp_pkt_t* udp_pkt = (wan_udp_pkt_t*)data;
u_int32_t ip_temp;
unsigned short len,
udp_length,
temp,
ip_length;
int even_bound = 0;
/* fill in UDP reply */
udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY;
/* fill in UDP length */
udp_length =
sizeof(struct udphdr) +
sizeof(wan_mgmt_t) +
sizeof(wan_cmd_t) +
mbox_len;
if (card->wandev.config_id == WANCONFIG_CHDLC ||
card->wandev.config_id == WANCONFIG_SDLC){
udp_length += sizeof(wan_trace_info_t);
}
/* Set length of packet */
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
len = sizeof(struct ip) + udp_length;
#else
len = sizeof(struct iphdr) + udp_length;
#endif
/* put it on an even boundary */
if (udp_length & 0x0001){
udp_length += 1;
len += 1;
even_bound = 1;
}
temp = (udp_length<<8)|(udp_length>>8);
udp_pkt->wan_udp_len = temp;
/* swap UDP ports */
temp = udp_pkt->wan_udp_sport;
udp_pkt->wan_udp_sport = udp_pkt->wan_udp_dport;
udp_pkt->wan_udp_dport = temp;
/* add UDP pseudo header */
temp = 0x1100;
*((unsigned short*)(udp_pkt->wan_udp_data + mbox_len + even_bound)) = temp;
temp = (udp_length<<8)|(udp_length>>8);
*((unsigned short*)(udp_pkt->wan_udp_data + mbox_len + even_bound + 2)) = temp;
/* calculate UDP checksum */
udp_pkt->wan_udp_sum = 0;
udp_pkt->wan_udp_sum =
wan_calc_checksum(&data[UDP_OFFSET],
udp_length + UDP_OFFSET);
/* fill in IP length */
ip_length = len;
temp = (ip_length<<8)|(ip_length>>8);
udp_pkt->wan_ip_len = temp;
/* swap IP addresses */
ip_temp = udp_pkt->wan_ip_src;
udp_pkt->wan_ip_src = udp_pkt->wan_ip_dst;
udp_pkt->wan_ip_dst = ip_temp;
/* fill in IP checksum */
udp_pkt->wan_ip_sum = 0;
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
udp_pkt->wan_ip_sum = wan_calc_checksum(data, sizeof(struct ip));
#else
udp_pkt->wan_ip_sum = wan_calc_checksum(data, sizeof(struct iphdr));
#endif
return len;
} /* wan_reply_udp */
#if defined(__LINUX__)
/*
* ===========================================================================
* Reply to UDP Management system.
* Agruments:
* mbox_len - includes data length and trace_info_t (chdlc and dsl).
* Return length of reply.
*/
int wan_ip_udp_setup(void* card_id, wan_rtp_conf_t *rtp_conf,
u32 chan,
unsigned char *data, unsigned int mbox_len)
{
wan_rtp_pkt_t* rtp_pkt = (wan_rtp_pkt_t*)data;
unsigned short len,
udp_length,
temp,
ip_length;
int even_bound = 0;
/* fill in UDP length */
udp_length = sizeof(struct udphdr) +
sizeof(wan_rtp_hdr_t) +
mbox_len;
/* Set length of packet */
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
len = sizeof(struct ip) + udp_length;
#else
len = sizeof(struct iphdr) + udp_length;
#endif
/* put it on an even boundary */
#if 1
if (udp_length & 0x0001){
udp_length += 1;
data[sizeof(ethhdr_t)+sizeof(iphdr_t)+udp_length]=0;
len += 1;
even_bound = 1;
}
#endif
temp = (udp_length<<8)|(udp_length>>8);
rtp_pkt->wan_udp_len = temp;
temp = rtp_pkt->wan_udp_sport;
rtp_pkt->wan_udp_sport = htons(rtp_conf->rtp_port+chan);
rtp_pkt->wan_udp_dport = htons(rtp_conf->rtp_port+chan);
/* calculate UDP checksum */
rtp_pkt->wan_udp_sum = 0;
rtp_pkt->wan_udp_sum = 0;
#if 0
wan_calc_checksum(&data[sizeof(ethhdr_t)+UDP_OFFSET],
udp_length+UDP_OFFSET);
#endif
/* fill in IP length */
ip_length = len;
temp = (ip_length<<8)|(ip_length>>8);
rtp_pkt->wan_ip_len = temp;
/* IP addresses */
rtp_pkt->wan_ip_src = rtp_conf->rtp_local_ip;
rtp_pkt->wan_ip_dst = rtp_conf->rtp_ip;
rtp_pkt->wan_ip_v = 4;
rtp_pkt->wan_ip_hl = 5;
rtp_pkt->wan_ip_len = htons(ip_length);
rtp_pkt->wan_ip_tos = 1;
rtp_pkt->wan_ip_ttl = 255;
rtp_pkt->wan_ip_p = IPPROTO_UDP;
memcpy(rtp_pkt->wan_eth_dest,rtp_conf->rtp_mac,ETH_ALEN);
memcpy(rtp_pkt->wan_eth_src,rtp_conf->rtp_local_mac,ETH_ALEN);
rtp_pkt->wan_eth_proto=0x0008;
/* fill in IP checksum */
rtp_pkt->wan_ip_sum = 0;
rtp_pkt->wan_ip_sum = wan_calc_checksum(&data[sizeof(ethhdr_t)], sizeof(iphdr_t));
return len+sizeof(ethhdr_t);
} /* wan_ip_udp_setup */
#endif
/*
*****************************************************************************
**
**
*/
/*
** Initialize WANPIPE debug timer
*/
void wanpipe_debug_timer_init(void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
wan_init_timer(&card->debug_timer,
wanpipe_debug_timer,
(wan_timer_arg_t)card);
return;
}
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
static void wanpipe_debug_timer(void* arg)
#else
static void wanpipe_debug_timer(unsigned long arg)
#endif
{
sdla_t* card = (sdla_t*)arg;
wan_tasklet_t* debug_task = NULL;
/*
** I should set running flag to zero in order to
** schedule this task. I don't care if after setting
** this flag to zero, the same task can be scheduled from
** another place before I'll try to do this here, only
** one task will go through and the result will be same.
*/
WAN_ASSERT1(card == NULL);
debug_task = &card->debug_task;
if (card->wandev.state == WAN_UNCONFIGURED){
return;
}
WAN_TASKLET_END(debug_task);
WAN_TASKLET_SCHEDULE(debug_task);
}
/*
*****************************************************************************
**
**
*/
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
void wanpipe_debugging (void* data, int pending)
#else
void wanpipe_debugging (unsigned long data)
#endif
{
sdla_t* card = (sdla_t*)data;
wan_tasklet_t* debug_task = NULL;
static u_int32_t CRC_frames = 0, abort_frames = 0;
static u_int32_t tx_underun_frames = 0;
int delay = 0;
WAN_ASSERT1(card == NULL);
if (card->wandev.state == WAN_UNCONFIGURED){
goto wanpipe_debugging_end;
}
if (card->wandev.state == WAN_CONNECTED){
/*
** Terminate sequence because link comes UP.
*/
DEBUG_DBG("%s: WAN_DBG: Link came UP before the end of the DEBUG sequence!\n",
card->devname);
goto wanpipe_debugging_end;
}
if (card->wan_debugging_state == WAN_DEBUGGING_NONE ||
card->wan_debugging_state == WAN_DEBUGGING_AGAIN){
DEBUG_DBG("%s: WAN_DBG: Debugging state is %s!\n",
card->devname,
(card->wan_debugging_state == WAN_DEBUGGING_NONE) ? "Start":"Again");
card->wan_debugging_state = WAN_DEBUGGING_START;
}
if (IS_TE1_CARD(card) || IS_56K_CARD(card)){
u_int32_t status;
/* Sangoma T1/E1/56K cards */
/* Check Tv attributes */
if (card->wandev.fe_iface.read_alarm){
card->wandev.fe_iface.read_alarm(&card->fe, 0);
}
if (card->wandev.fe_iface.read_alarm &&
(status = card->wandev.fe_iface.read_alarm(&card->fe, 0))){
DEBUG_DBG("%s: WAN_DBG: T1/E1/56K is not in Service, print Alarms!\n",
card->devname);
/* Not in service, Alarms */
if (card->wan_debug_last_msg != WAN_DEBUG_ALARM_MSG){
card->wandev.fe_iface.print_fe_alarm(&card->fe, status);
DEBUG_EVENT("%s: Line for WANPIPEn is down.\n",
card->devname);
DEBUG_EVENT("%s: All WANPIPEn interfaces down.\n",
card->devname);
DEBUG_EVENT("%s: Tell your Telco about your\n",
card->devname);
DEBUG_EVENT("%s: ALARM condition.\n",
card->devname);
}
card->wan_debug_last_msg = WAN_DEBUG_ALARM_MSG;
}else{
/* In service, no Alarms */
switch(card->wan_debugging_state){
case WAN_DEBUGGING_START:
DEBUG_DBG("%s: WAN_DBG: T1/E1/56K in Service, reading statistics...\n",
card->devname);
/* Read number of CRC, abort and tx frames */
CRC_frames = card->get_crc_frames(card);
abort_frames = card->get_abort_frames(card);
tx_underun_frames = card->get_tx_underun_frames(card);
card->wan_debugging_state = WAN_DEBUGGING_CONT;
wan_add_timer(&card->debug_timer, 15*HZ);
return;
break;
case WAN_DEBUGGING_CONT:
if (IS_TE1_CARD(card) &&
((card->get_crc_frames(card) != CRC_frames) ||
(card->get_abort_frames(card) != abort_frames))){
DEBUG_DBG("%s: WAN_DBG: T1/E1/56K in Service, RX CRC/Abort frames!\n",
card->devname);
/* CRC/Abort frames, Probably incorrect channel config */
if (card->wan_debug_last_msg != WAN_DEBUG_TE1_MSG){
DEBUG_EVENT("%s: T1/E1 channel set-up is wrong!\n",
card->devname);
DEBUG_EVENT("%s: Your current channel configuration is %s!\n",
card->devname,
card->wandev.fe_iface.print_fe_act_channels(&card->fe));
DEBUG_EVENT("%s: Have your Telco check the \n",
card->devname);
DEBUG_EVENT("%s: active DS0 channels on your line.\n",
card->devname);
}
card->wan_debug_last_msg = WAN_DEBUG_TE1_MSG;
}else{
/* no CRC/Abort frames */
goto line_down_without_DSU_CSU_error;
}
break;
case WAN_DEBUGGING_PROTOCOL:
DEBUG_DBG("%s: WAN_DBG: Debugging protocol level...\n",
card->devname);
if (card->wan_debugging){
delay = card->wan_debugging(card);
}
break;
}
}
}else{
/* Sangoma Serial cards */
switch(card->wan_debugging_state){
case WAN_DEBUGGING_START:
DEBUG_DBG("%s: WAN_DBG: Serial card, reading statistics...\n",
card->devname);
/* Check CRC and abort stats for 15 second */
CRC_frames = card->get_crc_frames(card);
abort_frames = card->get_abort_frames(card);
tx_underun_frames = card->get_tx_underun_frames(card);
card->wan_debugging_state = WAN_DEBUGGING_CONT;
wan_add_timer(&card->debug_timer, 15*HZ);
return;
break;
case WAN_DEBUGGING_CONT:
if ((card->get_crc_frames(card) != CRC_frames) ||
(card->get_abort_frames(card) != abort_frames)){
DEBUG_DBG("%s: WAN_DBG: Serial card, RX CRC/Abort frames!\n",
card->devname);
/* CRC/Abort frames, Probably incorrect channel config */
if (card->wandev.clocking == WANOPT_EXTERNAL){
if (card->wan_debug_last_msg != WAN_DEBUG_LINERROR_MSG){
/* External clocking */
DEBUG_EVENT("%s: Your line is experiencing errors!\n",
card->devname);
DEBUG_EVENT("%s: Check your DSU/CSU and line configuration\n",
card->devname);
DEBUG_EVENT("%s: with your Telco.\n",
card->devname);
}
card->wan_debug_last_msg = WAN_DEBUG_LINERROR_MSG;
}else{
/* Internal clocking */
if (card->wan_debug_last_msg != WAN_DEBUG_CLK_MSG){
DEBUG_EVENT("%s: You are set for Internal clocking, \n",
card->devname);
DEBUG_EVENT("%s: causing line errors!\n",
card->devname);
DEBUG_EVENT("%s: Set to External clocking except for\n",
card->devname);
DEBUG_EVENT("%s: back-to-back testing!\n",
card->devname);
}
card->wan_debug_last_msg = WAN_DEBUG_CLK_MSG;
}
}else{
/* no CRC/Abort frames */
goto line_down_without_DSU_CSU_error;
}
break;
case WAN_DEBUGGING_PROTOCOL:
DEBUG_DBG("%s: WAN_DBG: Debugging protocol level...\n",
card->devname);
if (card->wan_debugging){
delay = card->wan_debugging(card);
}
break;
}
}
/* Link is down because DSU/CSU errors */
goto wanpipe_debugging_end;
line_down_without_DSU_CSU_error:
/* Link is down (no DSU/CSU errors) - may be protocol problem */
if (card->get_tx_underun_frames(card) != tx_underun_frames){
DEBUG_DBG("%s: WAN_DBG: No TX frames!\n",
card->devname);
if (card->wan_debug_last_msg != WAN_DEBUG_TX_MSG){
DEBUG_EVENT("%s: WAN port is not transmitting!\n",
card->devname);
DEBUG_EVENT("%s: No TX clock from DSU/CSU.\n",
card->devname);
DEBUG_EVENT("%s: Check your cable with your DSU/CSU supplier.\n",
card->devname);
}
card->wan_debug_last_msg = WAN_DEBUG_TX_MSG;
}else{
if (card->wan_debugging){
delay = card->wan_debugging(card);
}
if (card->wan_debugging_state == WAN_DEBUGGING_PROTOCOL){
wan_add_timer(&card->debug_timer, delay*HZ);
return;
}
}
goto wanpipe_debugging_end;
wanpipe_debugging_end:
/*
** WANPIPE debugging task is finished. Clear debugging flag!
*/
card->wan_debugging_state = WAN_DEBUGGING_NONE;
debug_task = &card->debug_task;
WAN_TASKLET_END(debug_task);
if (card->wandev.state != WAN_CONNECTED && card->wandev.state != WAN_UNCONFIGURED){
/*
** Repeat the WANPIPE debugging task in next 60 seconds.
*/
card->wan_debugging_state = WAN_DEBUGGING_AGAIN;
wan_add_timer(&card->debug_timer, WAN_DEBUGGING_DELAY*HZ);
}else{
/*
** Link is connected, We don't need to remember the last message
*/
card->wan_debug_last_msg = WAN_DEBUG_NONE_MSG;
WAN_DEBUG_STOP(card);
}
return;
}
/* ALEX_DEBUG */
void wan_debug_trigger(int flag)
{
if (wanpipe_debug == NULL){
return;
}
switch(flag){
case WAN_DEBUG_SET_TRIGGER:
wan_set_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status);
break;
case WAN_DEBUG_CLEAR_TRIGGER:
wan_clear_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status);
break;
}
return;
}
void wan_debug_write(char* msg)
{
wanpipe_kernel_msg_info_t wan_debug_info;
wanpipe_kernel_msg_hdr_t wan_dbg;
int len = strlen(msg);
wan_smp_flag_t smp_flags;
if (wanpipe_debug == NULL || !wanpipe_debug->configured){
return;
}
if (!wan_test_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status)){
/* No Debug Trigger */
return;
}
if (wan_test_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status) ||
wan_test_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status)){
/* We cannot add new message! */
return;
}
if (len == 0){
DEBUG_EVENT("wan_debug_write: Debug message is empty!\n");
return;
}
wan_spin_lock_irq(&wanpipe_debug->wandev.lock, &smp_flags);
wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, 0, &wan_debug_info, sizeof(wanpipe_kernel_msg_info_t));
if (wan_debug_info.magic != ROUTER_MAGIC || wanpipe_debug->u.debug.total_len == 0){
wan_debug_info.magic = ROUTER_MAGIC;
wan_debug_info.total_len = 0;
wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, 0,
&wan_debug_info, sizeof(wanpipe_kernel_msg_info_t));
wanpipe_debug->u.debug.total_len = 0;
wanpipe_debug->u.debug.total_num = 0;
wanpipe_debug->u.debug.current_offset = sizeof(wanpipe_kernel_msg_info_t);
}
if (wan_debug_info.total_len + sizeof(wanpipe_kernel_msg_info_t) + len > (256 * 1024)){
DEBUG_EVENT("wan_debug_write: There are no enought memory (%ld)!\n",
wan_debug_info.total_len);
DEBUG_EVENT("wan_debug_write: Disable debug message output!\n");
wan_set_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status);
goto wan_debug_write_done;
}
wan_dbg.len = len;
wan_getcurrenttime(&wan_dbg.time, NULL);
wanpipe_debug->hw_iface.poke(wanpipe_debug->hw,
wanpipe_debug->u.debug.total_len+sizeof(wanpipe_kernel_msg_info_t),
&wan_dbg,
sizeof(wanpipe_kernel_msg_hdr_t));
wanpipe_debug->u.debug.total_len += sizeof(wanpipe_kernel_msg_hdr_t);
wanpipe_debug->hw_iface.poke(wanpipe_debug->hw,
wanpipe_debug->u.debug.total_len+sizeof(wanpipe_kernel_msg_info_t),
msg,
len);
wanpipe_debug->u.debug.total_len += len;
wanpipe_debug->u.debug.total_num ++;
wan_debug_info.total_len = wanpipe_debug->u.debug.total_len;
wanpipe_debug->hw_iface.poke(wanpipe_debug->hw,
0,
&wan_debug_info,
sizeof(wanpipe_kernel_msg_info_t));
wan_debug_write_done:
wan_spin_unlock_irq(&wanpipe_debug->wandev.lock, &smp_flags);
return;
}
int wan_debug_read(void* device, void* u_dbg_msg)
{
wanpipe_kernel_msg_info_t wan_debug_info;
wan_kernel_msg_t dbg_msg;
wanpipe_kernel_msg_hdr_t* wan_dbg;
char* data = NULL;
unsigned long next_offset = 0, offset = 0;
int read_done = 0, err = 0;
wan_smp_flag_t smp_flags;
if (!wanpipe_debug || wanpipe_debug->wandev.state == WAN_UNCONFIGURED){
return -EINVAL;
}
wan_spin_lock_irq(&wanpipe_debug->wandev.lock, &smp_flags);
/* We are busy to read all debug message. Do not add new messages yet! */
if (!wan_test_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status)){
wan_set_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status);
DEBUG_DBG("wan_debug_read: Number of debug messages %ld\n",
wanpipe_debug->u.debug.total_num);
}
if (WAN_COPY_FROM_USER((void*)&dbg_msg, (void*)u_dbg_msg, sizeof(wan_kernel_msg_t))){
wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status);
err = -EFAULT;
goto wan_get_dbg_msg_error;
}
if (dbg_msg.magic != ROUTER_MAGIC){
wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status);
err = -EINVAL;
goto wan_get_dbg_msg_error;
}
if ((data = wan_malloc(dbg_msg.max_len)) == NULL){
wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status);
err = -ENOMEM;
goto wan_get_dbg_msg_error;
}
wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, 0,
&wan_debug_info, sizeof(wanpipe_kernel_msg_info_t));
if (wan_debug_info.total_len == 0 || wan_debug_info.magic != ROUTER_MAGIC){
DEBUG_DBG("%s: There are no debug messages!\n",
wanpipe_debug->devname);
dbg_msg.len = 0;
goto wan_get_dbg_msg_done;
}
next_offset = wanpipe_debug->u.debug.current_offset;
if (wan_debug_info.total_len-next_offset > dbg_msg.max_len){
dbg_msg.is_more = 1;
}
do {
wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, next_offset,
&data[offset], sizeof(wanpipe_kernel_msg_hdr_t));
wan_dbg = (wanpipe_kernel_msg_hdr_t*)&data[offset];
if (wan_dbg->len == 0){
DEBUG_DBG("wan_debug_read: Debug msg is empty!\n");
}
if (offset + sizeof(wanpipe_kernel_msg_hdr_t) + wan_dbg->len < dbg_msg.max_len){
next_offset += sizeof(wanpipe_kernel_msg_hdr_t);
offset += sizeof(wanpipe_kernel_msg_hdr_t);
wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, next_offset, &data[offset], wan_dbg->len);
next_offset += wan_dbg->len;
offset += wan_dbg->len;
dbg_msg.num ++;
}else{
read_done = 1;
}
if (next_offset >= wan_debug_info.total_len){
read_done = 1;
}
}while(!read_done);
wanpipe_debug->u.debug.current_offset = next_offset;
wan_get_dbg_msg_done:
if (offset){
if (WAN_COPY_TO_USER((void*)dbg_msg.data, (void*)data, offset)){
err = -EFAULT;
goto wan_get_dbg_msg_done;
}
}
dbg_msg.len = offset;
if (!dbg_msg.is_more){
DEBUG_DBG("%s: There are no more debug messages!\n",
wanpipe_debug->devname);
wan_debug_info.magic = ROUTER_MAGIC;
wan_debug_info.total_len = 0;
wanpipe_debug->u.debug.current_offset =
sizeof(wanpipe_kernel_msg_info_t);
wanpipe_debug->u.debug.total_len = 0;
wanpipe_debug->u.debug.total_num = 0;
wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, 0,
&wan_debug_info, sizeof(wanpipe_kernel_msg_info_t));
if (wan_test_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status)){
DEBUG_EVENT("wan_debug_write: Enable debug message output!\n");
wan_clear_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status);
}
wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status);
}
if (WAN_COPY_TO_USER((void*)u_dbg_msg, (void*)&dbg_msg, sizeof(wan_kernel_msg_t))){
err = -EFAULT;
goto wan_get_dbg_msg_done;
}
wan_get_dbg_msg_error:
if (data){
wan_free(data);
}
wan_spin_unlock_irq(&wanpipe_debug->wandev.lock, &smp_flags);
return err;
}
int wan_tracing_enabled(wan_trace_t *trace_info)
{
WAN_ASSERT(trace_info == NULL);
if (wan_test_bit(0,&trace_info->tracing_enabled)){
if ((SYSTEM_TICKS - trace_info->trace_timeout) > WAN_MAX_TRACE_TIMEOUT){
DEBUG_EVENT("wanpipe: Disabling trace, timeout!\n");
wan_clear_bit(0,&trace_info->tracing_enabled);
wan_clear_bit(1,&trace_info->tracing_enabled);
return -EINVAL;
}
if (wan_skb_queue_len(&trace_info->trace_queue) < trace_info->max_trace_queue){
if(wan_test_bit(3,&trace_info->tracing_enabled)){
/* Trace ALL cells, including Idle.
** Check that trace queue is NOT more than half full. */
if (wan_skb_queue_len(&trace_info->trace_queue) < trace_info->max_trace_queue / 2){
/*it is ok to enqueue an idle cell. */
return 3;
}else{
return -ENOBUFS;
}
}
if (wan_test_bit(1,&trace_info->tracing_enabled)){
return 1;
}
if (wan_test_bit(2,&trace_info->tracing_enabled)){
return 2;
}
return 0;
}
if (WAN_NET_RATELIMIT()){
DEBUG_EVENT("wanpipe: Warning: trace queue overflow %d (max=%d)!\n",
wan_skb_queue_len(&trace_info->trace_queue),
trace_info->max_trace_queue);
}
return -ENOBUFS;
}
return -EINVAL;
}
int wan_capture_trace_packet(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, char direction)
{
int len = 0;
void* new_skb = NULL;
wan_trace_pkt_t trc_el;
int flag = 0;
if ((flag = wan_tracing_enabled(trace_info)) >= 0){
/* Allocate a header mbuf */
len = wan_skb_len(skb) + sizeof(wan_trace_pkt_t);
new_skb = wan_skb_alloc(len);
if (new_skb == NULL)
return -1;
wan_getcurrenttime(&trc_el.sec, &trc_el.usec);
trc_el.status = direction;
trc_el.data_avail = 1;
trc_el.time_stamp =
(unsigned short)((((trc_el.sec * 1000000) + trc_el.usec) / 1000) % 0xFFFF);
trc_el.real_length = wan_skb_len(skb);
wan_skb_copyback(new_skb,
wan_skb_len(new_skb),
sizeof(wan_trace_pkt_t),
(caddr_t)&trc_el);
wan_skb_copyback(new_skb,
wan_skb_len(new_skb),
wan_skb_len(skb),
(caddr_t)wan_skb_data(skb));
wan_skb_queue_tail(&trace_info->trace_queue, new_skb);
}
return 0;
}
int wan_capture_trace_packet_offset(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, int off,char direction)
{
int flag = 0;
if ((flag = wan_tracing_enabled(trace_info)) >= 1){
int len = 0;
void* new_skb = NULL;
wan_trace_pkt_t trc_el, *trc_el_ptr;
int i,drop=1;
unsigned char diff=0,*src_ptr,*dest_ptr;
if (off < 1){
return -EINVAL;
}
/* Allocate a header mbuf */
len = wan_skb_len(skb) + sizeof(wan_trace_pkt_t) + 16;
new_skb = wan_skb_alloc(len);
if (new_skb == NULL)
return -1;
wan_getcurrenttime(&trc_el.sec, &trc_el.usec);
trc_el.status = direction;
trc_el.data_avail = 1;
trc_el.time_stamp =
(unsigned short)((((trc_el.sec * 1000000) + trc_el.usec) / 1000) % 0xFFFF);
trc_el.real_length = wan_skb_len(skb);
wan_skb_copyback(new_skb,
wan_skb_len(new_skb),
sizeof(wan_trace_pkt_t),
(caddr_t)&trc_el);
trc_el.real_length=0;
src_ptr=wan_skb_data(skb);
for (i=(off-1);i<wan_skb_len(skb);){
dest_ptr=wan_skb_put(new_skb,1);
dest_ptr[0]=src_ptr[i];
trc_el.real_length++;
if (i==(off-1)){
diff=dest_ptr[0];
}
if (diff != dest_ptr[0]){
drop=0;
}
if (IS_T1_CARD(card)){
i+=24;
}else{
i+=31;
}
}
if (drop){
wan_skb_free(new_skb);
return 0;
}
trc_el_ptr=(wan_trace_pkt_t*)wan_skb_data(new_skb);
trc_el_ptr->real_length = trc_el.real_length;
wan_skb_queue_tail(&trace_info->trace_queue, new_skb);
}
return 0;
}
void wan_trace_info_init(wan_trace_t *trace, int max_trace_queue)
{
wan_skb_queue_t* trace_queue = NULL;
trace_queue = &trace->trace_queue;
WAN_IFQ_INIT(trace_queue, max_trace_queue);
trace->trace_timeout = SYSTEM_TICKS;
trace->tracing_enabled = 0;
trace->max_trace_queue = max_trace_queue;
}
int wan_trace_purge (wan_trace_t *trace)
{
wan_skb_queue_t* trace_queue = NULL;
WAN_ASSERT(trace == NULL);
trace_queue = &trace->trace_queue;
WAN_IFQ_PURGE(trace_queue);
return 0;
}
int wan_trace_enqueue(wan_trace_t *trace, void *skb_ptr)
{
wan_skb_queue_t* trace_queue = NULL;
netskb_t* skb = (netskb_t*)skb_ptr;
int err = 0;
WAN_ASSERT(trace == NULL);
trace_queue = &trace->trace_queue;
WAN_IFQ_ENQUEUE(trace_queue, skb, NULL, err);
return err;
}
/*
*****************************************************************************
**
**
*/
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
u_char ds1_variables_oid[] = { 1,3,6,1,2,1,10,18 };
u_char fr_variables_oid[] = { 1,3,6,1,2,1,10,32 };
u_char ppp_variables_oid[] = { 1,3,6,1,2,1,10,23 };
u_char x25_variables_oid[] = { 1,3,6,1,2,1,10,5 };
int wan_snmp_data(sdla_t* card, netdevice_t* dev, int cmd, struct ifreq* ifr)
{
wanpipe_snmp_t snmp;
switch(cmd){
case SIOC_WANPIPE_SNMP:
break;
case SIOC_WANPIPE_SNMP_IFSPEED:
if (WAN_COPY_TO_USER(ifr->ifr_data, &card->wandev.bps, sizeof(card->wandev.bps))){
DEBUG_EVENT("%s: %s(): Line: %d: Failed to copy kernel space to user snmp data!\n",
card->devname, __FUNCTION__, __LINE__);
return -EFAULT;
}
return 0;
default:
DEBUG_EVENT("%s: Unknown cmd: %d (0x%X) \n",__FUNCTION__,cmd,cmd);
}
if (WAN_COPY_FROM_USER(&snmp, ifr->ifr_data, sizeof(wanpipe_snmp_t))){
DEBUG_EVENT("%s: Failed to copy user snmp data to kernel space!\n",
card->devname);
return -EFAULT;
}
if (strncmp((char *)ds1_variables_oid,(char *)snmp.snmp_name, sizeof(ds1_variables_oid)) == 0){
/* SNMP call for ds1 */
DEBUG_SNMP("%s: Get T1/E1 SNMP data\n",
card->devname);
if(card->wandev.fe_iface.get_snmp_data){
card->wandev.fe_iface.get_snmp_data(&card->fe, dev, &snmp);
}else{
DEBUG_EVENT("%s: Failed to get Front End SNMP data! Request is invalid for Serial Card.\n",
card->devname);
}
}else{
if (strncmp((char *)fr_variables_oid,(char *)snmp.snmp_name, sizeof(fr_variables_oid)) == 0){
/* SNMP call for frame relay */
DEBUG_SNMP("%s: Get Frame Relay SNMP data\n", card->devname);
}
if (strncmp((char *)ppp_variables_oid,(char *)snmp.snmp_name, sizeof(ppp_variables_oid)) == 0){
/* SNMP call for PPP */
DEBUG_SNMP("%s: Get PPP SNMP data\n", card->devname);
}
if (strncmp((char *)x25_variables_oid,(char *)snmp.snmp_name, sizeof(x25_variables_oid)) == 0){
/* SNMP call for x251 */
DEBUG_SNMP("%s: Get X.25 SNMP data\n", card->devname);
}
if (card->get_snmp_data){
card->get_snmp_data(card, dev, &snmp);
}else{
DEBUG_SNMP("%s: get_snmp_data() ptr is NULL!!\n", card->devname);
}
}
if (WAN_COPY_TO_USER(ifr->ifr_data, &snmp, sizeof(wanpipe_snmp_t))){
DEBUG_EVENT("%s: Failed to copy kernel space to user snmp data!\n",
card->devname);
return -EFAULT;
}
return 0;
}
#endif
void wanpipe_card_lock_irq(void *card_id, unsigned long *flags)
{
#define card ((sdla_t*)card_id)
wan_spin_lock_irq(&card->wandev.lock, (wan_smp_flag_t*)flags);
#undef card
}
void wanpipe_card_unlock_irq(void *card_id, unsigned long *flags)
{
#define card ((sdla_t*)card_id)
wan_spin_unlock_irq(&card->wandev.lock,(wan_smp_flag_t*)flags);
#undef card
}
/*===================================================
* Abstracted Wanpipe Specific Functions
*===================================================
*/
/*
* ============================================================================
* Get WAN device state.
*/
char wpabs_get_state (void* card_id)
{
return wanpipe_get_state(card_id);
}
void wpabs_card_lock_irq(void *card_id,unsigned long *flags)
{
wanpipe_card_lock_irq(card_id,flags);
}
void wpabs_card_unlock_irq(void *card_id,unsigned long *flags)
{
wanpipe_card_unlock_irq(card_id,flags);
}
int wpabs_trace_queue_len(void *trace_ptr)
{
wan_trace_t* trace = (wan_trace_t *)trace_ptr;
wan_skb_queue_t* trace_queue = NULL;
WAN_ASSERT(trace == NULL);
trace_queue = &trace->trace_queue;
return WAN_IFQ_LEN(trace_queue);
}
int wpabs_tracing_enabled(void *trace_ptr)
{
return wan_tracing_enabled((wan_trace_t*)trace_ptr);
}
void* wpabs_trace_info_alloc(void)
{
return wan_malloc(sizeof(wan_trace_t));
}
void wpabs_trace_info_init(void *trace_ptr, int max_trace_queue)
{
wan_trace_info_init(trace_ptr, max_trace_queue);
}
int wpabs_trace_purge (void *trace_ptr)
{
return wan_trace_purge(trace_ptr);
}
int wpabs_trace_enqueue(void *trace_ptr, void *skb_ptr)
{
return wan_trace_enqueue(trace_ptr, skb_ptr);
}
void wpabs_set_state (void* card_id, int state)
{
wanpipe_set_state(card_id, state);
}
/*
* ============================================================================
* Get WAN device state.
*/
void wpabs_set_baud (void* card_id, unsigned int baud)
{
wanpipe_set_baud(card_id, baud);
}
/*void* wpabs_dma_alloc(void* pcard, DMA_DESCRIPTION* dma_descr)
*/
void* wpabs_dma_alloc(void* pcard, unsigned long max_length)
{
sdla_t* card = (sdla_t*)pcard;
wan_dma_descr_t* dma_descr = NULL;
dma_descr = wan_malloc(sizeof(wan_dma_descr_t));
if (dma_descr == NULL){
return NULL;
}
dma_descr->max_length = max_length;
#if defined(__NetBSD__) || defined(__OpenBSD__)
card->hw_iface.getcfg(card->hw, SDLA_DMATAG, &dma_descr->dmat);
#endif
if (wan_dma_alloc(card->hw, dma_descr)){
wan_free(dma_descr);
return NULL;
}
return dma_descr;
}
int wpabs_dma_free(void* pcard, void* dma_descr)
{
int err=0;
sdla_t* card = (sdla_t*)pcard;
err=wan_dma_free(card->hw, (wan_dma_descr_t*)dma_descr);
wan_free(dma_descr);
return err;
}
/* LIP ATM definitions */
#define ATM_CELL_SIZE 53
#define ATM_HEADER_SZ 5
#define ATM_PAYLOAD_SZ 48
#define ATM_PAD_CHAR 0x6A
/*#define DEBUG_ATM DEBUG_EVENT*/
#define DEBUG_ATM DEBUG_TEST
int init_atm_idle_buffer(unsigned char *buff, int buff_len, char *if_name, char hardware_flip)
{
const unsigned char idle_cell_header[ATM_HEADER_SZ] = {0x00, 0x00, 0x00, 0x01, 0x52};
unsigned char idle_cell[ATM_CELL_SIZE];
int ind, number_of_cells_fit_idle_buffer;
/* copy header */
memcpy(idle_cell, idle_cell_header, ATM_HEADER_SZ);
/* init pad chars */
memset(&idle_cell[ATM_HEADER_SZ], ATM_PAD_CHAR, ATM_PAYLOAD_SZ);
number_of_cells_fit_idle_buffer = buff_len / ATM_CELL_SIZE;
if(number_of_cells_fit_idle_buffer == 0 /*|| buff_len % ATM_CELL_SIZE*/){
DEBUG_EVENT("%s: Error: Invalid Idle buffer length=%d, not multiple of ATM_CELL_SIZE (53)!\n",
if_name, buff_len);
return 1;
}
/* finally, init the buffer */
for(ind = 0; ind < number_of_cells_fit_idle_buffer; ind++){
memcpy(&buff[ind*ATM_CELL_SIZE], idle_cell, ATM_CELL_SIZE);
}
return 0;
}
int atm_add_data_to_skb(void* skb, void *data, int data_len, char *if_name)
{
unsigned char *skb_data_ptr;
DEBUG_ATM("%s(): data_len=%d, skb tail room=%d\n",
__FUNCTION__, data_len, wan_skb_tailroom(skb));
if(data_len > wan_skb_tailroom(skb)){
DEBUG_EVENT("%s: %s(): Warining: 'data_len=%d > skb tail room=%d'!\n",
if_name, __FUNCTION__, data_len, wan_skb_tailroom(skb));
return 1;
}
skb_data_ptr = wan_skb_put(skb, data_len);
/* copy data to the new skb */
memcpy(skb_data_ptr, data, data_len);
return 0;
}
int atm_pad_idle_cells_in_tx_skb(void *skb, void *tx_idle_skb, char *if_name)
{
unsigned char *idle_skb_data_ptr;
int num_of_cells_to_pad, i, empty_space;
DEBUG_ATM("%s()\n", __FUNCTION__);
idle_skb_data_ptr = wan_skb_data(tx_idle_skb);
empty_space = wan_skb_len(tx_idle_skb) - wan_skb_len(skb);
DEBUG_ATM("empty space length: %d\n", empty_space);
num_of_cells_to_pad = empty_space / ATM_CELL_SIZE;
DEBUG_ATM("num_of_cells_to_pad: %d\n", num_of_cells_to_pad);
if(empty_space % ATM_CELL_SIZE){
DEBUG_EVENT("%s: %s(): Error, empty space length (%d) is not multiple of ATM_CELL_SIZE!\n",
if_name, __FUNCTION__, empty_space);
return 1;
}
if(num_of_cells_to_pad){
for(i = 0 ; i < num_of_cells_to_pad; i++){
if(atm_add_data_to_skb(skb, idle_skb_data_ptr, ATM_CELL_SIZE, if_name)){
return 2;
}
}
}
return 0;
}
void *atm_tx_skb_dequeue(void* wp_tx_pending_list, void *tx_idle_skb, char *if_name)
{
void *tx_skb, *single_cell_skb;
int max_num_of_cells_fit_in_tx_buffer, i;
if(wan_skb_queue_len(wp_tx_pending_list) == 0){
return NULL;
}
DEBUG_ATM("%s(): queue len: %d\n", __FUNCTION__, wan_skb_queue_len(wp_tx_pending_list));
tx_skb = wan_skb_alloc(wan_skb_len(tx_idle_skb));
if (!tx_skb){
DEBUG_EVENT("%s: Failed to allocate ATM TX skb!\n", if_name);
return NULL;
}
max_num_of_cells_fit_in_tx_buffer = wan_skb_len(tx_idle_skb) / ATM_CELL_SIZE;
DEBUG_ATM("max_num_of_cells_fit_in_tx_buffer=%d\n", max_num_of_cells_fit_in_tx_buffer);
i=0;
while(i++ < max_num_of_cells_fit_in_tx_buffer){
single_cell_skb = wan_skb_dequeue(wp_tx_pending_list);
if(single_cell_skb == NULL){
/* no more data, but may be idle cells should be added */
DEBUG_ATM("no more data\n");
break;
}
atm_add_data_to_skb( tx_skb,
wan_skb_data(single_cell_skb),
wan_skb_len (single_cell_skb),
if_name);
wan_skb_free(single_cell_skb);
}
/* try to add idle cells, if no space it won't do anything */
atm_pad_idle_cells_in_tx_skb(tx_skb, tx_idle_skb, if_name);
return tx_skb;
}
int wanpipe_globals_util_init(void)
{
wan_generate_bit_rev_table();
return 0;
}
/*
* Verify iovec. The caller must ensure that the iovec is big enough
* to hold the message iovec.
*
* Save time not doing verify_area. copy_*_user will make this work
* in any case.
*/
#if defined(__LINUX__)
int wan_verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
{
int size, err, ct;
m->msg_name = NULL;
size = m->msg_iovlen * sizeof(struct iovec);
if (copy_from_user(iov, m->msg_iov, size))
return -EFAULT;
m->msg_iov = iov;
err = 0;
for (ct = 0; ct < m->msg_iovlen; ct++) {
err += iov[ct].iov_len;
/*
* Goal is not to verify user data, but to prevent returning
* negative value, which is interpreted as errno.
* Overflow is still possible, but it is harmless.
*/
if (err < 0)
return -EMSGSIZE;
}
return err;
}
/*
* Copy iovec to kernel. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/
int wan_memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
{
while (len > 0) {
if (iov->iov_len) {
int copy = min_t(unsigned int, len, iov->iov_len);
if (copy_from_user(kdata, iov->iov_base, copy))
return -EFAULT;
len -= copy;
kdata += copy;
iov->iov_base += copy;
iov->iov_len -= copy;
}
iov++;
}
return 0;
}
/*
* Copy kernel to iovec. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/
int wan_memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
{
while (len > 0) {
if (iov->iov_len) {
int copy = min_t(unsigned int, iov->iov_len, len);
if (copy_to_user(iov->iov_base, kdata, copy))
return -EFAULT;
kdata += copy;
len -= copy;
iov->iov_len -= copy;
iov->iov_base += copy;
}
iov++;
}
return 0;
}
#endif