1997-12-13 17:16:07 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1997-12-13 17:16:07 +03:00
NBT netbios library routines
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
Copyright ( C ) Jeremy Allison 1994 - 1998
1997-12-13 17:16:07 +03: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1997-12-13 17:16:07 +03:00
( at your option ) any later version .
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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1997-12-13 17:16:07 +03:00
*/
# include "includes.h"
int num_response_packets = 0 ;
/***************************************************************************
Add an expected response record into the list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-05 09:07:05 +04:00
static void add_response_record ( struct subnet_record * subrec ,
1997-12-13 17:16:07 +03:00
struct response_record * rrec )
{
2003-08-27 05:25:01 +04:00
num_response_packets + + ; /* count of total number of packets still around */
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 4 , ( " add_response_record: adding response record id:%hu to subnet %s. num_records:%d \n " ,
rrec - > response_id , subrec - > subnet_name , num_response_packets ) ) ;
1997-12-13 17:16:07 +03:00
2008-01-02 22:56:07 +03:00
DLIST_ADD_END ( subrec - > responselist , rrec , struct response_record * ) ;
1997-12-13 17:16:07 +03:00
}
/***************************************************************************
Remove an expected response record from the list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_response_record ( struct subnet_record * subrec ,
struct response_record * rrec )
{
2008-02-29 17:55:33 +03:00
/* It is possible this can be called twice,
with a rrec pointer that has been freed . So
before we inderect into rrec , search for it
on the responselist first . Bug # 3617. JRA . */
struct response_record * p = NULL ;
for ( p = subrec - > responselist ; p ; p = p - > next ) {
if ( p = = rrec ) {
break ;
}
}
if ( p = = NULL ) {
/* We didn't find rrec on the list. */
return ;
}
2008-01-02 22:56:07 +03:00
DLIST_REMOVE ( subrec - > responselist , rrec ) ;
2003-08-27 05:25:01 +04:00
if ( rrec - > userdata ) {
if ( rrec - > userdata - > free_fn ) {
( * rrec - > userdata - > free_fn ) ( rrec - > userdata ) ;
} else {
ZERO_STRUCTP ( rrec - > userdata ) ;
SAFE_FREE ( rrec - > userdata ) ;
}
}
/* Ensure we can delete. */
rrec - > packet - > locked = False ;
free_packet ( rrec - > packet ) ;
ZERO_STRUCTP ( rrec ) ;
SAFE_FREE ( rrec ) ;
num_response_packets - - ; /* count of total number of packets still around */
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Create a response record for an outgoing packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct response_record * make_response_record ( struct subnet_record * subrec ,
2002-07-15 14:35:28 +04:00
struct packet_struct * p ,
response_function resp_fn ,
timeout_response_function timeout_fn ,
success_function success_fn ,
fail_function fail_fn ,
struct userdata_struct * userdata )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct response_record * rrec ;
struct nmb_packet * nmb = & p - > packet . nmb ;
2004-12-07 21:25:53 +03:00
if ( ! ( rrec = SMB_MALLOC_P ( struct response_record ) ) ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " make_response_queue_record: malloc fail for response_record. \n " ) ) ;
return NULL ;
}
memset ( ( char * ) rrec , ' \0 ' , sizeof ( * rrec ) ) ;
rrec - > response_id = nmb - > header . name_trn_id ;
rrec - > resp_fn = resp_fn ;
rrec - > timeout_fn = timeout_fn ;
rrec - > success_fn = success_fn ;
rrec - > fail_fn = fail_fn ;
rrec - > packet = p ;
if ( userdata ) {
/* Intelligent userdata. */
if ( userdata - > copy_fn ) {
if ( ( rrec - > userdata = ( * userdata - > copy_fn ) ( userdata ) ) = = NULL ) {
DEBUG ( 0 , ( " make_response_queue_record: copy fail for userdata. \n " ) ) ;
ZERO_STRUCTP ( rrec ) ;
SAFE_FREE ( rrec ) ;
return NULL ;
}
} else {
/* Primitive userdata, do a memcpy. */
if ( ( rrec - > userdata = ( struct userdata_struct * )
2004-12-07 21:25:53 +03:00
SMB_MALLOC ( sizeof ( struct userdata_struct ) + userdata - > userdata_len ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " make_response_queue_record: malloc fail for userdata. \n " ) ) ;
ZERO_STRUCTP ( rrec ) ;
SAFE_FREE ( rrec ) ;
return NULL ;
}
rrec - > userdata - > copy_fn = userdata - > copy_fn ;
rrec - > userdata - > free_fn = userdata - > free_fn ;
rrec - > userdata - > userdata_len = userdata - > userdata_len ;
memcpy ( rrec - > userdata - > data , userdata - > data , userdata - > userdata_len ) ;
}
} else {
rrec - > userdata = NULL ;
}
rrec - > num_msgs = 0 ;
if ( ! nmb - > header . nm_flags . bcast )
rrec - > repeat_interval = 5 ; /* 5 seconds for unicast packets. */
else
rrec - > repeat_interval = 1 ; /* XXXX should be in ms */
rrec - > repeat_count = 3 ; /* 3 retries */
rrec - > repeat_time = time ( NULL ) + rrec - > repeat_interval ; /* initial retry time */
/* This packet is not being processed. */
rrec - > in_expiration_processing = False ;
/* Lock the packet so we won't lose it while it's on the list. */
p - > locked = True ;
add_response_record ( subrec , rrec ) ;
return rrec ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Find a response in a subnet ' s name query response list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct response_record * find_response_record_on_subnet (
struct subnet_record * subrec , uint16 id )
{
2003-08-27 05:25:01 +04:00
struct response_record * rrec = NULL ;
for ( rrec = subrec - > responselist ; rrec ; rrec = rrec - > next ) {
if ( rrec - > response_id = = id ) {
DEBUG ( 4 , ( " find_response_record: found response record id = %hu on subnet %s \n " ,
id , subrec - > subnet_name ) ) ;
break ;
}
}
return rrec ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Find a response in any subnet ' s name query response list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct response_record * find_response_record ( struct subnet_record * * ppsubrec ,
uint16 id )
{
2003-08-27 05:25:01 +04:00
struct response_record * rrec = NULL ;
for ( ( * ppsubrec ) = FIRST_SUBNET ; ( * ppsubrec ) ;
( * ppsubrec ) = NEXT_SUBNET_INCLUDING_UNICAST ( * ppsubrec ) ) {
if ( ( rrec = find_response_record_on_subnet ( * ppsubrec , id ) ) ! = NULL )
return rrec ;
}
/* There should never be response records on the remote_broadcast subnet.
Sanity check to ensure this is so . */
if ( remote_broadcast_subnet - > responselist ! = NULL ) {
DEBUG ( 0 , ( " find_response_record: response record found on subnet %s. This should \
1997-12-13 17:16:07 +03:00
never happen ! \ n " , remote_broadcast_subnet->subnet_name));
2003-08-27 05:25:01 +04:00
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Now check the WINS server subnet if it exists. */
if ( wins_server_subnet ! = NULL ) {
* ppsubrec = wins_server_subnet ;
if ( ( rrec = find_response_record_on_subnet ( * ppsubrec , id ) ) ! = NULL )
return rrec ;
}
1997-12-13 17:16:07 +03:00
2006-06-03 04:36:00 +04:00
DEBUG ( 3 , ( " find_response_record: response packet id %hu received with no \
1997-12-13 17:16:07 +03:00
matching record . \ n " , id));
2003-08-27 05:25:01 +04:00
* ppsubrec = NULL ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return NULL ;
1997-12-13 17:16:07 +03:00
}
1998-01-29 11:25:46 +03:00
/****************************************************************************
Check if a refresh is queued for a particular name on a particular subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool is_refresh_already_queued ( struct subnet_record * subrec , struct name_record * namerec )
1998-01-29 11:25:46 +03:00
{
2003-08-27 05:25:01 +04:00
struct response_record * rrec = NULL ;
1998-01-29 11:25:46 +03:00
2003-08-27 05:25:01 +04:00
for ( rrec = subrec - > responselist ; rrec ; rrec = rrec - > next ) {
struct packet_struct * p = rrec - > packet ;
struct nmb_packet * nmb = & p - > packet . nmb ;
if ( ( nmb - > header . opcode = = NMB_NAME_REFRESH_OPCODE_8 ) | |
( nmb - > header . opcode = = NMB_NAME_REFRESH_OPCODE_9 ) ) {
/* Yes it's a queued refresh - check if the name is correct. */
if ( nmb_name_equal ( & nmb - > question . question_name , & namerec - > name ) )
return True ;
}
}
return False ;
}