2010-01-26 14:40:00 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/init.h>
# include <linux/bitops.h>
2006-01-11 23:17:47 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/seq_file.h>
/* We are an ethernet device */
# include <linux/if_ether.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <net/sock.h>
# include <linux/skbuff.h>
# include <linux/ip.h>
2010-01-26 14:40:09 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include <net/checksum.h> /* for ip_fast_csum() */
# include <net/arp.h>
# include <net/dst.h>
# include <linux/proc_fs.h>
/* And atm device */
# include <linux/atmdev.h>
# include <linux/atmlec.h>
# include <linux/atmmpc.h>
/* Modular too */
# include <linux/module.h>
# include "lec.h"
# include "mpc.h"
# include "resources.h"
/*
2007-02-09 17:24:29 +03:00
* mpc . c : Implementation of MPOA client kernel part
2005-04-17 02:20:36 +04:00
*/
#if 0
2010-01-26 14:40:20 +03:00
# define dprintk(format, args...) \
printk ( KERN_DEBUG " mpoa:%s: " format , __func__ , # # args )
# define dprintk_cont(format, args...) printk(KERN_CONT format, ##args)
2005-04-17 02:20:36 +04:00
# else
2010-01-26 14:40:20 +03:00
# define dprintk(format, args...) \
do { if ( 0 ) \
printk ( KERN_DEBUG " mpoa:%s: " format , __func__ , # # args ) ; \
} while ( 0 )
# define dprintk_cont(format, args...) \
do { if ( 0 ) printk ( KERN_CONT format , # # args ) ; } while ( 0 )
2005-04-17 02:20:36 +04:00
# endif
#if 0
2010-01-26 14:40:20 +03:00
# define ddprintk(format, args...) \
printk ( KERN_DEBUG " mpoa:%s: " format , __func__ , # # args )
# define ddprintk_cont(format, args...) printk(KERN_CONT format, ##args)
2005-04-17 02:20:36 +04:00
# else
2010-01-26 14:40:20 +03:00
# define ddprintk(format, args...) \
do { if ( 0 ) \
printk ( KERN_DEBUG " mpoa:%s: " format , __func__ , # # args ) ; \
} while ( 0 )
# define ddprintk_cont(format, args...) \
do { if ( 0 ) printk ( KERN_CONT format , # # args ) ; } while ( 0 )
2005-04-17 02:20:36 +04:00
# endif
# define MPOA_TAG_LEN 4
/* mpc_daemon -> kernel */
2010-01-26 14:40:09 +03:00
static void MPOA_trigger_rcvd ( struct k_message * msg , struct mpoa_client * mpc ) ;
2005-04-17 02:20:36 +04:00
static void MPOA_res_reply_rcvd ( struct k_message * msg , struct mpoa_client * mpc ) ;
static void ingress_purge_rcvd ( struct k_message * msg , struct mpoa_client * mpc ) ;
static void egress_purge_rcvd ( struct k_message * msg , struct mpoa_client * mpc ) ;
static void mps_death ( struct k_message * msg , struct mpoa_client * mpc ) ;
2010-01-26 14:40:09 +03:00
static void clean_up ( struct k_message * msg , struct mpoa_client * mpc ,
int action ) ;
static void MPOA_cache_impos_rcvd ( struct k_message * msg ,
struct mpoa_client * mpc ) ;
static void set_mpc_ctrl_addr_rcvd ( struct k_message * mesg ,
struct mpoa_client * mpc ) ;
static void set_mps_mac_addr_rcvd ( struct k_message * mesg ,
struct mpoa_client * mpc ) ;
2005-04-17 02:20:36 +04:00
2008-07-31 03:31:46 +04:00
static const uint8_t * copy_macs ( struct mpoa_client * mpc ,
const uint8_t * router_mac ,
const uint8_t * tlvs , uint8_t mps_macs ,
uint8_t device_type ) ;
2005-04-17 02:20:36 +04:00
static void purge_egress_shortcut ( struct atm_vcc * vcc , eg_cache_entry * entry ) ;
2008-07-31 03:31:46 +04:00
static void send_set_mps_ctrl_addr ( const char * addr , struct mpoa_client * mpc ) ;
2005-04-17 02:20:36 +04:00
static void mpoad_close ( struct atm_vcc * vcc ) ;
static int msg_from_mpoad ( struct atm_vcc * vcc , struct sk_buff * skb ) ;
static void mpc_push ( struct atm_vcc * vcc , struct sk_buff * skb ) ;
2009-08-31 23:50:42 +04:00
static netdev_tx_t mpc_send_packet ( struct sk_buff * skb ,
2010-01-26 14:40:09 +03:00
struct net_device * dev ) ;
static int mpoa_event_listener ( struct notifier_block * mpoa_notifier ,
unsigned long event , void * dev ) ;
2005-04-17 02:20:36 +04:00
static void mpc_timer_refresh ( void ) ;
2010-01-26 14:40:09 +03:00
static void mpc_cache_check ( unsigned long checking_time ) ;
2005-04-17 02:20:36 +04:00
static struct llc_snap_hdr llc_snap_mpoa_ctrl = {
0xaa , 0xaa , 0x03 ,
{ 0x00 , 0x00 , 0x5e } ,
{ 0x00 , 0x03 } /* For MPOA control PDUs */
2007-02-09 17:24:29 +03:00
} ;
2005-04-17 02:20:36 +04:00
static struct llc_snap_hdr llc_snap_mpoa_data = {
0xaa , 0xaa , 0x03 ,
{ 0x00 , 0x00 , 0x00 } ,
{ 0x08 , 0x00 } /* This is for IP PDUs only */
2007-02-09 17:24:29 +03:00
} ;
2005-04-17 02:20:36 +04:00
static struct llc_snap_hdr llc_snap_mpoa_data_tagged = {
0xaa , 0xaa , 0x03 ,
{ 0x00 , 0x00 , 0x00 } ,
{ 0x88 , 0x4c } /* This is for tagged data PDUs */
2007-02-09 17:24:29 +03:00
} ;
2005-04-17 02:20:36 +04:00
static struct notifier_block mpoa_notifier = {
mpoa_event_listener ,
NULL ,
0
} ;
struct mpoa_client * mpcs = NULL ; /* FIXME */
static struct atm_mpoa_qos * qos_head = NULL ;
2005-09-10 00:10:40 +04:00
static DEFINE_TIMER ( mpc_timer , NULL , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
static struct mpoa_client * find_mpc_by_itfnum ( int itf )
{
struct mpoa_client * mpc ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = mpcs ; /* our global linked list */
while ( mpc ! = NULL ) {
if ( mpc - > dev_num = = itf )
return mpc ;
2007-02-09 17:24:29 +03:00
mpc = mpc - > next ;
2005-04-17 02:20:36 +04:00
}
return NULL ; /* not found */
}
static struct mpoa_client * find_mpc_by_vcc ( struct atm_vcc * vcc )
{
struct mpoa_client * mpc ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = mpcs ; /* our global linked list */
while ( mpc ! = NULL ) {
if ( mpc - > mpoad_vcc = = vcc )
return mpc ;
mpc = mpc - > next ;
}
return NULL ; /* not found */
}
static struct mpoa_client * find_mpc_by_lec ( struct net_device * dev )
{
struct mpoa_client * mpc ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = mpcs ; /* our global linked list */
while ( mpc ! = NULL ) {
if ( mpc - > dev = = dev )
return mpc ;
mpc = mpc - > next ;
}
return NULL ; /* not found */
}
/*
* Functions for managing QoS list
*/
/*
* Overwrites the old entry or makes a new one .
*/
2006-11-15 08:11:29 +03:00
struct atm_mpoa_qos * atm_mpoa_add_qos ( __be32 dst_ip , struct atm_qos * qos )
2005-04-17 02:20:36 +04:00
{
struct atm_mpoa_qos * entry ;
entry = atm_mpoa_search_qos ( dst_ip ) ;
if ( entry ! = NULL ) {
entry - > qos = * qos ;
return entry ;
}
entry = kmalloc ( sizeof ( struct atm_mpoa_qos ) , GFP_KERNEL ) ;
if ( entry = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mpoa: out of memory \n " ) ;
2005-04-17 02:20:36 +04:00
return entry ;
}
entry - > ipaddr = dst_ip ;
entry - > qos = * qos ;
entry - > next = qos_head ;
qos_head = entry ;
return entry ;
}
2006-11-15 08:11:29 +03:00
struct atm_mpoa_qos * atm_mpoa_search_qos ( __be32 dst_ip )
2005-04-17 02:20:36 +04:00
{
struct atm_mpoa_qos * qos ;
qos = qos_head ;
2010-01-26 14:40:09 +03:00
while ( qos ) {
if ( qos - > ipaddr = = dst_ip )
2005-04-17 02:20:36 +04:00
break ;
qos = qos - > next ;
}
return qos ;
2007-02-09 17:24:29 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* Returns 0 for failure
*/
int atm_mpoa_delete_qos ( struct atm_mpoa_qos * entry )
{
struct atm_mpoa_qos * curr ;
2010-01-26 14:40:09 +03:00
if ( entry = = NULL )
return 0 ;
2005-04-17 02:20:36 +04:00
if ( entry = = qos_head ) {
qos_head = qos_head - > next ;
kfree ( entry ) ;
return 1 ;
}
curr = qos_head ;
while ( curr ! = NULL ) {
if ( curr - > next = = entry ) {
curr - > next = entry - > next ;
kfree ( entry ) ;
return 1 ;
}
curr = curr - > next ;
}
return 0 ;
}
/* this is buggered - we need locking for qos_head */
void atm_mpoa_disp_qos ( struct seq_file * m )
{
struct atm_mpoa_qos * qos ;
qos = qos_head ;
seq_printf ( m , " QoS entries for shortcuts: \n " ) ;
seq_printf ( m , " IP address \n TX:max_pcr pcr min_pcr max_cdv max_sdu \n RX:max_pcr pcr min_pcr max_cdv max_sdu \n " ) ;
while ( qos ! = NULL ) {
2008-10-31 10:54:56 +03:00
seq_printf ( m , " %pI4 \n %-7d %-7d %-7d %-7d %-7d \n %-7d %-7d %-7d %-7d %-7d \n " ,
2010-01-26 14:40:09 +03:00
& qos - > ipaddr ,
qos - > qos . txtp . max_pcr ,
qos - > qos . txtp . pcr ,
qos - > qos . txtp . min_pcr ,
qos - > qos . txtp . max_cdv ,
qos - > qos . txtp . max_sdu ,
qos - > qos . rxtp . max_pcr ,
qos - > qos . rxtp . pcr ,
qos - > qos . rxtp . min_pcr ,
qos - > qos . rxtp . max_cdv ,
qos - > qos . rxtp . max_sdu ) ;
2005-04-17 02:20:36 +04:00
qos = qos - > next ;
}
}
static struct net_device * find_lec_by_itfnum ( int itf )
{
struct net_device * dev ;
char name [ IFNAMSIZ ] ;
sprintf ( name , " lec%d " , itf ) ;
2007-09-17 22:56:21 +04:00
dev = dev_get_by_name ( & init_net , name ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return dev ;
}
static struct mpoa_client * alloc_mpc ( void )
{
struct mpoa_client * mpc ;
2010-01-26 14:40:09 +03:00
mpc = kzalloc ( sizeof ( struct mpoa_client ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( mpc = = NULL )
return NULL ;
rwlock_init ( & mpc - > ingress_lock ) ;
rwlock_init ( & mpc - > egress_lock ) ;
mpc - > next = mpcs ;
atm_mpoa_init_cache ( mpc ) ;
mpc - > parameters . mpc_p1 = MPC_P1 ;
mpc - > parameters . mpc_p2 = MPC_P2 ;
2010-01-26 14:40:09 +03:00
memset ( mpc - > parameters . mpc_p3 , 0 , sizeof ( mpc - > parameters . mpc_p3 ) ) ;
2005-04-17 02:20:36 +04:00
mpc - > parameters . mpc_p4 = MPC_P4 ;
2007-02-09 17:24:29 +03:00
mpc - > parameters . mpc_p5 = MPC_P5 ;
2005-04-17 02:20:36 +04:00
mpc - > parameters . mpc_p6 = MPC_P6 ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpcs = mpc ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return mpc ;
}
/*
*
* start_mpc ( ) puts the MPC on line . All the packets destined
2007-02-09 17:24:29 +03:00
* to the lec underneath us are now being monitored and
2005-04-17 02:20:36 +04:00
* shortcuts will be established .
*
*/
static void start_mpc ( struct mpoa_client * mpc , struct net_device * dev )
{
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) \n " , mpc - > dev - > name ) ;
2009-03-20 22:35:28 +03:00
if ( ! dev - > netdev_ops )
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) not starting \n " , dev - > name ) ;
2009-03-20 22:35:28 +03:00
else {
mpc - > old_ops = dev - > netdev_ops ;
mpc - > new_ops = * mpc - > old_ops ;
mpc - > new_ops . ndo_start_xmit = mpc_send_packet ;
dev - > netdev_ops = & mpc - > new_ops ;
2005-04-17 02:20:36 +04:00
}
}
static void stop_mpc ( struct mpoa_client * mpc )
{
2009-03-20 22:35:28 +03:00
struct net_device * dev = mpc - > dev ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
/* Lets not nullify lec device's dev->hard_start_xmit */
2009-03-20 22:35:28 +03:00
if ( dev - > netdev_ops ! = & mpc - > new_ops ) {
2010-01-26 14:40:20 +03:00
dprintk_cont ( " mpc already stopped, not fatal \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:20 +03:00
dprintk_cont ( " \n " ) ;
2007-02-09 17:24:29 +03:00
2009-03-20 22:35:28 +03:00
dev - > netdev_ops = mpc - > old_ops ;
mpc - > old_ops = NULL ;
/* close_shortcuts(mpc); ??? FIXME */
2005-04-17 02:20:36 +04:00
}
static const char * mpoa_device_type_string ( char type ) __attribute__ ( ( unused ) ) ;
static const char * mpoa_device_type_string ( char type )
{
2010-01-26 14:40:09 +03:00
switch ( type ) {
2005-04-17 02:20:36 +04:00
case NON_MPOA :
return " non-MPOA device " ;
case MPS :
return " MPS " ;
case MPC :
return " MPC " ;
case MPS_AND_MPC :
return " both MPS and MPC " ;
}
2010-01-26 14:40:09 +03:00
return " unspecified (non-MPOA) device " ;
2005-04-17 02:20:36 +04:00
}
/*
2008-12-08 12:14:16 +03:00
* lec device calls this via its netdev_priv ( dev ) - > lane2_ops
* - > associate_indicator ( ) when it sees a TLV in LE_ARP packet .
2005-04-17 02:20:36 +04:00
* We fill in the pointer above when we see a LANE2 lec initializing
* See LANE2 spec 3.1 .5
*
* Quite a big and ugly function but when you look at it
* all it does is to try to locate and parse MPOA Device
* Type TLV .
* We give our lec a pointer to this function and when the
* lec sees a TLV it uses the pointer to call this function .
*
*/
2008-07-31 03:31:46 +04:00
static void lane2_assoc_ind ( struct net_device * dev , const u8 * mac_addr ,
const u8 * tlvs , u32 sizeoftlvs )
2005-04-17 02:20:36 +04:00
{
uint32_t type ;
uint8_t length , mpoa_device_type , number_of_mps_macs ;
2008-07-31 03:31:46 +04:00
const uint8_t * end_of_tlvs ;
2005-04-17 02:20:36 +04:00
struct mpoa_client * mpc ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpoa_device_type = number_of_mps_macs = 0 ; /* silence gcc */
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) received TLV(s), " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
dprintk ( " total length of all TLVs %d \n " , sizeoftlvs ) ;
mpc = find_mpc_by_lec ( dev ) ; /* Sampo-Fix: moved here from below */
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) no mpc \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
end_of_tlvs = tlvs + sizeoftlvs ;
while ( end_of_tlvs - tlvs > = 5 ) {
2010-01-26 14:40:09 +03:00
type = ( ( tlvs [ 0 ] < < 24 ) | ( tlvs [ 1 ] < < 16 ) |
( tlvs [ 2 ] < < 8 ) | tlvs [ 3 ] ) ;
2005-04-17 02:20:36 +04:00
length = tlvs [ 4 ] ;
tlvs + = 5 ;
dprintk ( " type 0x%x length %02x \n " , type , length ) ;
if ( tlvs + length > end_of_tlvs ) {
2010-01-26 14:40:09 +03:00
pr_info ( " TLV value extends past its buffer, aborting parse \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
if ( type = = 0 ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mpoa: (%s) TLV type was 0, returning \n " ,
dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( type ! = TLV_MPOA_DEVICE_TYPE ) {
tlvs + = length ;
continue ; /* skip other TLVs */
}
mpoa_device_type = * tlvs + + ;
number_of_mps_macs = * tlvs + + ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) MPOA device type '%s', " ,
2010-01-26 14:40:09 +03:00
dev - > name , mpoa_device_type_string ( mpoa_device_type ) ) ;
2005-04-17 02:20:36 +04:00
if ( mpoa_device_type = = MPS_AND_MPC & &
length < ( 42 + number_of_mps_macs * ETH_ALEN ) ) { /* :) */
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) short MPOA Device Type TLV \n " ,
dev - > name ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2010-01-26 14:40:09 +03:00
if ( ( mpoa_device_type = = MPS | | mpoa_device_type = = MPC ) & &
length < 22 + number_of_mps_macs * ETH_ALEN ) {
pr_info ( " (%s) short MPOA Device Type TLV \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2010-01-26 14:40:09 +03:00
if ( mpoa_device_type ! = MPS & &
mpoa_device_type ! = MPS_AND_MPC ) {
2010-01-26 14:40:20 +03:00
dprintk ( " ignoring non-MPS device " ) ;
2010-01-26 14:40:09 +03:00
if ( mpoa_device_type = = MPC )
tlvs + = 20 ;
2005-04-17 02:20:36 +04:00
continue ; /* we are only interested in MPSs */
}
2010-01-26 14:40:09 +03:00
if ( number_of_mps_macs = = 0 & &
mpoa_device_type = = MPS_AND_MPC ) {
pr_info ( " (%s) MPS_AND_MPC has zero MACs \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
continue ; /* someone should read the spec */
}
2010-01-26 14:40:20 +03:00
dprintk_cont ( " this MPS has %d MAC addresses \n " ,
number_of_mps_macs ) ;
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
/*
* ok , now we can go and tell our daemon
* the control address of MPS
*/
2005-04-17 02:20:36 +04:00
send_set_mps_ctrl_addr ( tlvs , mpc ) ;
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
tlvs = copy_macs ( mpc , mac_addr , tlvs ,
number_of_mps_macs , mpoa_device_type ) ;
if ( tlvs = = NULL )
return ;
2005-04-17 02:20:36 +04:00
}
if ( end_of_tlvs - tlvs ! = 0 )
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) ignoring %Zd bytes of trailing TLV garbage \n " ,
dev - > name , end_of_tlvs - tlvs ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
* Store at least advertizing router ' s MAC address
* plus the possible MAC address ( es ) to mpc - > mps_macs .
* For a freshly allocated MPOA client mpc - > mps_macs = = 0.
*/
2008-07-31 03:31:46 +04:00
static const uint8_t * copy_macs ( struct mpoa_client * mpc ,
const uint8_t * router_mac ,
const uint8_t * tlvs , uint8_t mps_macs ,
uint8_t device_type )
2005-04-17 02:20:36 +04:00
{
int num_macs ;
num_macs = ( mps_macs > 1 ) ? mps_macs : 1 ;
if ( mpc - > number_of_mps_macs ! = num_macs ) { /* need to reallocate? */
2010-01-26 14:40:09 +03:00
if ( mpc - > number_of_mps_macs ! = 0 )
kfree ( mpc - > mps_macs ) ;
2005-04-17 02:20:36 +04:00
mpc - > number_of_mps_macs = 0 ;
2010-01-26 14:40:09 +03:00
mpc - > mps_macs = kmalloc ( num_macs * ETH_ALEN , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( mpc - > mps_macs = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) out of mem \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
}
memcpy ( mpc - > mps_macs , router_mac , ETH_ALEN ) ;
tlvs + = 20 ; if ( device_type = = MPS_AND_MPC ) tlvs + = 20 ;
if ( mps_macs > 0 )
memcpy ( mpc - > mps_macs , tlvs , mps_macs * ETH_ALEN ) ;
tlvs + = mps_macs * ETH_ALEN ;
mpc - > number_of_mps_macs = num_macs ;
return tlvs ;
}
static int send_via_shortcut ( struct sk_buff * skb , struct mpoa_client * mpc )
{
in_cache_entry * entry ;
struct iphdr * iph ;
char * buff ;
2006-11-15 08:11:29 +03:00
__be32 ipaddr = 0 ;
2005-04-17 02:20:36 +04:00
static struct {
struct llc_snap_hdr hdr ;
2006-11-15 08:11:29 +03:00
__be32 tag ;
2005-04-17 02:20:36 +04:00
} tagged_llc_snap_hdr = {
{ 0xaa , 0xaa , 0x03 , { 0x00 , 0x00 , 0x00 } , { 0x88 , 0x4c } } ,
0
} ;
buff = skb - > data + mpc - > dev - > hard_header_len ;
iph = ( struct iphdr * ) buff ;
ipaddr = iph - > daddr ;
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) ipaddr 0x%x \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , ipaddr ) ;
2005-04-17 02:20:36 +04:00
entry = mpc - > in_ops - > get ( ipaddr , mpc ) ;
if ( entry = = NULL ) {
entry = mpc - > in_ops - > add_entry ( ipaddr , mpc ) ;
2010-01-26 14:40:09 +03:00
if ( entry ! = NULL )
mpc - > in_ops - > put ( entry ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2010-01-26 14:40:09 +03:00
/* threshold not exceeded or VCC not ready */
if ( mpc - > in_ops - > cache_hit ( entry , mpc ) ! = OPEN ) {
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) cache_hit: returns != OPEN \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > put ( entry ) ;
return 1 ;
}
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) using shortcut \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
/* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
if ( iph - > ttl < = 1 ) {
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) IP ttl = %u, using LANE \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , iph - > ttl ) ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > put ( entry ) ;
return 1 ;
}
iph - > ttl - - ;
iph - > check = 0 ;
iph - > check = ip_fast_csum ( ( unsigned char * ) iph , iph - > ihl ) ;
if ( entry - > ctrl_info . tag ! = 0 ) {
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) adding tag 0x%x \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , entry - > ctrl_info . tag ) ;
2005-04-17 02:20:36 +04:00
tagged_llc_snap_hdr . tag = entry - > ctrl_info . tag ;
2010-01-26 14:40:09 +03:00
skb_pull ( skb , ETH_HLEN ) ; /* get rid of Eth header */
skb_push ( skb , sizeof ( tagged_llc_snap_hdr ) ) ;
/* add LLC/SNAP header */
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( skb , & tagged_llc_snap_hdr ,
sizeof ( tagged_llc_snap_hdr ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-01-26 14:40:09 +03:00
skb_pull ( skb , ETH_HLEN ) ; /* get rid of Eth header */
skb_push ( skb , sizeof ( struct llc_snap_hdr ) ) ;
/* add LLC/SNAP header + tag */
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( skb , & llc_snap_mpoa_data ,
sizeof ( struct llc_snap_hdr ) ) ;
2005-04-17 02:20:36 +04:00
}
atomic_add ( skb - > truesize , & sk_atm ( entry - > shortcut ) - > sk_wmem_alloc ) ;
ATM_SKB ( skb ) - > atm_options = entry - > shortcut - > atm_options ;
entry - > shortcut - > send ( entry - > shortcut , skb ) ;
entry - > packets_fwded + + ;
mpc - > in_ops - > put ( entry ) ;
return 0 ;
}
/*
* Probably needs some error checks and locking , not sure . . .
*/
2009-08-31 23:50:42 +04:00
static netdev_tx_t mpc_send_packet ( struct sk_buff * skb ,
struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct mpoa_client * mpc ;
struct ethhdr * eth ;
int i = 0 ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = find_mpc_by_lec ( dev ) ; /* this should NEVER fail */
2010-01-26 14:40:09 +03:00
if ( mpc = = NULL ) {
pr_info ( " (%s) no MPC found \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
goto non_ip ;
}
eth = ( struct ethhdr * ) skb - > data ;
if ( eth - > h_proto ! = htons ( ETH_P_IP ) )
goto non_ip ; /* Multi-Protocol Over ATM :-) */
2008-01-09 14:51:59 +03:00
/* Weed out funny packets (e.g., AF_PACKET or raw). */
if ( skb - > len < ETH_HLEN + sizeof ( struct iphdr ) )
goto non_ip ;
skb_set_network_header ( skb , ETH_HLEN ) ;
if ( skb - > len < ETH_HLEN + ip_hdr ( skb ) - > ihl * 4 | | ip_hdr ( skb ) - > ihl < 5 )
goto non_ip ;
2005-04-17 02:20:36 +04:00
while ( i < mpc - > number_of_mps_macs ) {
2010-01-26 14:40:09 +03:00
if ( ! compare_ether_addr ( eth - > h_dest ,
( mpc - > mps_macs + i * ETH_ALEN ) ) )
if ( send_via_shortcut ( skb , mpc ) = = 0 ) /* try shortcut */
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
i + + ;
}
2010-01-26 14:40:09 +03:00
non_ip :
return mpc - > old_ops - > ndo_start_xmit ( skb , dev ) ;
2005-04-17 02:20:36 +04:00
}
static int atm_mpoa_vcc_attach ( struct atm_vcc * vcc , void __user * arg )
{
int bytes_left ;
struct mpoa_client * mpc ;
struct atmmpc_ioc ioc_data ;
in_cache_entry * in_entry ;
2006-11-15 08:11:29 +03:00
__be32 ipaddr ;
2005-04-17 02:20:36 +04:00
bytes_left = copy_from_user ( & ioc_data , arg , sizeof ( struct atmmpc_ioc ) ) ;
if ( bytes_left ! = 0 ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mpoa:Short read (missed %d bytes) from userland \n " ,
bytes_left ) ;
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
ipaddr = ioc_data . ipaddr ;
if ( ioc_data . dev_num < 0 | | ioc_data . dev_num > = MAX_LEC_ITF )
return - EINVAL ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = find_mpc_by_itfnum ( ioc_data . dev_num ) ;
if ( mpc = = NULL )
return - EINVAL ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
if ( ioc_data . type = = MPC_SOCKET_INGRESS ) {
in_entry = mpc - > in_ops - > get ( ipaddr , mpc ) ;
2010-01-26 14:40:09 +03:00
if ( in_entry = = NULL | |
in_entry - > entry_state < INGRESS_RESOLVED ) {
pr_info ( " (%s) did not find RESOLVED entry from ingress cache \n " ,
2005-04-17 02:20:36 +04:00
mpc - > dev - > name ) ;
2010-01-26 14:40:09 +03:00
if ( in_entry ! = NULL )
mpc - > in_ops - > put ( in_entry ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) attaching ingress SVC, entry = %pI4 \n " ,
mpc - > dev - > name , & in_entry - > ctrl_info . in_dst_ip ) ;
2005-04-17 02:20:36 +04:00
in_entry - > shortcut = vcc ;
mpc - > in_ops - > put ( in_entry ) ;
} else {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) attaching egress SVC \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
}
vcc - > proto_data = mpc - > dev ;
vcc - > push = mpc_push ;
return 0 ;
}
/*
*
*/
static void mpc_vcc_close ( struct atm_vcc * vcc , struct net_device * dev )
{
struct mpoa_client * mpc ;
in_cache_entry * in_entry ;
eg_cache_entry * eg_entry ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = find_mpc_by_lec ( dev ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) close for unknown MPC \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
in_entry = mpc - > in_ops - > get_by_vcc ( vcc , mpc ) ;
if ( in_entry ) {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) ingress SVC closed ip = %pI4 \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , & in_entry - > ctrl_info . in_dst_ip ) ;
2005-04-17 02:20:36 +04:00
in_entry - > shortcut = NULL ;
mpc - > in_ops - > put ( in_entry ) ;
}
eg_entry = mpc - > eg_ops - > get_by_vcc ( vcc , mpc ) ;
if ( eg_entry ) {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) egress SVC closed \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
eg_entry - > shortcut = NULL ;
mpc - > eg_ops - > put ( eg_entry ) ;
}
if ( in_entry = = NULL & & eg_entry = = NULL )
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) unused vcc closed \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
static void mpc_push ( struct atm_vcc * vcc , struct sk_buff * skb )
{
struct net_device * dev = ( struct net_device * ) vcc - > proto_data ;
struct sk_buff * new_skb ;
eg_cache_entry * eg ;
struct mpoa_client * mpc ;
2006-11-15 08:11:29 +03:00
__be32 tag ;
2005-04-17 02:20:36 +04:00
char * tmp ;
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
if ( skb = = NULL ) {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) null skb, closing VCC \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
mpc_vcc_close ( vcc , dev ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
skb - > dev = dev ;
2010-01-26 14:40:09 +03:00
if ( memcmp ( skb - > data , & llc_snap_mpoa_ctrl ,
sizeof ( struct llc_snap_hdr ) ) = = 0 ) {
2005-04-17 02:20:36 +04:00
struct sock * sk = sk_atm ( vcc ) ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) control packet arrived \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
/* Pass control packets to daemon */
skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
sk - > sk_data_ready ( sk , skb - > len ) ;
return ;
}
/* data coming over the shortcut */
atm_return ( vcc , skb - > truesize ) ;
mpc = find_mpc_by_lec ( dev ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) unknown MPC \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:09 +03:00
if ( memcmp ( skb - > data , & llc_snap_mpoa_data_tagged ,
sizeof ( struct llc_snap_hdr ) ) = = 0 ) { /* MPOA tagged data */
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) tagged data packet arrived \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:09 +03:00
} else if ( memcmp ( skb - > data , & llc_snap_mpoa_data ,
sizeof ( struct llc_snap_hdr ) ) = = 0 ) { /* MPOA data */
pr_info ( " (%s) Unsupported non-tagged data packet arrived. Purging \n " ,
dev - > name ) ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb_any ( skb ) ;
return ;
} else {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) garbage arrived, purging \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb_any ( skb ) ;
return ;
}
tmp = skb - > data + sizeof ( struct llc_snap_hdr ) ;
2006-11-15 08:11:29 +03:00
tag = * ( __be32 * ) tmp ;
2005-04-17 02:20:36 +04:00
eg = mpc - > eg_ops - > get_by_tag ( tag , mpc ) ;
if ( eg = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mpoa: (%s) Didn't find egress cache entry, tag = %u \n " ,
dev - > name , tag ) ;
2005-04-17 02:20:36 +04:00
purge_egress_shortcut ( vcc , NULL ) ;
dev_kfree_skb_any ( skb ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
/*
* See if ingress MPC is using shortcut we opened as a return channel .
* This means we have a bi - directional vcc opened by us .
2007-02-09 17:24:29 +03:00
*/
2005-04-17 02:20:36 +04:00
if ( eg - > shortcut = = NULL ) {
eg - > shortcut = vcc ;
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) egress SVC in use \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
}
2010-01-26 14:40:09 +03:00
skb_pull ( skb , sizeof ( struct llc_snap_hdr ) + sizeof ( tag ) ) ;
/* get rid of LLC/SNAP header */
new_skb = skb_realloc_headroom ( skb , eg - > ctrl_info . DH_length ) ;
/* LLC/SNAP is shorter than MAC header :( */
2005-04-17 02:20:36 +04:00
dev_kfree_skb_any ( skb ) ;
2010-01-26 14:40:09 +03:00
if ( new_skb = = NULL ) {
2005-04-17 02:20:36 +04:00
mpc - > eg_ops - > put ( eg ) ;
return ;
}
skb_push ( new_skb , eg - > ctrl_info . DH_length ) ; /* add MAC header */
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( new_skb , eg - > ctrl_info . DLL_header ,
eg - > ctrl_info . DH_length ) ;
2005-04-17 02:20:36 +04:00
new_skb - > protocol = eth_type_trans ( new_skb , dev ) ;
2007-04-11 07:45:18 +04:00
skb_reset_network_header ( new_skb ) ;
2005-04-17 02:20:36 +04:00
2007-04-21 09:47:35 +04:00
eg - > latest_ip_addr = ip_hdr ( new_skb ) - > saddr ;
2005-04-17 02:20:36 +04:00
eg - > packets_rcvd + + ;
mpc - > eg_ops - > put ( eg ) ;
memset ( ATM_SKB ( skb ) , 0 , sizeof ( struct atm_skb_data ) ) ;
netif_rx ( new_skb ) ;
return ;
}
static struct atmdev_ops mpc_ops = { /* only send is required */
. close = mpoad_close ,
. send = msg_from_mpoad
} ;
static struct atm_dev mpc_dev = {
. ops = & mpc_ops ,
. type = " mpc " ,
. number = 42 ,
2007-04-26 12:37:44 +04:00
. lock = __SPIN_LOCK_UNLOCKED ( mpc_dev . lock )
2005-04-17 02:20:36 +04:00
/* members not explicitly initialised will be 0 */
} ;
2010-01-26 14:40:09 +03:00
static int atm_mpoa_mpoad_attach ( struct atm_vcc * vcc , int arg )
2005-04-17 02:20:36 +04:00
{
struct mpoa_client * mpc ;
struct lec_priv * priv ;
int err ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
if ( mpcs = = NULL ) {
init_timer ( & mpc_timer ) ;
mpc_timer_refresh ( ) ;
/* This lets us now how our LECs are doing */
err = register_netdevice_notifier ( & mpoa_notifier ) ;
if ( err < 0 ) {
del_timer ( & mpc_timer ) ;
return err ;
}
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc = find_mpc_by_itfnum ( arg ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:20 +03:00
dprintk ( " allocating new mpc for itf %d \n " , arg ) ;
2005-04-17 02:20:36 +04:00
mpc = alloc_mpc ( ) ;
if ( mpc = = NULL )
return - ENOMEM ;
mpc - > dev_num = arg ;
2010-01-26 14:40:09 +03:00
mpc - > dev = find_lec_by_itfnum ( arg ) ;
/* NULL if there was no lec */
2005-04-17 02:20:36 +04:00
}
if ( mpc - > mpoad_vcc ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mpoad is already present for itf %d \n " , arg ) ;
2005-04-17 02:20:36 +04:00
return - EADDRINUSE ;
}
if ( mpc - > dev ) { /* check if the lec is LANE2 capable */
2008-11-13 10:39:10 +03:00
priv = netdev_priv ( mpc - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( priv - > lane_version < 2 ) {
dev_put ( mpc - > dev ) ;
mpc - > dev = NULL ;
} else
2007-02-09 17:24:29 +03:00
priv - > lane2_ops - > associate_indicator = lane2_assoc_ind ;
2005-04-17 02:20:36 +04:00
}
mpc - > mpoad_vcc = vcc ;
vcc - > dev = & mpc_dev ;
vcc_insert_socket ( sk_atm ( vcc ) ) ;
2010-01-26 14:40:09 +03:00
set_bit ( ATM_VF_META , & vcc - > flags ) ;
set_bit ( ATM_VF_READY , & vcc - > flags ) ;
2005-04-17 02:20:36 +04:00
if ( mpc - > dev ) {
char empty [ ATM_ESA_LEN ] ;
memset ( empty , 0 , ATM_ESA_LEN ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
start_mpc ( mpc , mpc - > dev ) ;
/* set address if mpcd e.g. gets killed and restarted.
* If we do not do it now we have to wait for the next LE_ARP
*/
2010-01-26 14:40:09 +03:00
if ( memcmp ( mpc - > mps_ctrl_addr , empty , ATM_ESA_LEN ) ! = 0 )
2005-04-17 02:20:36 +04:00
send_set_mps_ctrl_addr ( mpc - > mps_ctrl_addr , mpc ) ;
}
__module_get ( THIS_MODULE ) ;
return arg ;
}
2008-07-31 03:31:46 +04:00
static void send_set_mps_ctrl_addr ( const char * addr , struct mpoa_client * mpc )
2005-04-17 02:20:36 +04:00
{
struct k_message mesg ;
2010-01-26 14:40:09 +03:00
memcpy ( mpc - > mps_ctrl_addr , addr , ATM_ESA_LEN ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mesg . type = SET_MPS_CTRL_ADDR ;
memcpy ( mesg . MPS_ctrl , addr , ATM_ESA_LEN ) ;
msg_to_mpoad ( & mesg , mpc ) ;
return ;
}
static void mpoad_close ( struct atm_vcc * vcc )
{
struct mpoa_client * mpc ;
struct sk_buff * skb ;
mpc = find_mpc_by_vcc ( vcc ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " did not find MPC \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( ! mpc - > mpoad_vcc ) {
2010-01-26 14:40:09 +03:00
pr_info ( " close for non-present mpoad \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
mpc - > mpoad_vcc = NULL ;
if ( mpc - > dev ) {
2008-11-13 10:39:10 +03:00
struct lec_priv * priv = netdev_priv ( mpc - > dev ) ;
2005-04-17 02:20:36 +04:00
priv - > lane2_ops - > associate_indicator = NULL ;
stop_mpc ( mpc ) ;
dev_put ( mpc - > dev ) ;
}
mpc - > in_ops - > destroy_cache ( mpc ) ;
mpc - > eg_ops - > destroy_cache ( mpc ) ;
while ( ( skb = skb_dequeue ( & sk_atm ( vcc ) - > sk_receive_queue ) ) ) {
atm_return ( vcc , skb - > truesize ) ;
kfree_skb ( skb ) ;
}
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) going down \n " ,
2005-04-17 02:20:36 +04:00
( mpc - > dev ) ? mpc - > dev - > name : " <unknown> " ) ;
module_put ( THIS_MODULE ) ;
return ;
}
/*
*
*/
static int msg_from_mpoad ( struct atm_vcc * vcc , struct sk_buff * skb )
{
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
struct mpoa_client * mpc = find_mpc_by_vcc ( vcc ) ;
2010-01-26 14:40:09 +03:00
struct k_message * mesg = ( struct k_message * ) skb - > data ;
2005-04-17 02:20:36 +04:00
atomic_sub ( skb - > truesize , & sk_atm ( vcc ) - > sk_wmem_alloc ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " no mpc found \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) " , mpc - > dev ? mpc - > dev - > name : " <unknown> " ) ;
2010-01-26 14:40:09 +03:00
switch ( mesg - > type ) {
2005-04-17 02:20:36 +04:00
case MPOA_RES_REPLY_RCVD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " mpoa_res_reply_rcvd \n " ) ;
2005-04-17 02:20:36 +04:00
MPOA_res_reply_rcvd ( mesg , mpc ) ;
break ;
case MPOA_TRIGGER_RCVD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " mpoa_trigger_rcvd \n " ) ;
2005-04-17 02:20:36 +04:00
MPOA_trigger_rcvd ( mesg , mpc ) ;
break ;
case INGRESS_PURGE_RCVD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " nhrp_purge_rcvd \n " ) ;
2005-04-17 02:20:36 +04:00
ingress_purge_rcvd ( mesg , mpc ) ;
break ;
case EGRESS_PURGE_RCVD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " egress_purge_reply_rcvd \n " ) ;
2005-04-17 02:20:36 +04:00
egress_purge_rcvd ( mesg , mpc ) ;
break ;
case MPS_DEATH :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " mps_death \n " ) ;
2005-04-17 02:20:36 +04:00
mps_death ( mesg , mpc ) ;
break ;
case CACHE_IMPOS_RCVD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " cache_impos_rcvd \n " ) ;
2005-04-17 02:20:36 +04:00
MPOA_cache_impos_rcvd ( mesg , mpc ) ;
break ;
case SET_MPC_CTRL_ADDR :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " set_mpc_ctrl_addr \n " ) ;
2005-04-17 02:20:36 +04:00
set_mpc_ctrl_addr_rcvd ( mesg , mpc ) ;
break ;
case SET_MPS_MAC_ADDR :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " set_mps_mac_addr \n " ) ;
2005-04-17 02:20:36 +04:00
set_mps_mac_addr_rcvd ( mesg , mpc ) ;
break ;
case CLEAN_UP_AND_EXIT :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " clean_up_and_exit \n " ) ;
2005-04-17 02:20:36 +04:00
clean_up ( mesg , mpc , DIE ) ;
break ;
case RELOAD :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " reload \n " ) ;
2005-04-17 02:20:36 +04:00
clean_up ( mesg , mpc , RELOAD ) ;
break ;
case SET_MPC_PARAMS :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " set_mpc_params \n " ) ;
2005-04-17 02:20:36 +04:00
mpc - > parameters = mesg - > content . params ;
break ;
default :
2010-01-26 14:40:20 +03:00
dprintk_cont ( " unknown message %d \n " , mesg - > type ) ;
2005-04-17 02:20:36 +04:00
break ;
}
kfree_skb ( skb ) ;
return 0 ;
}
/* Remember that this function may not do things that sleep */
int msg_to_mpoad ( struct k_message * mesg , struct mpoa_client * mpc )
{
struct sk_buff * skb ;
struct sock * sk ;
if ( mpc = = NULL | | ! mpc - > mpoad_vcc ) {
2010-01-26 14:40:09 +03:00
pr_info ( " mesg %d to a non-existent mpoad \n " , mesg - > type ) ;
2005-04-17 02:20:36 +04:00
return - ENXIO ;
}
skb = alloc_skb ( sizeof ( struct k_message ) , GFP_ATOMIC ) ;
if ( skb = = NULL )
return - ENOMEM ;
skb_put ( skb , sizeof ( struct k_message ) ) ;
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data ( skb , mesg , sizeof ( * mesg ) ) ;
2005-04-17 02:20:36 +04:00
atm_force_charge ( mpc - > mpoad_vcc , skb - > truesize ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
sk = sk_atm ( mpc - > mpoad_vcc ) ;
skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
sk - > sk_data_ready ( sk , skb - > len ) ;
return 0 ;
}
2010-01-26 14:40:09 +03:00
static int mpoa_event_listener ( struct notifier_block * mpoa_notifier ,
unsigned long event , void * dev_ptr )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
struct mpoa_client * mpc ;
struct lec_priv * priv ;
dev = ( struct net_device * ) dev_ptr ;
2007-09-12 15:02:17 +04:00
2008-07-20 09:34:43 +04:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) )
2007-09-12 15:02:17 +04:00
return NOTIFY_DONE ;
2005-04-17 02:20:36 +04:00
if ( dev - > name = = NULL | | strncmp ( dev - > name , " lec " , 3 ) )
return NOTIFY_DONE ; /* we are only interested in lec:s */
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
switch ( event ) {
case NETDEV_REGISTER : /* a new lec device was allocated */
2008-11-13 10:39:10 +03:00
priv = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( priv - > lane_version < 2 )
break ;
priv - > lane2_ops - > associate_indicator = lane2_assoc_ind ;
mpc = find_mpc_by_itfnum ( priv - > itfnum ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:20 +03:00
dprintk ( " allocating new mpc for %s \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
mpc = alloc_mpc ( ) ;
if ( mpc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " no new mpc " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
mpc - > dev_num = priv - > itfnum ;
mpc - > dev = dev ;
dev_hold ( dev ) ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) was initialized \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
break ;
case NETDEV_UNREGISTER :
/* the lec device was deallocated */
mpc = find_mpc_by_lec ( dev ) ;
if ( mpc = = NULL )
break ;
2010-01-26 14:40:20 +03:00
dprintk ( " device (%s) was deallocated \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
stop_mpc ( mpc ) ;
dev_put ( mpc - > dev ) ;
mpc - > dev = NULL ;
break ;
case NETDEV_UP :
/* the dev was ifconfig'ed up */
mpc = find_mpc_by_lec ( dev ) ;
if ( mpc = = NULL )
break ;
2010-01-26 14:40:09 +03:00
if ( mpc - > mpoad_vcc ! = NULL )
2005-04-17 02:20:36 +04:00
start_mpc ( mpc , dev ) ;
break ;
case NETDEV_DOWN :
/* the dev was ifconfig'ed down */
/* this means that the flow of packets from the
* upper layer stops
*/
mpc = find_mpc_by_lec ( dev ) ;
if ( mpc = = NULL )
break ;
2010-01-26 14:40:09 +03:00
if ( mpc - > mpoad_vcc ! = NULL )
2005-04-17 02:20:36 +04:00
stop_mpc ( mpc ) ;
break ;
case NETDEV_REBOOT :
case NETDEV_CHANGE :
case NETDEV_CHANGEMTU :
case NETDEV_CHANGEADDR :
case NETDEV_GOING_DOWN :
break ;
default :
break ;
}
return NOTIFY_DONE ;
}
/*
* Functions which are called after a message is received from mpcd .
* Msg is reused on purpose .
*/
static void MPOA_trigger_rcvd ( struct k_message * msg , struct mpoa_client * mpc )
{
2006-11-15 08:11:29 +03:00
__be32 dst_ip = msg - > content . in_info . in_dst_ip ;
2005-04-17 02:20:36 +04:00
in_cache_entry * entry ;
entry = mpc - > in_ops - > get ( dst_ip , mpc ) ;
2010-01-26 14:40:09 +03:00
if ( entry = = NULL ) {
2005-04-17 02:20:36 +04:00
entry = mpc - > in_ops - > add_entry ( dst_ip , mpc ) ;
entry - > entry_state = INGRESS_RESOLVING ;
msg - > type = SND_MPOA_RES_RQST ;
msg - > content . in_info = entry - > ctrl_info ;
msg_to_mpoad ( msg , mpc ) ;
do_gettimeofday ( & ( entry - > reply_wait ) ) ;
mpc - > in_ops - > put ( entry ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
if ( entry - > entry_state = = INGRESS_INVALID ) {
2005-04-17 02:20:36 +04:00
entry - > entry_state = INGRESS_RESOLVING ;
msg - > type = SND_MPOA_RES_RQST ;
msg - > content . in_info = entry - > ctrl_info ;
msg_to_mpoad ( msg , mpc ) ;
do_gettimeofday ( & ( entry - > reply_wait ) ) ;
mpc - > in_ops - > put ( entry ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) entry already in resolving state \n " ,
2005-04-17 02:20:36 +04:00
( mpc - > dev ) ? mpc - > dev - > name : " <unknown> " ) ;
mpc - > in_ops - > put ( entry ) ;
return ;
}
/*
* Things get complicated because we have to check if there ' s an egress
2007-02-09 17:24:29 +03:00
* shortcut with suitable traffic parameters we could use .
2005-04-17 02:20:36 +04:00
*/
2010-01-26 14:40:09 +03:00
static void check_qos_and_open_shortcut ( struct k_message * msg ,
struct mpoa_client * client ,
in_cache_entry * entry )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:11:29 +03:00
__be32 dst_ip = msg - > content . in_info . in_dst_ip ;
2005-04-17 02:20:36 +04:00
struct atm_mpoa_qos * qos = atm_mpoa_search_qos ( dst_ip ) ;
eg_cache_entry * eg_entry = client - > eg_ops - > get_by_src_ip ( dst_ip , client ) ;
2010-01-26 14:40:09 +03:00
if ( eg_entry & & eg_entry - > shortcut ) {
if ( eg_entry - > shortcut - > qos . txtp . traffic_class &
msg - > qos . txtp . traffic_class &
( qos ? qos - > qos . txtp . traffic_class : ATM_UBR | ATM_CBR ) ) {
if ( eg_entry - > shortcut - > qos . txtp . traffic_class = = ATM_UBR )
entry - > shortcut = eg_entry - > shortcut ;
else if ( eg_entry - > shortcut - > qos . txtp . max_pcr > 0 )
entry - > shortcut = eg_entry - > shortcut ;
2005-04-17 02:20:36 +04:00
}
2010-01-26 14:40:09 +03:00
if ( entry - > shortcut ) {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) using egress SVC to reach %pI4 \n " ,
2008-10-31 10:54:56 +03:00
client - > dev - > name , & dst_ip ) ;
2005-04-17 02:20:36 +04:00
client - > eg_ops - > put ( eg_entry ) ;
return ;
}
}
if ( eg_entry ! = NULL )
client - > eg_ops - > put ( eg_entry ) ;
/* No luck in the egress cache we must open an ingress SVC */
msg - > type = OPEN_INGRESS_SVC ;
2010-01-26 14:40:09 +03:00
if ( qos & &
( qos - > qos . txtp . traffic_class = = msg - > qos . txtp . traffic_class ) ) {
2005-04-17 02:20:36 +04:00
msg - > qos = qos - > qos ;
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) trying to get a CBR shortcut \n " ,
client - > dev - > name ) ;
} else
memset ( & msg - > qos , 0 , sizeof ( struct atm_qos ) ) ;
2005-04-17 02:20:36 +04:00
msg_to_mpoad ( msg , client ) ;
return ;
}
static void MPOA_res_reply_rcvd ( struct k_message * msg , struct mpoa_client * mpc )
{
2006-11-15 08:11:29 +03:00
__be32 dst_ip = msg - > content . in_info . in_dst_ip ;
2005-04-17 02:20:36 +04:00
in_cache_entry * entry = mpc - > in_ops - > get ( dst_ip , mpc ) ;
2006-06-26 11:01:58 +04:00
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) ip %pI4 \n " ,
2008-10-31 10:54:56 +03:00
mpc - > dev - > name , & dst_ip ) ;
2010-01-26 14:40:20 +03:00
ddprintk ( " (%s) entry = %p " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , entry ) ;
if ( entry = = NULL ) {
pr_info ( " (%s) ARGH, received res. reply for an entry that doesn't exist. \n " ,
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:20 +03:00
ddprintk_cont ( " entry_state = %d " , entry - > entry_state ) ;
2005-04-17 02:20:36 +04:00
if ( entry - > entry_state = = INGRESS_RESOLVED ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) RESOLVED entry! \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > put ( entry ) ;
return ;
}
entry - > ctrl_info = msg - > content . in_info ;
do_gettimeofday ( & ( entry - > tv ) ) ;
do_gettimeofday ( & ( entry - > reply_wait ) ) ; /* Used in refreshing func from now on */
entry - > refresh_time = 0 ;
2010-01-26 14:40:20 +03:00
ddprintk_cont ( " entry->shortcut = %p \n " , entry - > shortcut ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:09 +03:00
if ( entry - > entry_state = = INGRESS_RESOLVING & &
entry - > shortcut ! = NULL ) {
2007-02-09 17:24:29 +03:00
entry - > entry_state = INGRESS_RESOLVED ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > put ( entry ) ;
return ; /* Shortcut already open... */
}
if ( entry - > shortcut ! = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) entry->shortcut != NULL, impossible! \n " ,
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > put ( entry ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
check_qos_and_open_shortcut ( msg , mpc , entry ) ;
entry - > entry_state = INGRESS_RESOLVED ;
mpc - > in_ops - > put ( entry ) ;
return ;
}
static void ingress_purge_rcvd ( struct k_message * msg , struct mpoa_client * mpc )
{
2006-11-15 08:11:29 +03:00
__be32 dst_ip = msg - > content . in_info . in_dst_ip ;
__be32 mask = msg - > ip_mask ;
2005-04-17 02:20:36 +04:00
in_cache_entry * entry = mpc - > in_ops - > get_with_mask ( dst_ip , mpc , mask ) ;
2010-01-26 14:40:09 +03:00
if ( entry = = NULL ) {
pr_info ( " (%s) purge for a non-existing entry, ip = %pI4 \n " ,
mpc - > dev - > name , & dst_ip ) ;
2005-04-17 02:20:36 +04:00
return ;
}
do {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) removing an ingress entry, ip = %pI4 \n " ,
2008-10-31 10:54:56 +03:00
mpc - > dev - > name , & dst_ip ) ;
2005-04-17 02:20:36 +04:00
write_lock_bh ( & mpc - > ingress_lock ) ;
mpc - > in_ops - > remove_entry ( entry , mpc ) ;
write_unlock_bh ( & mpc - > ingress_lock ) ;
mpc - > in_ops - > put ( entry ) ;
entry = mpc - > in_ops - > get_with_mask ( dst_ip , mpc , mask ) ;
} while ( entry ! = NULL ) ;
return ;
2007-02-09 17:24:29 +03:00
}
2005-04-17 02:20:36 +04:00
static void egress_purge_rcvd ( struct k_message * msg , struct mpoa_client * mpc )
{
2006-11-15 08:11:29 +03:00
__be32 cache_id = msg - > content . eg_info . cache_id ;
2005-04-17 02:20:36 +04:00
eg_cache_entry * entry = mpc - > eg_ops - > get_by_cache_id ( cache_id , mpc ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
if ( entry = = NULL ) {
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) purge for a non-existing entry \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
write_lock_irq ( & mpc - > egress_lock ) ;
mpc - > eg_ops - > remove_entry ( entry , mpc ) ;
write_unlock_irq ( & mpc - > egress_lock ) ;
mpc - > eg_ops - > put ( entry ) ;
return ;
2007-02-09 17:24:29 +03:00
}
2005-04-17 02:20:36 +04:00
static void purge_egress_shortcut ( struct atm_vcc * vcc , eg_cache_entry * entry )
{
struct sock * sk ;
struct k_message * purge_msg ;
struct sk_buff * skb ;
2010-01-26 14:40:20 +03:00
dprintk ( " entering \n " ) ;
2005-04-17 02:20:36 +04:00
if ( vcc = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " vcc == NULL \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
skb = alloc_skb ( sizeof ( struct k_message ) , GFP_ATOMIC ) ;
if ( skb = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " out of memory \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
skb_put ( skb , sizeof ( struct k_message ) ) ;
memset ( skb - > data , 0 , sizeof ( struct k_message ) ) ;
purge_msg = ( struct k_message * ) skb - > data ;
purge_msg - > type = DATA_PLANE_PURGE ;
if ( entry ! = NULL )
purge_msg - > content . eg_info = entry - > ctrl_info ;
atm_force_charge ( vcc , skb - > truesize ) ;
sk = sk_atm ( vcc ) ;
skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
sk - > sk_data_ready ( sk , skb - > len ) ;
2010-01-26 14:40:20 +03:00
dprintk ( " exiting \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
* Our MPS died . Tell our daemon to send NHRP data plane purge to each
* of the egress shortcuts we have .
*/
2010-01-26 14:40:09 +03:00
static void mps_death ( struct k_message * msg , struct mpoa_client * mpc )
2005-04-17 02:20:36 +04:00
{
eg_cache_entry * entry ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:09 +03:00
if ( memcmp ( msg - > MPS_ctrl , mpc - > mps_ctrl_addr , ATM_ESA_LEN ) ) {
pr_info ( " (%s) wrong MPS \n " , mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* FIXME: This knows too much of the cache structure */
read_lock_irq ( & mpc - > egress_lock ) ;
entry = mpc - > eg_cache ;
while ( entry ! = NULL ) {
purge_egress_shortcut ( entry - > shortcut , entry ) ;
entry = entry - > next ;
}
read_unlock_irq ( & mpc - > egress_lock ) ;
mpc - > in_ops - > destroy_cache ( mpc ) ;
mpc - > eg_ops - > destroy_cache ( mpc ) ;
return ;
}
2010-01-26 14:40:09 +03:00
static void MPOA_cache_impos_rcvd ( struct k_message * msg ,
struct mpoa_client * mpc )
2005-04-17 02:20:36 +04:00
{
uint16_t holding_time ;
eg_cache_entry * entry = mpc - > eg_ops - > get_by_cache_id ( msg - > content . eg_info . cache_id , mpc ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
holding_time = msg - > content . eg_info . holding_time ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) entry = %p, holding_time = %u \n " ,
2010-01-26 14:40:09 +03:00
mpc - > dev - > name , entry , holding_time ) ;
if ( entry = = NULL & & holding_time ) {
2005-04-17 02:20:36 +04:00
entry = mpc - > eg_ops - > add_entry ( msg , mpc ) ;
mpc - > eg_ops - > put ( entry ) ;
return ;
}
2010-01-26 14:40:09 +03:00
if ( holding_time ) {
2005-04-17 02:20:36 +04:00
mpc - > eg_ops - > update ( entry , holding_time ) ;
return ;
}
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
write_lock_irq ( & mpc - > egress_lock ) ;
mpc - > eg_ops - > remove_entry ( entry , mpc ) ;
write_unlock_irq ( & mpc - > egress_lock ) ;
mpc - > eg_ops - > put ( entry ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:09 +03:00
static void set_mpc_ctrl_addr_rcvd ( struct k_message * mesg ,
struct mpoa_client * mpc )
2005-04-17 02:20:36 +04:00
{
struct lec_priv * priv ;
int i , retval ;
uint8_t tlv [ 4 + 1 + 1 + 1 + ATM_ESA_LEN ] ;
tlv [ 0 ] = 00 ; tlv [ 1 ] = 0xa0 ; tlv [ 2 ] = 0x3e ; tlv [ 3 ] = 0x2a ; /* type */
tlv [ 4 ] = 1 + 1 + ATM_ESA_LEN ; /* length */
tlv [ 5 ] = 0x02 ; /* MPOA client */
tlv [ 6 ] = 0x00 ; /* number of MPS MAC addresses */
memcpy ( & tlv [ 7 ] , mesg - > MPS_ctrl , ATM_ESA_LEN ) ; /* MPC ctrl ATM addr */
memcpy ( mpc - > our_ctrl_addr , mesg - > MPS_ctrl , ATM_ESA_LEN ) ;
2010-01-26 14:40:20 +03:00
dprintk ( " (%s) setting MPC ctrl ATM address to " ,
mpc - > dev ? mpc - > dev - > name : " <unknown> " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 7 ; i < sizeof ( tlv ) ; i + + )
2010-01-26 14:40:20 +03:00
dprintk_cont ( " %02x " , tlv [ i ] ) ;
dprintk_cont ( " \n " ) ;
2005-04-17 02:20:36 +04:00
if ( mpc - > dev ) {
2008-11-13 10:39:10 +03:00
priv = netdev_priv ( mpc - > dev ) ;
2010-01-26 14:40:09 +03:00
retval = priv - > lane2_ops - > associate_req ( mpc - > dev ,
mpc - > dev - > dev_addr ,
tlv , sizeof ( tlv ) ) ;
2005-04-17 02:20:36 +04:00
if ( retval = = 0 )
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) MPOA device type TLV association failed \n " ,
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
retval = priv - > lane2_ops - > resolve ( mpc - > dev , NULL , 1 , NULL , NULL ) ;
if ( retval < 0 )
2010-01-26 14:40:09 +03:00
pr_info ( " (%s) targetless LE_ARP request failed \n " ,
mpc - > dev - > name ) ;
2005-04-17 02:20:36 +04:00
}
return ;
}
2010-01-26 14:40:09 +03:00
static void set_mps_mac_addr_rcvd ( struct k_message * msg ,
struct mpoa_client * client )
2005-04-17 02:20:36 +04:00
{
2010-01-26 14:40:09 +03:00
if ( client - > number_of_mps_macs )
2005-04-17 02:20:36 +04:00
kfree ( client - > mps_macs ) ;
client - > number_of_mps_macs = 0 ;
2006-11-21 06:14:33 +03:00
client - > mps_macs = kmemdup ( msg - > MPS_ctrl , ETH_ALEN , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( client - > mps_macs = = NULL ) {
2010-01-26 14:40:09 +03:00
pr_info ( " out of memory \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
client - > number_of_mps_macs = 1 ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return ;
}
/*
* purge egress cache and tell daemon to ' action ' ( DIE , RELOAD )
*/
static void clean_up ( struct k_message * msg , struct mpoa_client * mpc , int action )
{
eg_cache_entry * entry ;
msg - > type = SND_EGRESS_PURGE ;
/* FIXME: This knows too much of the cache structure */
read_lock_irq ( & mpc - > egress_lock ) ;
entry = mpc - > eg_cache ;
2010-01-26 14:40:09 +03:00
while ( entry ! = NULL ) {
msg - > content . eg_info = entry - > ctrl_info ;
2010-01-26 14:40:20 +03:00
dprintk ( " cache_id %u \n " , entry - > ctrl_info . cache_id ) ;
2010-01-26 14:40:09 +03:00
msg_to_mpoad ( msg , mpc ) ;
entry = entry - > next ;
2005-04-17 02:20:36 +04:00
}
read_unlock_irq ( & mpc - > egress_lock ) ;
msg - > type = action ;
msg_to_mpoad ( msg , mpc ) ;
return ;
}
static void mpc_timer_refresh ( void )
{
mpc_timer . expires = jiffies + ( MPC_P2 * HZ ) ;
mpc_timer . data = mpc_timer . expires ;
mpc_timer . function = mpc_cache_check ;
add_timer ( & mpc_timer ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:09 +03:00
static void mpc_cache_check ( unsigned long checking_time )
2005-04-17 02:20:36 +04:00
{
struct mpoa_client * mpc = mpcs ;
static unsigned long previous_resolving_check_time ;
static unsigned long previous_refresh_time ;
2007-02-09 17:24:29 +03:00
2010-01-26 14:40:09 +03:00
while ( mpc ! = NULL ) {
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > clear_count ( mpc ) ;
mpc - > eg_ops - > clear_expired ( mpc ) ;
2010-01-26 14:40:09 +03:00
if ( checking_time - previous_resolving_check_time >
mpc - > parameters . mpc_p4 * HZ ) {
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > check_resolving ( mpc ) ;
previous_resolving_check_time = checking_time ;
}
2010-01-26 14:40:09 +03:00
if ( checking_time - previous_refresh_time >
mpc - > parameters . mpc_p5 * HZ ) {
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > refresh ( mpc ) ;
previous_refresh_time = checking_time ;
}
mpc = mpc - > next ;
}
mpc_timer_refresh ( ) ;
2007-02-09 17:24:29 +03:00
2005-04-17 02:20:36 +04:00
return ;
}
2010-01-26 14:40:09 +03:00
static int atm_mpoa_ioctl ( struct socket * sock , unsigned int cmd ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
int err = 0 ;
struct atm_vcc * vcc = ATM_SD ( sock ) ;
if ( cmd ! = ATMMPC_CTRL & & cmd ! = ATMMPC_DATA )
return - ENOIOCTLCMD ;
if ( ! capable ( CAP_NET_ADMIN ) )
return - EPERM ;
switch ( cmd ) {
2010-01-26 14:40:09 +03:00
case ATMMPC_CTRL :
err = atm_mpoa_mpoad_attach ( vcc , ( int ) arg ) ;
if ( err > = 0 )
sock - > state = SS_CONNECTED ;
break ;
case ATMMPC_DATA :
err = atm_mpoa_vcc_attach ( vcc , ( void __user * ) arg ) ;
break ;
default :
break ;
2005-04-17 02:20:36 +04:00
}
return err ;
}
static struct atm_ioctl atm_ioctl_ops = {
. owner = THIS_MODULE ,
. ioctl = atm_mpoa_ioctl ,
} ;
static __init int atm_mpoa_init ( void )
{
register_atm_ioctl ( & atm_ioctl_ops ) ;
if ( mpc_proc_init ( ) ! = 0 )
2010-01-26 14:40:00 +03:00
pr_info ( " failed to initialize /proc/mpoa \n " ) ;
2005-04-17 02:20:36 +04:00
2010-01-26 14:40:09 +03:00
pr_info ( " mpc.c: " __DATE__ " " __TIME__ " initialized \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit atm_mpoa_cleanup ( void )
{
struct mpoa_client * mpc , * tmp ;
struct atm_mpoa_qos * qos , * nextqos ;
struct lec_priv * priv ;
mpc_proc_clean ( ) ;
del_timer ( & mpc_timer ) ;
unregister_netdevice_notifier ( & mpoa_notifier ) ;
deregister_atm_ioctl ( & atm_ioctl_ops ) ;
mpc = mpcs ;
mpcs = NULL ;
while ( mpc ! = NULL ) {
tmp = mpc - > next ;
if ( mpc - > dev ! = NULL ) {
stop_mpc ( mpc ) ;
2008-11-13 10:39:10 +03:00
priv = netdev_priv ( mpc - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( priv - > lane2_ops ! = NULL )
priv - > lane2_ops - > associate_indicator = NULL ;
}
2010-01-26 14:40:20 +03:00
ddprintk ( " about to clear caches \n " ) ;
2005-04-17 02:20:36 +04:00
mpc - > in_ops - > destroy_cache ( mpc ) ;
mpc - > eg_ops - > destroy_cache ( mpc ) ;
2010-01-26 14:40:20 +03:00
ddprintk ( " caches cleared \n " ) ;
2005-04-17 02:20:36 +04:00
kfree ( mpc - > mps_macs ) ;
memset ( mpc , 0 , sizeof ( struct mpoa_client ) ) ;
2010-01-26 14:40:20 +03:00
ddprintk ( " about to kfree %p \n " , mpc ) ;
2005-04-17 02:20:36 +04:00
kfree ( mpc ) ;
2010-01-26 14:40:20 +03:00
ddprintk ( " next mpc is at %p \n " , tmp ) ;
2005-04-17 02:20:36 +04:00
mpc = tmp ;
}
qos = qos_head ;
qos_head = NULL ;
while ( qos ! = NULL ) {
nextqos = qos - > next ;
2010-01-26 14:40:20 +03:00
dprintk ( " freeing qos entry %p \n " , qos ) ;
2005-04-17 02:20:36 +04:00
kfree ( qos ) ;
qos = nextqos ;
}
return ;
}
module_init ( atm_mpoa_init ) ;
module_exit ( atm_mpoa_cleanup ) ;
MODULE_LICENSE ( " GPL " ) ;