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 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> /* For the statistics structure. */
# include <asm/system.h>
# include <asm/uaccess.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/netrom.h>
/*
* Only allow IP over NET / ROM frames through if the netrom device is up .
*/
int nr_rx_ip ( struct sk_buff * skb , struct net_device * dev )
{
2009-01-09 16:01:03 +03:00
struct net_device_stats * stats = & dev - > stats ;
2005-04-17 02:20:36 +04:00
if ( ! netif_running ( dev ) ) {
2005-09-13 01:23:06 +04:00
stats - > rx_dropped + + ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
stats - > rx_packets + + ;
stats - > rx_bytes + = skb - > len ;
skb - > protocol = htons ( ETH_P_IP ) ;
/* Spoof incoming device */
skb - > dev = dev ;
2007-12-20 11:25:54 +03:00
skb - > mac_header = skb - > network_header ;
2007-04-11 07:45:18 +04:00
skb_reset_network_header ( skb ) ;
2005-04-17 02:20:36 +04:00
skb - > pkt_type = PACKET_HOST ;
2005-08-24 22:35:51 +04:00
netif_rx ( skb ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2005-08-24 22:35:51 +04:00
# ifdef CONFIG_INET
2005-04-17 02:20:36 +04:00
static int nr_rebuild_header ( struct sk_buff * skb )
{
unsigned char * bp = skb - > data ;
2005-09-13 01:21:48 +04:00
if ( arp_find ( bp + 7 , skb ) )
2005-04-17 02:20:36 +04:00
return 1 ;
bp [ 6 ] & = ~ AX25_CBIT ;
bp [ 6 ] & = ~ AX25_EBIT ;
bp [ 6 ] | = AX25_SSSID_SPARE ;
bp + = AX25_ADDR_LEN ;
bp [ 6 ] & = ~ AX25_CBIT ;
bp [ 6 ] | = AX25_EBIT ;
bp [ 6 ] | = AX25_SSSID_SPARE ;
2005-09-13 01:21:48 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
# else
static int nr_rebuild_header ( struct sk_buff * skb )
{
return 1 ;
}
# endif
2007-10-09 12:40:57 +04:00
static int nr_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 , NR_NETWORK_LEN + NR_TRANSPORT_LEN ) ;
memcpy ( buff , ( saddr ! = NULL ) ? saddr : dev - > dev_addr , dev - > addr_len ) ;
buff [ 6 ] & = ~ AX25_CBIT ;
buff [ 6 ] & = ~ AX25_EBIT ;
buff [ 6 ] | = AX25_SSSID_SPARE ;
buff + = AX25_ADDR_LEN ;
if ( daddr ! = NULL )
memcpy ( buff , daddr , dev - > addr_len ) ;
buff [ 6 ] & = ~ AX25_CBIT ;
buff [ 6 ] | = AX25_EBIT ;
buff [ 6 ] | = AX25_SSSID_SPARE ;
buff + = AX25_ADDR_LEN ;
* buff + + = sysctl_netrom_network_ttl_initialiser ;
* buff + + = NR_PROTO_IP ;
* buff + + = NR_PROTO_IP ;
* buff + + = 0 ;
* buff + + = 0 ;
* buff + + = NR_PROTOEXT ;
if ( daddr ! = NULL )
return 37 ;
return - 37 ;
}
2006-12-15 02:50:34 +03:00
static int __must_check nr_set_mac_address ( struct net_device * dev , void * addr )
2005-04-17 02:20:36 +04:00
{
struct sockaddr * sa = addr ;
2006-12-15 02:50:34 +03:00
int err ;
if ( ! memcmp ( dev - > dev_addr , sa - > sa_data , dev - > addr_len ) )
return 0 ;
if ( dev - > flags & IFF_UP ) {
err = ax25_listen_register ( ( ax25_address * ) sa - > sa_data , NULL ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
ax25_listen_release ( ( ax25_address * ) dev - > dev_addr , NULL ) ;
2006-12-15 02:50:34 +03:00
}
2005-04-17 02:20:36 +04:00
memcpy ( dev - > dev_addr , sa - > sa_data , dev - > addr_len ) ;
return 0 ;
}
static int nr_open ( struct net_device * dev )
{
2006-12-15 02:50:34 +03:00
int err ;
err = ax25_listen_register ( ( ax25_address * ) dev - > dev_addr , NULL ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
netif_start_queue ( dev ) ;
2006-12-15 02:50:34 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int nr_close ( struct net_device * dev )
{
ax25_listen_release ( ( ax25_address * ) dev - > dev_addr , NULL ) ;
netif_stop_queue ( dev ) ;
return 0 ;
}
static int nr_xmit ( struct sk_buff * skb , struct net_device * dev )
{
2009-01-09 16:01:03 +03:00
struct net_device_stats * stats = & dev - > stats ;
2005-09-13 01:28:03 +04:00
unsigned int len = skb - > len ;
2005-09-13 01:21:48 +04:00
if ( ! nr_route_frame ( skb , NULL ) ) {
kfree_skb ( skb ) ;
stats - > tx_errors + + ;
return 0 ;
}
stats - > tx_packets + + ;
stats - > tx_bytes + = len ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-10-09 12:40:57 +04:00
static const struct header_ops nr_header_ops = {
. create = nr_header ,
. rebuild = nr_rebuild_header ,
} ;
2005-04-17 02:20:36 +04:00
void nr_setup ( struct net_device * dev )
{
dev - > mtu = NR_MAX_PACKET_SIZE ;
dev - > hard_start_xmit = nr_xmit ;
dev - > open = nr_open ;
dev - > stop = nr_close ;
2007-10-09 12:40:57 +04:00
dev - > header_ops = & nr_header_ops ;
2005-04-17 02:20:36 +04:00
dev - > hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN ;
dev - > addr_len = AX25_ADDR_LEN ;
dev - > type = ARPHRD_NETROM ;
dev - > set_mac_address = nr_set_mac_address ;
/* New-style flags. */
2005-09-13 01:26:26 +04:00
dev - > flags = IFF_NOARP ;
2005-04-17 02:20:36 +04:00
}