2013-01-04 06:05:31 +04:00
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
2010-12-13 14:19:28 +03:00
*
* Andreas Langer
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
*/
# include "main.h"
# include "unicast.h"
# include "send.h"
# include "soft-interface.h"
# include "gateway_client.h"
# include "originator.h"
# include "hash.h"
# include "translation-table.h"
# include "routing.h"
# include "hard-interface.h"
2012-05-16 22:23:17 +04:00
static struct sk_buff *
batadv_frag_merge_packet ( struct list_head * head ,
2012-06-06 00:31:31 +04:00
struct batadv_frag_packet_list_entry * tfp ,
2012-05-16 22:23:17 +04:00
struct sk_buff * skb )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:30 +04:00
struct batadv_unicast_frag_packet * up ;
2010-12-13 14:19:28 +03:00
struct sk_buff * tmp_skb ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_packet * unicast_packet ;
2011-05-15 01:14:54 +04:00
int hdr_len = sizeof ( * unicast_packet ) ;
int uni_diff = sizeof ( * up ) - hdr_len ;
2012-07-08 20:33:51 +04:00
uint8_t * packet_pos ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
up = ( struct batadv_unicast_frag_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* set skb to the first part and tmp_skb to the second part */
2012-06-04 00:19:21 +04:00
if ( up - > flags & BATADV_UNI_FRAG_HEAD ) {
2010-12-13 14:19:28 +03:00
tmp_skb = tfp - > skb ;
} else {
tmp_skb = skb ;
skb = tfp - > skb ;
}
2011-02-07 02:26:43 +03:00
if ( skb_linearize ( skb ) < 0 | | skb_linearize ( tmp_skb ) < 0 )
goto err ;
2011-05-15 01:14:54 +04:00
skb_pull ( tmp_skb , sizeof ( * up ) ) ;
2011-02-07 02:26:43 +03:00
if ( pskb_expand_head ( skb , 0 , tmp_skb - > len , GFP_ATOMIC ) < 0 )
goto err ;
2010-12-13 14:19:28 +03:00
/* move free entry to end */
tfp - > skb = NULL ;
tfp - > seqno = 0 ;
list_move_tail ( & tfp - > list , head ) ;
memcpy ( skb_put ( skb , tmp_skb - > len ) , tmp_skb - > data , tmp_skb - > len ) ;
kfree_skb ( tmp_skb ) ;
memmove ( skb - > data + uni_diff , skb - > data , hdr_len ) ;
2012-07-08 20:33:51 +04:00
packet_pos = skb_pull ( skb , uni_diff ) ;
unicast_packet = ( struct batadv_unicast_packet * ) packet_pos ;
2012-06-04 00:19:21 +04:00
unicast_packet - > header . packet_type = BATADV_UNICAST ;
2010-12-13 14:19:28 +03:00
return skb ;
2011-02-07 02:26:43 +03:00
err :
/* free buffered skb, skb will be freed later */
kfree_skb ( tfp - > skb ) ;
return NULL ;
2010-12-13 14:19:28 +03:00
}
2012-05-16 22:23:17 +04:00
static void batadv_frag_create_entry ( struct list_head * head ,
struct sk_buff * skb )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_frag_packet_list_entry * tfp ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_frag_packet * up ;
up = ( struct batadv_unicast_frag_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* free and oldest packets stand at the end */
tfp = list_entry ( ( head ) - > prev , typeof ( * tfp ) , list ) ;
kfree_skb ( tfp - > skb ) ;
tfp - > seqno = ntohs ( up - > seqno ) ;
tfp - > skb = skb ;
list_move ( & tfp - > list , head ) ;
return ;
}
2012-05-16 22:23:17 +04:00
static int batadv_frag_create_buffer ( struct list_head * head )
2010-12-13 14:19:28 +03:00
{
int i ;
2012-06-06 00:31:31 +04:00
struct batadv_frag_packet_list_entry * tfp ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:15 +04:00
for ( i = 0 ; i < BATADV_FRAG_BUFFER_SIZE ; i + + ) {
2011-05-15 01:14:54 +04:00
tfp = kmalloc ( sizeof ( * tfp ) , GFP_ATOMIC ) ;
2010-12-13 14:19:28 +03:00
if ( ! tfp ) {
2012-05-12 04:09:40 +04:00
batadv_frag_list_free ( head ) ;
2010-12-13 14:19:28 +03:00
return - ENOMEM ;
}
tfp - > skb = NULL ;
tfp - > seqno = 0 ;
INIT_LIST_HEAD ( & tfp - > list ) ;
list_add ( & tfp - > list , head ) ;
}
return 0 ;
}
2012-06-06 00:31:31 +04:00
static struct batadv_frag_packet_list_entry *
2012-05-16 22:23:17 +04:00
batadv_frag_search_packet ( struct list_head * head ,
2012-06-06 00:31:30 +04:00
const struct batadv_unicast_frag_packet * up )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_frag_packet_list_entry * tfp ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_frag_packet * tmp_up = NULL ;
2013-01-15 16:17:19 +04:00
bool is_head_tmp , is_head ;
2010-12-13 14:19:28 +03:00
uint16_t search_seqno ;
2012-06-04 00:19:21 +04:00
if ( up - > flags & BATADV_UNI_FRAG_HEAD )
2010-12-13 14:19:28 +03:00
search_seqno = ntohs ( up - > seqno ) + 1 ;
else
search_seqno = ntohs ( up - > seqno ) - 1 ;
2013-01-15 16:17:19 +04:00
is_head = up - > flags & BATADV_UNI_FRAG_HEAD ;
2012-07-08 19:13:15 +04:00
2010-12-13 14:19:28 +03:00
list_for_each_entry ( tfp , head , list ) {
if ( ! tfp - > skb )
continue ;
if ( tfp - > seqno = = ntohs ( up - > seqno ) )
goto mov_tail ;
2012-06-06 00:31:30 +04:00
tmp_up = ( struct batadv_unicast_frag_packet * ) tfp - > skb - > data ;
2010-12-13 14:19:28 +03:00
if ( tfp - > seqno = = search_seqno ) {
2013-01-15 16:17:19 +04:00
is_head_tmp = tmp_up - > flags & BATADV_UNI_FRAG_HEAD ;
2012-07-08 19:13:15 +04:00
if ( is_head_tmp ! = is_head )
2010-12-13 14:19:28 +03:00
return tfp ;
else
goto mov_tail ;
}
}
return NULL ;
mov_tail :
list_move_tail ( & tfp - > list , head ) ;
return NULL ;
}
2012-05-12 04:09:40 +04:00
void batadv_frag_list_free ( struct list_head * head )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_frag_packet_list_entry * pf , * tmp_pf ;
2010-12-13 14:19:28 +03:00
if ( ! list_empty ( head ) ) {
list_for_each_entry_safe ( pf , tmp_pf , head , list ) {
kfree_skb ( pf - > skb ) ;
list_del ( & pf - > list ) ;
kfree ( pf ) ;
}
}
return ;
}
/* frag_reassemble_skb():
* returns NET_RX_DROP if the operation failed - skb is left intact
* returns NET_RX_SUCCESS if the fragment was buffered ( skb_new will be NULL )
* or the skb could be reassembled ( skb_new will point to the new packet and
* skb was freed )
*/
2012-06-06 00:31:31 +04:00
int batadv_frag_reassemble_skb ( struct sk_buff * skb ,
struct batadv_priv * bat_priv ,
2012-05-12 04:09:40 +04:00
struct sk_buff * * new_skb )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_orig_node * orig_node ;
struct batadv_frag_packet_list_entry * tmp_frag_entry ;
2010-12-13 14:19:28 +03:00
int ret = NET_RX_DROP ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_frag_packet * unicast_packet ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
unicast_packet = ( struct batadv_unicast_frag_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
* new_skb = NULL ;
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , unicast_packet - > orig ) ;
2011-02-18 15:28:09 +03:00
if ( ! orig_node )
2010-12-13 14:19:28 +03:00
goto out ;
orig_node - > last_frag_packet = jiffies ;
if ( list_empty ( & orig_node - > frag_list ) & &
2012-05-16 22:23:17 +04:00
batadv_frag_create_buffer ( & orig_node - > frag_list ) ) {
2010-12-13 14:19:28 +03:00
pr_debug ( " couldn't create frag buffer \n " ) ;
goto out ;
}
2012-05-16 22:23:17 +04:00
tmp_frag_entry = batadv_frag_search_packet ( & orig_node - > frag_list ,
unicast_packet ) ;
2010-12-13 14:19:28 +03:00
if ( ! tmp_frag_entry ) {
2012-05-16 22:23:17 +04:00
batadv_frag_create_entry ( & orig_node - > frag_list , skb ) ;
2010-12-13 14:19:28 +03:00
ret = NET_RX_SUCCESS ;
goto out ;
}
2012-05-16 22:23:17 +04:00
* new_skb = batadv_frag_merge_packet ( & orig_node - > frag_list ,
tmp_frag_entry , skb ) ;
2010-12-13 14:19:28 +03:00
/* if not, merge failed */
if ( * new_skb )
ret = NET_RX_SUCCESS ;
2011-02-18 15:28:09 +03:00
out :
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
2012-06-06 00:31:31 +04:00
int batadv_frag_send_skb ( struct sk_buff * skb , struct batadv_priv * bat_priv ,
struct batadv_hard_iface * hard_iface ,
const uint8_t dstaddr [ ] )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:30 +04:00
struct batadv_unicast_packet tmp_uc , * unicast_packet ;
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * primary_if ;
2010-12-13 14:19:28 +03:00
struct sk_buff * frag_skb ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_frag_packet * frag1 , * frag2 ;
2011-05-15 01:14:54 +04:00
int uc_hdr_len = sizeof ( * unicast_packet ) ;
int ucf_hdr_len = sizeof ( * frag1 ) ;
2011-01-26 00:59:26 +03:00
int data_len = skb - > len - uc_hdr_len ;
2011-04-20 17:40:58 +04:00
int large_tail = 0 , ret = NET_RX_DROP ;
2011-02-10 17:33:56 +03:00
uint16_t seqno ;
2010-12-13 14:19:28 +03:00
2012-05-12 15:48:54 +04:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 17:40:58 +04:00
if ( ! primary_if )
2010-12-13 14:19:28 +03:00
goto dropped ;
2011-01-13 23:53:38 +03:00
frag_skb = dev_alloc_skb ( data_len - ( data_len / 2 ) + ucf_hdr_len ) ;
if ( ! frag_skb )
goto dropped ;
2013-07-29 19:56:44 +04:00
skb - > priority = TC_PRIO_CONTROL ;
2011-01-26 00:59:26 +03:00
skb_reserve ( frag_skb , ucf_hdr_len ) ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
memcpy ( & tmp_uc , unicast_packet , uc_hdr_len ) ;
2011-01-26 00:59:26 +03:00
skb_split ( skb , frag_skb , data_len / 2 + uc_hdr_len ) ;
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:38 +04:00
if ( batadv_skb_head_push ( skb , ucf_hdr_len - uc_hdr_len ) < 0 | |
batadv_skb_head_push ( frag_skb , ucf_hdr_len ) < 0 )
2010-12-13 14:19:28 +03:00
goto drop_frag ;
2012-06-06 00:31:30 +04:00
frag1 = ( struct batadv_unicast_frag_packet * ) skb - > data ;
frag2 = ( struct batadv_unicast_frag_packet * ) frag_skb - > data ;
2010-12-13 14:19:28 +03:00
2011-05-15 01:14:54 +04:00
memcpy ( frag1 , & tmp_uc , sizeof ( tmp_uc ) ) ;
2010-12-13 14:19:28 +03:00
2011-11-20 18:47:38 +04:00
frag1 - > header . ttl - - ;
2012-06-04 00:19:13 +04:00
frag1 - > header . version = BATADV_COMPAT_VERSION ;
2012-06-04 00:19:21 +04:00
frag1 - > header . packet_type = BATADV_UNICAST_FRAG ;
2010-12-13 14:19:28 +03:00
2011-04-20 17:40:58 +04:00
memcpy ( frag1 - > orig , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2011-05-15 01:14:54 +04:00
memcpy ( frag2 , frag1 , sizeof ( * frag2 ) ) ;
2010-12-13 14:19:28 +03:00
2011-01-26 01:02:31 +03:00
if ( data_len & 1 )
2012-06-04 00:19:21 +04:00
large_tail = BATADV_UNI_FRAG_LARGETAIL ;
2011-01-26 01:02:31 +03:00
2012-06-04 00:19:21 +04:00
frag1 - > flags = BATADV_UNI_FRAG_HEAD | large_tail ;
2011-01-26 01:02:31 +03:00
frag2 - > flags = large_tail ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:33:20 +03:00
seqno = atomic_add_return ( 2 , & hard_iface - > frag_seqno ) ;
2011-02-10 17:33:56 +03:00
frag1 - > seqno = htons ( seqno - 1 ) ;
frag2 - > seqno = htons ( seqno ) ;
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:37 +04:00
batadv_send_skb_packet ( skb , hard_iface , dstaddr ) ;
batadv_send_skb_packet ( frag_skb , hard_iface , dstaddr ) ;
2011-04-20 17:40:58 +04:00
ret = NET_RX_SUCCESS ;
goto out ;
2010-12-13 14:19:28 +03:00
drop_frag :
kfree_skb ( frag_skb ) ;
dropped :
kfree_skb ( skb ) ;
2011-04-20 17:40:58 +04:00
out :
if ( primary_if )
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( primary_if ) ;
2011-04-20 17:40:58 +04:00
return ret ;
2010-12-13 14:19:28 +03:00
}
2012-10-01 11:57:35 +04:00
/**
* batadv_unicast_push_and_fill_skb - extends the buffer and initializes the
* common fields for unicast packets
* @ skb : packet
* @ hdr_size : amount of bytes to push at the beginning of the skb
* @ orig_node : the destination node
*
* Returns false if the buffer extension was not possible or true otherwise
*/
static bool batadv_unicast_push_and_fill_skb ( struct sk_buff * skb , int hdr_size ,
struct batadv_orig_node * orig_node )
{
struct batadv_unicast_packet * unicast_packet ;
uint8_t ttvn = ( uint8_t ) atomic_read ( & orig_node - > last_ttvn ) ;
if ( batadv_skb_head_push ( skb , hdr_size ) < 0 )
return false ;
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
unicast_packet - > header . version = BATADV_COMPAT_VERSION ;
/* batman packet type: unicast */
unicast_packet - > header . packet_type = BATADV_UNICAST ;
/* set unicast ttl */
unicast_packet - > header . ttl = BATADV_TTL ;
/* copy the destination for faster routing */
memcpy ( unicast_packet - > dest , orig_node - > orig , ETH_ALEN ) ;
/* set the destination tt version number */
unicast_packet - > ttvn = ttvn ;
return true ;
}
/**
* batadv_unicast_prepare_skb - encapsulate an skb with a unicast header
* @ skb : the skb containing the payload to encapsulate
* @ orig_node : the destination node
*
2013-08-06 22:21:15 +04:00
* Returns false if the payload could not be encapsulated or true otherwise .
*
* This call might reallocate skb data .
2012-10-01 11:57:35 +04:00
*/
static bool batadv_unicast_prepare_skb ( struct sk_buff * skb ,
struct batadv_orig_node * orig_node )
{
size_t uni_size = sizeof ( struct batadv_unicast_packet ) ;
return batadv_unicast_push_and_fill_skb ( skb , uni_size , orig_node ) ;
}
/**
* batadv_unicast_4addr_prepare_skb - encapsulate an skb with a unicast4addr
* header
* @ bat_priv : the bat priv with all the soft interface information
* @ skb : the skb containing the payload to encapsulate
* @ orig_node : the destination node
* @ packet_subtype : the batman 4 addr packet subtype to use
*
2013-08-06 22:21:15 +04:00
* Returns false if the payload could not be encapsulated or true otherwise .
*
* This call might reallocate skb data .
2012-10-01 11:57:35 +04:00
*/
2011-11-23 14:35:44 +04:00
bool batadv_unicast_4addr_prepare_skb ( struct batadv_priv * bat_priv ,
struct sk_buff * skb ,
struct batadv_orig_node * orig ,
int packet_subtype )
2012-10-01 11:57:35 +04:00
{
struct batadv_hard_iface * primary_if ;
struct batadv_unicast_4addr_packet * unicast_4addr_packet ;
bool ret = false ;
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
goto out ;
/* pull the header space and fill the unicast_packet substructure.
* We can do that because the first member of the unicast_4addr_packet
* is of type struct unicast_packet
*/
if ( ! batadv_unicast_push_and_fill_skb ( skb ,
sizeof ( * unicast_4addr_packet ) ,
orig ) )
goto out ;
unicast_4addr_packet = ( struct batadv_unicast_4addr_packet * ) skb - > data ;
unicast_4addr_packet - > u . header . packet_type = BATADV_UNICAST_4ADDR ;
memcpy ( unicast_4addr_packet - > src , primary_if - > net_dev - > dev_addr ,
ETH_ALEN ) ;
unicast_4addr_packet - > subtype = packet_subtype ;
unicast_4addr_packet - > reserved = 0 ;
ret = true ;
out :
if ( primary_if )
batadv_hardif_free_ref ( primary_if ) ;
return ret ;
}
/**
* batadv_unicast_generic_send_skb - send an skb as unicast
* @ bat_priv : the bat priv with all the soft interface information
* @ skb : payload to send
* @ packet_type : the batman unicast packet type to use
* @ packet_subtype : the batman packet subtype . It is ignored if packet_type is
* not BATADV_UNICAT_4ADDR
*
* Returns 1 in case of error or 0 otherwise
*/
int batadv_unicast_generic_send_skb ( struct batadv_priv * bat_priv ,
struct sk_buff * skb , int packet_type ,
int packet_subtype )
2010-12-13 14:19:28 +03:00
{
struct ethhdr * ethhdr = ( struct ethhdr * ) skb - > data ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_packet * unicast_packet ;
2012-06-06 00:31:31 +04:00
struct batadv_orig_node * orig_node ;
struct batadv_neigh_node * neigh_node ;
2010-12-13 14:19:28 +03:00
int data_len = skb - > len ;
2012-10-16 18:13:48 +04:00
int ret = NET_RX_DROP ;
2013-08-06 22:21:15 +04:00
unsigned int dev_mtu , header_len ;
2010-12-13 14:19:28 +03:00
/* get routing information */
2011-02-14 00:13:04 +03:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) ) {
2012-05-12 04:09:29 +04:00
orig_node = batadv_gw_get_selected_orig ( bat_priv ) ;
2011-02-14 00:13:04 +03:00
if ( orig_node )
2011-02-10 17:33:53 +03:00
goto find_router ;
}
2010-12-13 14:19:28 +03:00
2011-07-07 17:35:37 +04:00
/* check for tt host - increases orig_node refcount.
2012-05-12 04:09:43 +04:00
* returns NULL in case of AP isolation
*/
2012-05-12 04:09:39 +04:00
orig_node = batadv_transtable_search ( bat_priv , ethhdr - > h_source ,
ethhdr - > h_dest ) ;
2012-06-06 00:31:31 +04:00
2011-02-10 17:33:53 +03:00
find_router :
2012-05-12 04:09:43 +04:00
/* find_router():
2011-01-19 23:01:44 +03:00
* - if orig_node is NULL it returns NULL
* - increases neigh_nodes refcount if found .
*/
2012-05-12 04:09:36 +04:00
neigh_node = batadv_find_router ( bat_priv , orig_node , NULL ) ;
2012-06-06 00:31:31 +04:00
2011-02-10 17:33:53 +03:00
if ( ! neigh_node )
2011-01-19 23:01:44 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2012-10-01 11:57:35 +04:00
switch ( packet_type ) {
case BATADV_UNICAST :
2013-07-27 05:24:44 +04:00
if ( ! batadv_unicast_prepare_skb ( skb , orig_node ) )
goto out ;
2013-08-06 22:21:15 +04:00
header_len = sizeof ( struct batadv_unicast_packet ) ;
2012-10-01 11:57:35 +04:00
break ;
case BATADV_UNICAST_4ADDR :
2013-07-27 05:24:44 +04:00
if ( ! batadv_unicast_4addr_prepare_skb ( bat_priv , skb , orig_node ,
packet_subtype ) )
goto out ;
2013-08-06 22:21:15 +04:00
header_len = sizeof ( struct batadv_unicast_4addr_packet ) ;
2012-10-01 11:57:35 +04:00
break ;
default :
/* this function supports UNICAST and UNICAST_4ADDR only. It
* should never be invoked with any other packet type
*/
2011-01-19 23:01:44 +03:00
goto out ;
2012-10-01 11:57:35 +04:00
}
2010-12-13 14:19:28 +03:00
2013-08-06 22:21:15 +04:00
ethhdr = ( struct ethhdr * ) ( skb - > data + header_len ) ;
2012-06-06 00:31:30 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2012-03-16 21:03:28 +04:00
/* inform the destination node that we are still missing a correct route
* for this client . The destination will receive this packet and will
* try to reroute it because the ttvn contained in the header is less
* than the current one
*/
2012-05-12 04:09:39 +04:00
if ( batadv_tt_global_client_is_roaming ( bat_priv , ethhdr - > h_dest ) )
2012-03-16 21:03:28 +04:00
unicast_packet - > ttvn = unicast_packet - > ttvn - 1 ;
2012-06-19 22:26:30 +04:00
dev_mtu = neigh_node - > if_incoming - > net_dev - > mtu ;
2012-10-01 11:57:35 +04:00
/* fragmentation mechanism only works for UNICAST (now) */
if ( packet_type = = BATADV_UNICAST & &
atomic_read ( & bat_priv - > fragmentation ) & &
2012-06-19 22:26:30 +04:00
data_len + sizeof ( * unicast_packet ) > dev_mtu ) {
2010-12-13 14:19:28 +03:00
/* send frag skb decreases ttl */
2011-11-20 18:47:38 +04:00
unicast_packet - > header . ttl + + ;
2012-05-12 04:09:40 +04:00
ret = batadv_frag_send_skb ( skb , bat_priv ,
neigh_node - > if_incoming ,
neigh_node - > addr ) ;
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
}
2013-04-20 15:54:39 +04:00
if ( batadv_send_skb_to_orig ( skb , orig_node , NULL ) ! = NET_XMIT_DROP )
2012-10-16 18:13:48 +04:00
ret = 0 ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
if ( neigh_node )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( neigh_node ) ;
2011-02-10 17:33:53 +03:00
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2012-10-16 18:13:48 +04:00
if ( ret = = NET_RX_DROP )
2011-02-10 17:33:53 +03:00
kfree_skb ( skb ) ;
return ret ;
2010-12-13 14:19:28 +03:00
}