2005-04-17 02:20:36 +04: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 the License , or
* ( at your option ) any later version .
*
* Copyright ( C ) Jonathan Naylor G4KLX ( g4klx @ g4klx . demon . co . uk )
*/
# include <linux/module.h>
# include <linux/proc_fs.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/types.h>
# include <linux/sysctl.h>
# include <linux/string.h>
# include <linux/socket.h>
# include <linux/errno.h>
# include <linux/fcntl.h>
# include <linux/in.h>
# include <linux/if_ether.h>
# include <asm/system.h>
# include <asm/io.h>
# include <linux/inet.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/if_arp.h>
# include <linux/skbuff.h>
# include <net/ip.h>
# include <net/arp.h>
# include <net/ax25.h>
# include <net/rose.h>
2007-10-09 12:40:57 +04:00
static int rose_header ( struct sk_buff * skb , struct net_device * dev ,
unsigned short type ,
const void * daddr , const void * saddr , unsigned len )
2005-04-17 02:20:36 +04:00
{
unsigned char * buff = skb_push ( skb , ROSE_MIN_LEN + 2 ) ;
* buff + + = ROSE_GFI | ROSE_Q_BIT ;
* buff + + = 0x00 ;
* buff + + = ROSE_DATA ;
* buff + + = 0x7F ;
* buff + + = AX25_P_IP ;
if ( daddr ! = NULL )
return 37 ;
return - 37 ;
}
static int rose_rebuild_header ( struct sk_buff * skb )
{
2007-12-05 13:18:15 +03:00
# ifdef CONFIG_INET
2005-04-17 02:20:36 +04:00
struct net_device * dev = skb - > dev ;
2009-01-09 16:01:05 +03:00
struct net_device_stats * stats = & dev - > stats ;
2005-04-17 02:20:36 +04:00
unsigned char * bp = ( unsigned char * ) skb - > data ;
struct sk_buff * skbn ;
2006-07-04 06:29:15 +04:00
unsigned int len ;
2005-04-17 02:20:36 +04:00
if ( arp_find ( bp + 7 , skb ) ) {
return 1 ;
}
if ( ( skbn = skb_clone ( skb , GFP_ATOMIC ) ) = = NULL ) {
kfree_skb ( skb ) ;
return 1 ;
}
if ( skb - > sk ! = NULL )
skb_set_owner_w ( skbn , skb - > sk ) ;
kfree_skb ( skb ) ;
2006-07-04 06:29:15 +04:00
len = skbn - > len ;
2005-04-17 02:20:36 +04:00
if ( ! rose_route_frame ( skbn , NULL ) ) {
kfree_skb ( skbn ) ;
stats - > tx_errors + + ;
return 1 ;
}
stats - > tx_packets + + ;
2006-07-04 06:29:15 +04:00
stats - > tx_bytes + = len ;
2005-04-17 02:20:36 +04:00
# endif
return 1 ;
}
static int rose_set_mac_address ( struct net_device * dev , void * addr )
{
struct sockaddr * sa = addr ;
2006-12-15 02:51:44 +03:00
int err ;
2005-04-17 02:20:36 +04:00
2006-12-15 02:51:44 +03:00
if ( ! memcpy ( dev - > dev_addr , sa - > sa_data , dev - > addr_len ) )
return 0 ;
2005-04-17 02:20:36 +04:00
2006-12-15 02:51:44 +03:00
if ( dev - > flags & IFF_UP ) {
err = rose_add_loopback_node ( ( rose_address * ) dev - > dev_addr ) ;
if ( err )
return err ;
rose_del_loopback_node ( ( rose_address * ) dev - > dev_addr ) ;
}
2005-04-17 02:20:36 +04:00
2006-12-15 02:51:44 +03:00
memcpy ( dev - > dev_addr , sa - > sa_data , dev - > addr_len ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int rose_open ( struct net_device * dev )
{
2006-12-15 02:51:44 +03:00
int err ;
err = rose_add_loopback_node ( ( rose_address * ) dev - > dev_addr ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
netif_start_queue ( dev ) ;
2006-12-15 02:51:44 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int rose_close ( struct net_device * dev )
{
netif_stop_queue ( dev ) ;
rose_del_loopback_node ( ( rose_address * ) dev - > dev_addr ) ;
return 0 ;
}
2009-08-31 23:50:43 +04:00
static netdev_tx_t rose_xmit ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2009-01-09 16:01:05 +03:00
struct net_device_stats * stats = & dev - > stats ;
2005-04-17 02:20:36 +04:00
if ( ! netif_running ( dev ) ) {
printk ( KERN_ERR " ROSE: rose_xmit - called when iface is down \n " ) ;
2009-06-12 10:22:29 +04:00
return NETDEV_TX_BUSY ;
2005-04-17 02:20:36 +04:00
}
dev_kfree_skb ( skb ) ;
stats - > tx_errors + + ;
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
2007-10-09 12:40:57 +04:00
static const struct header_ops rose_header_ops = {
. create = rose_header ,
. rebuild = rose_rebuild_header ,
} ;
2009-01-09 16:01:06 +03:00
static const struct net_device_ops rose_netdev_ops = {
. ndo_open = rose_open ,
. ndo_stop = rose_close ,
. ndo_start_xmit = rose_xmit ,
. ndo_set_mac_address = rose_set_mac_address ,
} ;
2005-04-17 02:20:36 +04:00
void rose_setup ( struct net_device * dev )
{
dev - > mtu = ROSE_MAX_PACKET_SIZE - 2 ;
2009-01-09 16:01:06 +03:00
dev - > netdev_ops = & rose_netdev_ops ;
2005-04-17 02:20:36 +04:00
2007-10-09 12:40:57 +04:00
dev - > header_ops = & rose_header_ops ;
2005-04-17 02:20:36 +04:00
dev - > hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN ;
dev - > addr_len = ROSE_ADDR_LEN ;
dev - > type = ARPHRD_ROSE ;
/* New-style flags. */
2005-09-13 01:26:52 +04:00
dev - > flags = IFF_NOARP ;
2005-04-17 02:20:36 +04:00
}