2019-05-28 20:10:09 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-17 02:20:36 +04:00
/*
* Generic HDLC support routines for Linux
*
2008-02-02 00:37:12 +03:00
* Copyright ( C ) 1999 - 2008 Krzysztof Halasa < khc @ pm . waw . pl >
2005-04-17 02:20:36 +04:00
*
* Currently supported :
* * raw IP - in - HDLC
* * Cisco HDLC
* * Frame Relay with ANSI or CCITT LMI ( both user and network side )
* * PPP
* * X .25
*
* Use sethdlc utility to set line parameters , protocol and PVCs
*
* How does it work :
2006-09-27 01:23:45 +04:00
* - proto - > open ( ) , close ( ) , start ( ) , stop ( ) calls are serialized .
2005-04-17 02:20:36 +04:00
* The order is : open , [ start , stop . . . ] close . . .
2006-09-27 01:23:45 +04:00
* - proto - > start ( ) and stop ( ) are called with spin_lock_irq held .
2005-04-17 02:20:36 +04:00
*/
2011-06-26 23:01:28 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
2008-06-30 21:06:40 +04:00
# include <linux/hdlc.h>
2005-04-17 02:20:36 +04:00
# include <linux/if_arp.h>
2008-06-30 21:06:40 +04:00
# include <linux/inetdevice.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
2008-06-30 21:06:40 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/notifier.h>
2005-04-17 02:20:36 +04:00
# include <linux/pkt_sched.h>
2008-06-30 21:06:40 +04:00
# include <linux/poll.h>
2005-04-17 02:20:36 +04:00
# include <linux/rtnetlink.h>
2008-06-30 21:06:40 +04:00
# include <linux/skbuff.h>
# include <linux/slab.h>
2007-09-17 22:53:39 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
2021-06-01 16:23:18 +03:00
static const char * version = " HDLC support module revision 1.22 " ;
2005-04-17 02:20:36 +04:00
# undef DEBUG_LINK
2008-05-19 21:00:51 +04:00
static struct hdlc_proto * first_proto ;
2005-04-17 02:20:36 +04:00
static int hdlc_rcv ( struct sk_buff * skb , struct net_device * dev ,
2005-08-10 06:34:12 +04:00
struct packet_type * p , struct net_device * orig_dev )
2005-04-17 02:20:36 +04:00
{
2020-10-20 04:31:52 +03:00
struct hdlc_device * hdlc ;
/* First make sure "dev" is an HDLC device */
if ( ! ( dev - > priv_flags & IFF_WAN_HDLC ) ) {
kfree_skb ( skb ) ;
return NET_RX_SUCCESS ;
}
hdlc = dev_to_hdlc ( dev ) ;
2007-09-17 22:53:39 +04:00
2009-11-26 02:14:13 +03:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) ) {
2007-09-17 22:53:39 +04:00
kfree_skb ( skb ) ;
return 0 ;
}
2008-02-02 00:37:12 +03:00
BUG_ON ( ! hdlc - > proto - > netif_rx ) ;
return hdlc - > proto - > netif_rx ( skb ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-31 23:50:47 +04:00
netdev_tx_t hdlc_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2009-01-09 00:52:11 +03:00
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
2005-04-17 02:20:36 +04:00
2009-01-09 00:52:11 +03:00
if ( hdlc - > proto - > xmit )
return hdlc - > proto - > xmit ( skb , dev ) ;
return hdlc - > xmit ( skb , dev ) ; /* call hardware driver directly */
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( hdlc_start_xmit ) ;
2005-04-17 02:20:36 +04:00
2006-07-13 00:46:12 +04:00
static inline void hdlc_proto_start ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
2021-06-01 16:23:17 +03:00
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto - > start )
2008-02-02 00:37:12 +03:00
hdlc - > proto - > start ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-13 00:46:12 +04:00
static inline void hdlc_proto_stop ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
2021-06-01 16:23:17 +03:00
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto - > stop )
2008-02-02 00:37:12 +03:00
hdlc - > proto - > stop ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-13 00:46:12 +04:00
static int hdlc_device_event ( struct notifier_block * this , unsigned long event ,
void * ptr )
2005-04-17 02:20:36 +04:00
{
2013-05-28 05:30:21 +04:00
struct net_device * dev = netdev_notifier_info_to_dev ( ptr ) ;
2006-07-13 00:46:12 +04:00
hdlc_device * hdlc ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2006-07-13 00:46:12 +04:00
int on ;
2009-01-08 21:55:57 +03:00
2009-11-26 02:14:13 +03:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) )
2007-09-12 15:02:17 +04:00
return NOTIFY_DONE ;
2009-01-08 21:46:54 +03:00
if ( ! ( dev - > priv_flags & IFF_WAN_HDLC ) )
2006-07-13 00:46:12 +04:00
return NOTIFY_DONE ; /* not an HDLC device */
2008-06-30 21:06:40 +04:00
2006-07-13 00:46:12 +04:00
if ( event ! = NETDEV_CHANGE )
2010-09-20 18:30:54 +04:00
return NOTIFY_DONE ; /* Only interested in carrier changes */
2006-07-13 00:46:12 +04:00
on = netif_carrier_ok ( dev ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG_LINK
2006-07-13 00:46:12 +04:00
printk ( KERN_DEBUG " %s: hdlc_device_event NETDEV_CHANGE, carrier %i \n " ,
dev - > name , on ) ;
2005-04-17 02:20:36 +04:00
# endif
2006-07-13 00:46:12 +04:00
hdlc = dev_to_hdlc ( dev ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & hdlc - > state_lock , flags ) ;
if ( hdlc - > carrier = = on )
goto carrier_exit ; /* no change in DCD line level */
hdlc - > carrier = on ;
if ( ! hdlc - > open )
goto carrier_exit ;
2005-04-21 17:57:25 +04:00
if ( hdlc - > carrier ) {
2011-06-26 23:01:28 +04:00
netdev_info ( dev , " Carrier detected \n " ) ;
2006-07-13 00:46:12 +04:00
hdlc_proto_start ( dev ) ;
2005-04-21 17:57:25 +04:00
} else {
2011-06-26 23:01:28 +04:00
netdev_info ( dev , " Carrier lost \n " ) ;
2006-07-13 00:46:12 +04:00
hdlc_proto_stop ( dev ) ;
2005-04-21 17:57:25 +04:00
}
2005-04-17 02:20:36 +04:00
carrier_exit :
spin_unlock_irqrestore ( & hdlc - > state_lock , flags ) ;
2006-07-13 00:46:12 +04:00
return NOTIFY_DONE ;
2005-04-17 02:20:36 +04:00
}
/* Must be called by hardware driver when HDLC device is being opened */
int hdlc_open ( struct net_device * dev )
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
# ifdef DEBUG_LINK
2006-09-27 01:23:45 +04:00
printk ( KERN_DEBUG " %s: hdlc_open() carrier %i open %i \n " , dev - > name ,
2005-04-17 02:20:36 +04:00
hdlc - > carrier , hdlc - > open ) ;
# endif
2021-06-01 16:23:20 +03:00
if ( ! hdlc - > proto )
2005-04-17 02:20:36 +04:00
return - ENOSYS ; /* no protocol attached */
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto - > open ) {
int result = hdlc - > proto - > open ( dev ) ;
2021-06-01 16:23:17 +03:00
2005-04-17 02:20:36 +04:00
if ( result )
return result ;
}
spin_lock_irq ( & hdlc - > state_lock ) ;
2005-04-21 17:57:25 +04:00
if ( hdlc - > carrier ) {
2011-06-26 23:01:28 +04:00
netdev_info ( dev , " Carrier detected \n " ) ;
2006-07-13 00:46:12 +04:00
hdlc_proto_start ( dev ) ;
2021-06-01 16:23:22 +03:00
} else {
2011-06-26 23:01:28 +04:00
netdev_info ( dev , " No carrier \n " ) ;
2021-06-01 16:23:22 +03:00
}
2005-04-17 02:20:36 +04:00
hdlc - > open = 1 ;
spin_unlock_irq ( & hdlc - > state_lock ) ;
return 0 ;
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( hdlc_open ) ;
2005-04-17 02:20:36 +04:00
/* Must be called by hardware driver when HDLC device is being closed */
void hdlc_close ( struct net_device * dev )
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
# ifdef DEBUG_LINK
2006-09-27 01:23:45 +04:00
printk ( KERN_DEBUG " %s: hdlc_close() carrier %i open %i \n " , dev - > name ,
2005-04-17 02:20:36 +04:00
hdlc - > carrier , hdlc - > open ) ;
# endif
spin_lock_irq ( & hdlc - > state_lock ) ;
hdlc - > open = 0 ;
if ( hdlc - > carrier )
2006-07-13 00:46:12 +04:00
hdlc_proto_stop ( dev ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & hdlc - > state_lock ) ;
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto - > close )
hdlc - > proto - > close ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( hdlc_close ) ;
2005-04-17 02:20:36 +04:00
int hdlc_ioctl ( struct net_device * dev , struct ifreq * ifr , int cmd )
{
2006-09-27 01:23:45 +04:00
struct hdlc_proto * proto = first_proto ;
int result ;
2005-04-17 02:20:36 +04:00
if ( cmd ! = SIOCWANDEV )
return - EINVAL ;
2006-09-27 01:23:45 +04:00
if ( dev_to_hdlc ( dev ) - > proto ) {
result = dev_to_hdlc ( dev ) - > proto - > ioctl ( dev , ifr ) ;
if ( result ! = - EINVAL )
return result ;
2005-04-17 02:20:36 +04:00
}
2006-09-27 01:23:45 +04:00
/* Not handled by currently attached protocol (if any) */
while ( proto ) {
2021-06-01 16:23:21 +03:00
result = proto - > ioctl ( dev , ifr ) ;
if ( result ! = - EINVAL )
2006-09-27 01:23:45 +04:00
return result ;
proto = proto - > next ;
2005-04-17 02:20:36 +04:00
}
2006-09-27 01:23:45 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( hdlc_ioctl ) ;
2005-04-17 02:20:36 +04:00
2007-10-09 12:40:57 +04:00
static const struct header_ops hdlc_null_ops ;
2007-03-03 02:52:22 +03:00
static void hdlc_setup_dev ( struct net_device * dev )
{
/* Re-init all variables changed by HDLC protocol drivers,
* including ether_setup ( ) called from hdlc_raw_eth . c .
*/
dev - > flags = IFF_POINTOPOINT | IFF_NOARP ;
2009-01-08 21:46:54 +03:00
dev - > priv_flags = IFF_WAN_HDLC ;
2007-03-03 02:52:22 +03:00
dev - > mtu = HDLC_MAX_MTU ;
2016-10-20 20:55:19 +03:00
dev - > min_mtu = 68 ;
dev - > max_mtu = HDLC_MAX_MTU ;
2007-03-03 02:52:22 +03:00
dev - > type = ARPHRD_RAWHDLC ;
drivers/net/wan/hdlc: Change the default of hard_header_len to 0
Change the default value of hard_header_len in hdlc.c from 16 to 0.
Currently there are 6 HDLC protocol drivers, among them:
hdlc_raw_eth, hdlc_cisco, hdlc_ppp, hdlc_x25 set hard_header_len when
attaching the protocol, overriding the default. So this patch does not
affect them.
hdlc_raw and hdlc_fr don't set hard_header_len when attaching the
protocol. So this patch will change the hard_header_len of the HDLC
device for them from 16 to 0.
This is the correct change because both hdlc_raw and hdlc_fr don't have
header_ops, and the code in net/packet/af_packet.c expects the value of
hard_header_len to be consistent with header_ops.
In net/packet/af_packet.c, in the packet_snd function,
for AF_PACKET/DGRAM sockets it would reserve a headroom of
hard_header_len and call dev_hard_header to fill in that headroom,
and for AF_PACKET/RAW sockets, it does not reserve the headroom and
does not call dev_hard_header, but checks if the user has provided a
header of length hard_header_len (in function dev_validate_header).
Cc: Krzysztof Halasa <khc@pm.waw.pl>
Cc: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: Xie He <xie.he.0141@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-02 15:07:06 +03:00
dev - > hard_header_len = 0 ;
2020-08-13 21:17:04 +03:00
dev - > needed_headroom = 0 ;
2007-03-03 02:52:22 +03:00
dev - > addr_len = 0 ;
2007-10-09 12:40:57 +04:00
dev - > header_ops = & hdlc_null_ops ;
2007-03-03 02:52:22 +03:00
}
2007-01-11 16:48:59 +03:00
static void hdlc_setup ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
2007-03-03 02:52:22 +03:00
hdlc_setup_dev ( dev ) ;
2005-04-17 02:20:36 +04:00
hdlc - > carrier = 1 ;
hdlc - > open = 0 ;
spin_lock_init ( & hdlc - > state_lock ) ;
}
struct net_device * alloc_hdlcdev ( void * priv )
{
struct net_device * dev ;
2021-06-01 16:23:17 +03:00
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
dev = alloc_netdev ( sizeof ( struct hdlc_device ) , " hdlc%d " ,
NET_NAME_UNKNOWN , hdlc_setup ) ;
2005-04-17 02:20:36 +04:00
if ( dev )
dev_to_hdlc ( dev ) - > priv = priv ;
return dev ;
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( alloc_hdlcdev ) ;
2005-04-17 02:20:36 +04:00
void unregister_hdlc_device ( struct net_device * dev )
{
rtnl_lock ( ) ;
2006-09-27 01:23:45 +04:00
detach_hdlc_protocol ( dev ) ;
2015-12-03 23:12:30 +03:00
unregister_netdevice ( dev ) ;
2005-04-17 02:20:36 +04:00
rtnl_unlock ( ) ;
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( unregister_hdlc_device ) ;
2005-04-17 02:20:36 +04:00
2006-09-27 01:23:45 +04:00
int attach_hdlc_protocol ( struct net_device * dev , struct hdlc_proto * proto ,
2008-02-02 00:37:12 +03:00
size_t size )
2006-09-27 01:23:45 +04:00
{
2015-12-03 23:12:31 +03:00
int err ;
err = detach_hdlc_protocol ( dev ) ;
if ( err )
return err ;
2006-09-27 01:23:45 +04:00
if ( ! try_module_get ( proto - > module ) )
return - ENOSYS ;
2013-02-03 21:28:12 +04:00
if ( size ) {
dev_to_hdlc ( dev ) - > state = kmalloc ( size , GFP_KERNEL ) ;
2021-06-01 16:23:20 +03:00
if ( ! dev_to_hdlc ( dev ) - > state ) {
2006-09-27 01:23:45 +04:00
module_put ( proto - > module ) ;
return - ENOBUFS ;
}
2013-02-03 21:28:12 +04:00
}
2006-09-27 01:23:45 +04:00
dev_to_hdlc ( dev ) - > proto = proto ;
2015-12-03 23:12:31 +03:00
2006-09-27 01:23:45 +04:00
return 0 ;
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( attach_hdlc_protocol ) ;
2006-09-27 01:23:45 +04:00
2015-12-03 23:12:31 +03:00
int detach_hdlc_protocol ( struct net_device * dev )
2006-09-27 01:23:45 +04:00
{
hdlc_device * hdlc = dev_to_hdlc ( dev ) ;
2015-12-03 23:12:31 +03:00
int err ;
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto ) {
2015-12-03 23:12:31 +03:00
err = call_netdevice_notifiers ( NETDEV_PRE_TYPE_CHANGE , dev ) ;
err = notifier_to_errno ( err ) ;
if ( err ) {
netdev_err ( dev , " Refused to change device type \n " ) ;
return err ;
}
2006-09-27 01:23:45 +04:00
if ( hdlc - > proto - > detach )
hdlc - > proto - > detach ( dev ) ;
module_put ( hdlc - > proto - > module ) ;
hdlc - > proto = NULL ;
}
kfree ( hdlc - > state ) ;
hdlc - > state = NULL ;
2007-03-03 02:52:22 +03:00
hdlc_setup_dev ( dev ) ;
2015-12-03 23:12:31 +03:00
return 0 ;
2006-09-27 01:23:45 +04:00
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( detach_hdlc_protocol ) ;
2006-09-27 01:23:45 +04:00
void register_hdlc_protocol ( struct hdlc_proto * proto )
{
2008-05-19 21:00:51 +04:00
rtnl_lock ( ) ;
2006-09-27 01:23:45 +04:00
proto - > next = first_proto ;
first_proto = proto ;
2008-05-19 21:00:51 +04:00
rtnl_unlock ( ) ;
2006-09-27 01:23:45 +04:00
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( register_hdlc_protocol ) ;
2006-09-27 01:23:45 +04:00
void unregister_hdlc_protocol ( struct hdlc_proto * proto )
{
2008-05-19 21:00:51 +04:00
struct hdlc_proto * * p ;
rtnl_lock ( ) ;
p = & first_proto ;
while ( * p ! = proto ) {
BUG_ON ( ! * p ) ;
2006-09-27 01:23:45 +04:00
p = & ( ( * p ) - > next ) ;
}
2008-05-19 21:00:51 +04:00
* p = proto - > next ;
rtnl_unlock ( ) ;
2006-09-27 01:23:45 +04:00
}
2021-06-01 16:23:19 +03:00
EXPORT_SYMBOL ( unregister_hdlc_protocol ) ;
2006-09-27 01:23:45 +04:00
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Krzysztof Halasa <khc@pm.waw.pl> " ) ;
MODULE_DESCRIPTION ( " HDLC support module " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2009-03-09 11:18:29 +03:00
static struct packet_type hdlc_packet_type __read_mostly = {
2009-02-01 11:45:17 +03:00
. type = cpu_to_be16 ( ETH_P_HDLC ) ,
2005-04-17 02:20:36 +04:00
. func = hdlc_rcv ,
} ;
2006-07-13 00:46:12 +04:00
static struct notifier_block hdlc_notifier = {
2008-06-30 21:06:40 +04:00
. notifier_call = hdlc_device_event ,
2006-07-13 00:46:12 +04:00
} ;
2005-04-17 02:20:36 +04:00
static int __init hdlc_module_init ( void )
{
2006-07-13 00:46:12 +04:00
int result ;
2011-06-26 23:01:28 +04:00
pr_info ( " %s \n " , version ) ;
2021-06-01 16:23:21 +03:00
result = register_netdevice_notifier ( & hdlc_notifier ) ;
if ( result )
2008-06-30 21:06:40 +04:00
return result ;
dev_add_pack ( & hdlc_packet_type ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit hdlc_module_exit ( void )
{
dev_remove_pack ( & hdlc_packet_type ) ;
2006-07-13 00:46:12 +04:00
unregister_netdevice_notifier ( & hdlc_notifier ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( hdlc_module_init ) ;
module_exit ( hdlc_module_exit ) ;