2005-04-17 02:20:36 +04:00
/*
* X .25 Packet Layer release 002
*
2007-02-09 17:25:27 +03:00
* This is ALPHA test software . This code may break your machine , randomly fail to work with new
* releases , misbehave and / or generally screw up . It might even work .
2005-04-17 02:20:36 +04:00
*
* This code REQUIRES 2.1 .15 or higher
*
* This module :
* This module 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 .
*
* History
* X .25 001 Jonathan Naylor Started coding .
* 2000 - 09 - 04 Henner Eisen Prevent freeing a dangling skb .
*/
# include <linux/kernel.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <net/sock.h>
# include <linux/if_arp.h>
# include <net/x25.h>
static int x25_receive_data ( struct sk_buff * skb , struct x25_neigh * nb )
{
struct sock * sk ;
unsigned short frametype ;
unsigned int lci ;
frametype = skb - > data [ 2 ] ;
2007-02-09 17:25:27 +03:00
lci = ( ( skb - > data [ 0 ] < < 8 ) & 0xF00 ) + ( ( skb - > data [ 1 ] < < 0 ) & 0x0FF ) ;
2005-04-17 02:20:36 +04:00
/*
* LCI of zero is always for us , and its always a link control
* frame .
*/
if ( lci = = 0 ) {
x25_link_control ( skb , nb , frametype ) ;
return 0 ;
}
/*
* Find an existing socket .
*/
if ( ( sk = x25_find_socket ( lci , nb ) ) ! = NULL ) {
int queued = 1 ;
2007-03-13 19:06:52 +03:00
skb_reset_transport_header ( skb ) ;
2005-04-17 02:20:36 +04:00
bh_lock_sock ( sk ) ;
if ( ! sock_owned_by_user ( sk ) ) {
queued = x25_process_rx_frame ( sk , skb ) ;
} else {
sk_add_backlog ( sk , skb ) ;
}
bh_unlock_sock ( sk ) ;
2007-01-16 06:29:31 +03:00
sock_put ( sk ) ;
2005-04-17 02:20:36 +04:00
return queued ;
}
/*
* Is is a Call Request ? if so process it .
*/
if ( frametype = = X25_CALL_REQUEST )
return x25_rx_call_request ( skb , nb , lci ) ;
/*
2007-02-09 00:34:02 +03:00
* Its not a Call Request , nor is it a control frame .
* Can we forward it ?
2005-04-17 02:20:36 +04:00
*/
2007-02-09 00:34:02 +03:00
if ( x25_forward_data ( lci , nb , skb ) ) {
if ( frametype = = X25_CLEAR_CONFIRMATION ) {
x25_clear_forward_by_lci ( lci ) ;
}
kfree_skb ( skb ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
/*
x25_transmit_clear_request ( nb , lci , 0x0D ) ;
*/
if ( frametype ! = X25_CLEAR_CONFIRMATION )
printk ( KERN_DEBUG " x25_receive_data(): unknown frame type %2x \n " , frametype ) ;
return 0 ;
}
int x25_lapb_receive_frame ( struct sk_buff * skb , struct net_device * dev ,
2005-08-10 06:34:12 +04:00
struct packet_type * ptype , struct net_device * orig_dev )
2005-04-17 02:20:36 +04:00
{
struct sk_buff * nskb ;
struct x25_neigh * nb ;
2008-03-25 15:47:49 +03:00
if ( dev_net ( dev ) ! = & init_net )
2007-09-17 22:53:39 +04:00
goto drop ;
2005-04-17 02:20:36 +04:00
nskb = skb_copy ( skb , GFP_ATOMIC ) ;
if ( ! nskb )
goto drop ;
kfree_skb ( skb ) ;
skb = nskb ;
/*
* Packet received from unrecognised device , throw it away .
*/
nb = x25_get_neigh ( dev ) ;
if ( ! nb ) {
printk ( KERN_DEBUG " X.25: unknown neighbour - %s \n " , dev - > name ) ;
goto drop ;
}
switch ( skb - > data [ 0 ] ) {
case 0x00 :
skb_pull ( skb , 1 ) ;
if ( x25_receive_data ( skb , nb ) ) {
x25_neigh_put ( nb ) ;
goto out ;
}
break ;
case 0x01 :
x25_link_established ( nb ) ;
break ;
case 0x02 :
x25_link_terminated ( nb ) ;
break ;
}
x25_neigh_put ( nb ) ;
drop :
kfree_skb ( skb ) ;
out :
return 0 ;
}
void x25_establish_link ( struct x25_neigh * nb )
{
struct sk_buff * skb ;
unsigned char * ptr ;
switch ( nb - > dev - > type ) {
case ARPHRD_X25 :
if ( ( skb = alloc_skb ( 1 , GFP_ATOMIC ) ) = = NULL ) {
printk ( KERN_ERR " x25_dev: out of memory \n " ) ;
return ;
}
ptr = skb_put ( skb , 1 ) ;
* ptr = 0x01 ;
break ;
# if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
case ARPHRD_ETHER :
return ;
# endif
default :
return ;
}
skb - > protocol = htons ( ETH_P_X25 ) ;
skb - > dev = nb - > dev ;
dev_queue_xmit ( skb ) ;
}
void x25_terminate_link ( struct x25_neigh * nb )
{
struct sk_buff * skb ;
unsigned char * ptr ;
# if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
if ( nb - > dev - > type = = ARPHRD_ETHER )
return ;
# endif
if ( nb - > dev - > type ! = ARPHRD_X25 )
return ;
skb = alloc_skb ( 1 , GFP_ATOMIC ) ;
if ( ! skb ) {
printk ( KERN_ERR " x25_dev: out of memory \n " ) ;
return ;
}
ptr = skb_put ( skb , 1 ) ;
* ptr = 0x02 ;
skb - > protocol = htons ( ETH_P_X25 ) ;
skb - > dev = nb - > dev ;
dev_queue_xmit ( skb ) ;
}
void x25_send_frame ( struct sk_buff * skb , struct x25_neigh * nb )
{
unsigned char * dptr ;
2007-04-11 07:45:18 +04:00
skb_reset_network_header ( skb ) ;
2005-04-17 02:20:36 +04:00
switch ( nb - > dev - > type ) {
case ARPHRD_X25 :
dptr = skb_push ( skb , 1 ) ;
* dptr = 0x00 ;
break ;
# if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
case ARPHRD_ETHER :
kfree_skb ( skb ) ;
return ;
# endif
default :
kfree_skb ( skb ) ;
return ;
}
skb - > protocol = htons ( ETH_P_X25 ) ;
skb - > dev = nb - > dev ;
dev_queue_xmit ( skb ) ;
}