2005-04-17 02:20:36 +04:00
/*********************************************************************
2007-02-09 17:24:53 +03:00
*
2005-04-17 02:20:36 +04:00
* Filename : irlan_eth . c
2007-02-09 17:24:53 +03:00
* Version :
* Description :
2005-04-17 02:20:36 +04:00
* Status : Experimental .
* Author : Dag Brattli < dagb @ cs . uit . no >
* Created at : Thu Oct 15 08 : 37 : 58 1998
* Modified at : Tue Mar 21 09 : 06 : 41 2000
* Modified by : Dag Brattli < dagb @ cs . uit . no >
* Sources : skeleton . c by Donald Becker < becker @ CESDIS . gsfc . nasa . gov >
* slip . c by Laurence Culhane , < loz @ holmes . demon . co . uk >
* Fred N . van Kempen , < waltje @ uwalt . nl . mugnet . org >
2007-02-09 17:24:53 +03:00
*
2005-04-17 02:20:36 +04:00
* Copyright ( c ) 1998 - 2000 Dag Brattli , All Rights Reserved .
2007-02-09 17:24:53 +03:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
2005-04-17 02:20:36 +04:00
* the License , or ( at your option ) any later version .
2007-02-09 17:24:53 +03:00
*
2007-10-20 01:21:04 +04:00
* Neither Dag Brattli nor University of Tromsø admit liability nor
2007-02-09 17:24:53 +03:00
* provide warranty for any of this software . This material is
2005-04-17 02:20:36 +04:00
* provided " AS-IS " and at no charge .
2007-02-09 17:24:53 +03:00
*
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/inetdevice.h>
# include <linux/if_arp.h>
# include <linux/module.h>
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <net/arp.h>
# include <net/irda/irda.h>
# include <net/irda/irmod.h>
# include <net/irda/irlan_common.h>
# include <net/irda/irlan_client.h>
# include <net/irda/irlan_event.h>
# include <net/irda/irlan_eth.h>
static int irlan_eth_open ( struct net_device * dev ) ;
static int irlan_eth_close ( struct net_device * dev ) ;
2009-08-31 23:50:50 +04:00
static netdev_tx_t irlan_eth_xmit ( struct sk_buff * skb ,
struct net_device * dev ) ;
2013-07-13 18:03:55 +04:00
static void irlan_eth_set_multicast_list ( struct net_device * dev ) ;
2005-04-17 02:20:36 +04:00
2009-03-20 22:35:34 +03:00
static const struct net_device_ops irlan_eth_netdev_ops = {
2013-07-13 18:03:55 +04:00
. ndo_open = irlan_eth_open ,
. ndo_stop = irlan_eth_close ,
. ndo_start_xmit = irlan_eth_xmit ,
2011-08-16 10:29:01 +04:00
. ndo_set_rx_mode = irlan_eth_set_multicast_list ,
2009-03-20 22:35:34 +03:00
. ndo_validate_addr = eth_validate_addr ,
} ;
2005-04-17 02:20:36 +04:00
/*
* Function irlan_eth_setup ( dev )
*
* The network device initialization function .
*
*/
static void irlan_eth_setup ( struct net_device * dev )
{
2009-03-20 22:35:34 +03:00
ether_setup ( dev ) ;
dev - > netdev_ops = & irlan_eth_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > destructor = free_netdev ;
2016-10-21 06:25:27 +03:00
dev - > min_mtu = 0 ;
dev - > max_mtu = ETH_MAX_MTU ;
2007-02-09 17:24:53 +03:00
/*
2005-04-17 02:20:36 +04:00
* Lets do all queueing in IrTTP instead of this device driver .
* Queueing here as well can introduce some strange latency
* problems , which we will avoid by setting the queue size to 0.
*/
/*
* The bugs in IrTTP and IrLAN that created this latency issue
* have now been fixed , and we can propagate flow control properly
* to the network layer . However , this requires a minimal queue of
* packets for the device .
* Without flow control , the Tx Queue is 14 ( ttp ) + 0 ( dev ) = 14
* With flow control , the Tx Queue is 7 ( ttp ) + 4 ( dev ) = 11
* See irlan_eth_flow_indication ( ) . . .
* Note : this number was randomly selected and would need to
* be adjusted .
* Jean II */
dev - > tx_queue_len = 4 ;
}
/*
* Function alloc_irlandev
*
* Allocate network device and control block
*
*/
struct net_device * alloc_irlandev ( const char * name )
{
net: set name_assign_type in alloc_netdev()
Extend alloc_netdev{,_mq{,s}}() to take name_assign_type as argument, and convert
all users to pass NET_NAME_UNKNOWN.
Coccinelle patch:
@@
expression sizeof_priv, name, setup, txqs, rxqs, count;
@@
(
-alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs)
+alloc_netdev_mqs(sizeof_priv, name, NET_NAME_UNKNOWN, setup, txqs, rxqs)
|
-alloc_netdev_mq(sizeof_priv, name, setup, count)
+alloc_netdev_mq(sizeof_priv, name, NET_NAME_UNKNOWN, setup, count)
|
-alloc_netdev(sizeof_priv, name, setup)
+alloc_netdev(sizeof_priv, name, NET_NAME_UNKNOWN, setup)
)
v9: move comments here from the wrong commit
Signed-off-by: Tom Gundersen <teg@jklm.no>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-07-14 18:37:24 +04:00
return alloc_netdev ( sizeof ( struct irlan_cb ) , name , NET_NAME_UNKNOWN ,
2005-04-17 02:20:36 +04:00
irlan_eth_setup ) ;
}
/*
* Function irlan_eth_open ( dev )
*
* Network device has been opened by user
*
*/
static int irlan_eth_open ( struct net_device * dev )
{
struct irlan_cb * self = netdev_priv ( dev ) ;
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
/* Ready to play! */
2007-02-09 17:24:53 +03:00
netif_stop_queue ( dev ) ; /* Wait until data link is ready */
2005-04-17 02:20:36 +04:00
/* We are now open, so time to do some work */
self - > disconnect_reason = 0 ;
irlan_client_wakeup ( self , self - > saddr , self - > daddr ) ;
2007-02-09 17:24:53 +03:00
/* Make sure we have a hardware address before we return,
2005-04-17 02:20:36 +04:00
so DHCP clients gets happy */
return wait_event_interruptible ( self - > open_wait ,
! self - > tsap_data - > connected ) ;
}
/*
* Function irlan_eth_close ( dev )
*
* Stop the ether network device , his function will usually be called by
2007-02-09 17:24:53 +03:00
* ifconfig down . We should now disconnect the link , We start the
2005-04-17 02:20:36 +04:00
* close timer , so that the instance will be removed if we are unable
* to discover the remote device after the disconnect .
*/
static int irlan_eth_close ( struct net_device * dev )
{
struct irlan_cb * self = netdev_priv ( dev ) ;
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
/* Stop device */
netif_stop_queue ( dev ) ;
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
irlan_close_data_channel ( self ) ;
irlan_close_tsaps ( self ) ;
irlan_do_client_event ( self , IRLAN_LMP_DISCONNECT , NULL ) ;
2007-02-09 17:24:53 +03:00
irlan_do_provider_event ( self , IRLAN_LMP_DISCONNECT , NULL ) ;
2005-04-17 02:20:36 +04:00
/* Remove frames queued on the control channel */
skb_queue_purge ( & self - > client . txq ) ;
self - > client . tx_busy = 0 ;
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Function irlan_eth_tx ( skb )
*
* Transmits ethernet frames over IrDA link .
*
*/
2009-08-31 23:50:50 +04:00
static netdev_tx_t irlan_eth_xmit ( struct sk_buff * skb ,
struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct irlan_cb * self = netdev_priv ( dev ) ;
int ret ;
2010-08-18 04:24:43 +04:00
unsigned int len ;
2005-04-17 02:20:36 +04:00
/* skb headroom large enough to contain all IrDA-headers? */
if ( ( skb_headroom ( skb ) < self - > max_header_size ) | | ( skb_shared ( skb ) ) ) {
2007-02-09 17:24:53 +03:00
struct sk_buff * new_skb =
2005-04-17 02:20:36 +04:00
skb_realloc_headroom ( skb , self - > max_header_size ) ;
/* We have to free the original skb anyway */
dev_kfree_skb ( skb ) ;
/* Did the realloc succeed? */
if ( new_skb = = NULL )
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
/* Use the new skb instead */
skb = new_skb ;
2007-02-09 17:24:53 +03:00
}
2005-04-17 02:20:36 +04:00
2016-05-03 17:33:13 +03:00
netif_trans_update ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-08-18 04:24:43 +04:00
len = skb - > len ;
2005-04-17 02:20:36 +04:00
/* Now queue the packet in the transport layer */
if ( self - > use_udata )
ret = irttp_udata_request ( self - > tsap_data , skb ) ;
else
ret = irttp_data_request ( self - > tsap_data , skb ) ;
if ( ret < 0 ) {
2007-02-09 17:24:53 +03:00
/*
2005-04-17 02:20:36 +04:00
* IrTTPs tx queue is full , so we just have to
* drop the frame ! You might think that we should
* just return - 1 and don ' t deallocate the frame ,
* but that is dangerous since it ' s possible that
* we have replaced the original skb with a new
* one with larger headroom , and that would really
* confuse do_dev_queue_xmit ( ) in dev . c ! I have
2007-02-09 17:24:53 +03:00
* tried : - ) DB
2005-04-17 02:20:36 +04:00
*/
/* irttp_data_request already free the packet */
2010-08-20 03:51:33 +04:00
dev - > stats . tx_dropped + + ;
2005-04-17 02:20:36 +04:00
} else {
2010-08-20 03:51:33 +04:00
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = len ;
2005-04-17 02:20:36 +04:00
}
2007-02-09 17:24:53 +03:00
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
/*
* Function irlan_eth_receive ( handle , skb )
*
* This function gets the data that is received on the data channel
*
*/
int irlan_eth_receive ( void * instance , void * sap , struct sk_buff * skb )
{
struct irlan_cb * self = instance ;
2010-08-20 03:51:33 +04:00
struct net_device * dev = self - > dev ;
2005-04-17 02:20:36 +04:00
if ( skb = = NULL ) {
2010-08-20 03:51:33 +04:00
dev - > stats . rx_dropped + + ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
if ( skb - > len < ETH_HLEN ) {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s() : IrLAN frame too short (%d) \n " ,
__func__ , skb - > len ) ;
2010-08-20 03:51:33 +04:00
dev - > stats . rx_dropped + + ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb ( skb ) ;
return 0 ;
}
2007-02-09 17:24:53 +03:00
/*
* Adopt this frame ! Important to set all these fields since they
2005-04-17 02:20:36 +04:00
* might have been previously set by the low level IrDA network
2007-02-09 17:24:53 +03:00
* device driver
2005-04-17 02:20:36 +04:00
*/
2010-08-20 03:51:33 +04:00
skb - > protocol = eth_type_trans ( skb , dev ) ; /* Remove eth header */
2007-02-09 17:24:53 +03:00
2010-08-20 03:51:33 +04:00
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = skb - > len ;
2005-04-17 02:20:36 +04:00
netif_rx ( skb ) ; /* Eat it! */
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Function irlan_eth_flow ( status )
*
2007-02-09 17:24:53 +03:00
* Do flow control between IP / Ethernet and IrLAN / IrTTP . This is done by
2005-04-17 02:20:36 +04:00
* controlling the queue stop / start .
*
* The IrDA link layer has the advantage to have flow control , and
* IrTTP now properly handles that . Flow controlling the higher layers
* prevent us to drop Tx packets in here ( up to 15 % for a TCP socket ,
* more for UDP socket ) .
* Also , this allow us to reduce the overall transmit queue , which means
* less latency in case of mixed traffic .
* Jean II
*/
void irlan_eth_flow_indication ( void * instance , void * sap , LOCAL_FLOW flow )
{
struct irlan_cb * self ;
struct net_device * dev ;
2011-06-13 20:21:26 +04:00
self = instance ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = IRLAN_MAGIC , return ; ) ;
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
dev = self - > dev ;
IRDA_ASSERT ( dev ! = NULL , return ; ) ;
2007-02-09 17:24:53 +03:00
2014-11-12 01:44:57 +03:00
pr_debug ( " %s() : flow %s ; running %d \n " , __func__ ,
flow = = FLOW_STOP ? " FLOW_STOP " : " FLOW_START " ,
netif_running ( dev ) ) ;
2005-04-17 02:20:36 +04:00
switch ( flow ) {
case FLOW_STOP :
/* IrTTP is full, stop higher layers */
netif_stop_queue ( dev ) ;
break ;
case FLOW_START :
default :
/* Tell upper layers that its time to transmit frames again */
/* Schedule network layer */
netif_wake_queue ( dev ) ;
break ;
}
}
/*
* Function set_multicast_list ( dev )
*
* Configure the filtering of the device
*
*/
# define HW_MAX_ADDRS 4 /* Must query to get it! */
2007-02-09 17:24:53 +03:00
static void irlan_eth_set_multicast_list ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2007-02-09 17:24:53 +03:00
struct irlan_cb * self = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
/* Check if data channel has been connected yet */
if ( self - > client . state ! = IRLAN_DATA ) {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), delaying! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( dev - > flags & IFF_PROMISC ) {
/* Enable promiscuous mode */
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " Promiscuous mode not implemented by IrLAN! \n " ) ;
2013-07-13 18:03:55 +04:00
} else if ( ( dev - > flags & IFF_ALLMULTI ) | |
2010-02-08 07:30:35 +03:00
netdev_mc_count ( dev ) > HW_MAX_ADDRS ) {
2005-04-17 02:20:36 +04:00
/* Disable promiscuous mode, use normal mode. */
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), Setting multicast filter \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* hardware_set_filter(NULL); */
irlan_set_multicast_filter ( self , TRUE ) ;
2013-07-13 18:03:55 +04:00
} else if ( ! netdev_mc_empty ( dev ) ) {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), Setting multicast filter \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Walk the address list, and load the filter */
/* hardware_set_filter(dev->mc_list); */
irlan_set_multicast_filter ( self , TRUE ) ;
2013-07-13 18:03:55 +04:00
} else {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), Clearing multicast filter \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
irlan_set_multicast_filter ( self , FALSE ) ;
}
if ( dev - > flags & IFF_BROADCAST )
irlan_set_broadcast_filter ( self , TRUE ) ;
else
irlan_set_broadcast_filter ( self , FALSE ) ;
}