1/* 2 Unix SMB/CIFS implementation. 3 NBT netbios library routines 4 Copyright (C) Andrew Tridgell 1994-1998 5 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 6 Copyright (C) Jeremy Allison 1994-1998 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23 24#include "includes.h" 25 26extern int ClientNMB; 27 28int num_response_packets = 0; 29 30/*************************************************************************** 31 Add an expected response record into the list 32 **************************************************************************/ 33 34static void add_response_record(struct subnet_record *subrec, 35 struct response_record *rrec) 36{ 37 struct response_record *rrec2; 38 39 num_response_packets++; /* count of total number of packets still around */ 40 41 DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n", 42 rrec->response_id, subrec->subnet_name, num_response_packets)); 43 44 if (!subrec->responselist) { 45 subrec->responselist = rrec; 46 rrec->prev = NULL; 47 rrec->next = NULL; 48 return; 49 } 50 51 for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next) 52 ; 53 54 rrec2->next = rrec; 55 rrec->next = NULL; 56 rrec->prev = rrec2; 57} 58 59/*************************************************************************** 60 Remove an expected response record from the list 61 **************************************************************************/ 62 63void remove_response_record(struct subnet_record *subrec, 64 struct response_record *rrec) 65{ 66 if (rrec->prev) 67 rrec->prev->next = rrec->next; 68 if (rrec->next) 69 rrec->next->prev = rrec->prev; 70 71 if (subrec->responselist == rrec) 72 subrec->responselist = rrec->next; 73 74 if(rrec->userdata) { 75 if(rrec->userdata->free_fn) { 76 (*rrec->userdata->free_fn)(rrec->userdata); 77 } else { 78 ZERO_STRUCTP(rrec->userdata); 79 SAFE_FREE(rrec->userdata); 80 } 81 } 82 83 /* Ensure we can delete. */ 84 rrec->packet->locked = False; 85 free_packet(rrec->packet); 86 87 ZERO_STRUCTP(rrec); 88 SAFE_FREE(rrec); 89 90 num_response_packets--; /* count of total number of packets still around */ 91} 92 93/**************************************************************************** 94 Create a response record for an outgoing packet. 95 **************************************************************************/ 96 97struct response_record *make_response_record( struct subnet_record *subrec, 98 struct packet_struct *p, 99 response_function resp_fn, 100 timeout_response_function timeout_fn, 101 success_function success_fn, 102 fail_function fail_fn, 103 struct userdata_struct *userdata) 104{ 105 struct response_record *rrec; 106 struct nmb_packet *nmb = &p->packet.nmb; 107 108 if (!(rrec = SMB_MALLOC_P(struct response_record))) { 109 DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n")); 110 return NULL; 111 } 112 113 memset((char *)rrec, '\0', sizeof(*rrec)); 114 115 rrec->response_id = nmb->header.name_trn_id; 116 117 rrec->resp_fn = resp_fn; 118 rrec->timeout_fn = timeout_fn; 119 rrec->success_fn = success_fn; 120 rrec->fail_fn = fail_fn; 121 122 rrec->packet = p; 123 124 if(userdata) { 125 /* Intelligent userdata. */ 126 if(userdata->copy_fn) { 127 if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL) { 128 DEBUG(0,("make_response_queue_record: copy fail for userdata.\n")); 129 ZERO_STRUCTP(rrec); 130 SAFE_FREE(rrec); 131 return NULL; 132 } 133 } else { 134 /* Primitive userdata, do a memcpy. */ 135 if((rrec->userdata = (struct userdata_struct *) 136 SMB_MALLOC(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL) { 137 DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n")); 138 ZERO_STRUCTP(rrec); 139 SAFE_FREE(rrec); 140 return NULL; 141 } 142 rrec->userdata->copy_fn = userdata->copy_fn; 143 rrec->userdata->free_fn = userdata->free_fn; 144 rrec->userdata->userdata_len = userdata->userdata_len; 145 memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len); 146 } 147 } else { 148 rrec->userdata = NULL; 149 } 150 151 rrec->num_msgs = 0; 152 153 if(!nmb->header.nm_flags.bcast) 154 rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */ 155 else 156 rrec->repeat_interval = 1; /* XXXX should be in ms */ 157 rrec->repeat_count = 3; /* 3 retries */ 158 rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */ 159 160 /* This packet is not being processed. */ 161 rrec->in_expiration_processing = False; 162 163 /* Lock the packet so we won't lose it while it's on the list. */ 164 p->locked = True; 165 166 add_response_record(subrec, rrec); 167 168 return rrec; 169} 170 171/**************************************************************************** 172 Find a response in a subnet's name query response list. 173 **************************************************************************/ 174 175static struct response_record *find_response_record_on_subnet( 176 struct subnet_record *subrec, uint16 id) 177{ 178 struct response_record *rrec = NULL; 179 180 for (rrec = subrec->responselist; rrec; rrec = rrec->next) { 181 if (rrec->response_id == id) { 182 DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n", 183 id, subrec->subnet_name)); 184 break; 185 } 186 } 187 return rrec; 188} 189 190/**************************************************************************** 191 Find a response in any subnet's name query response list. 192 **************************************************************************/ 193 194struct response_record *find_response_record(struct subnet_record **ppsubrec, 195 uint16 id) 196{ 197 struct response_record *rrec = NULL; 198 199 for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec); 200 (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) { 201 if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL) 202 return rrec; 203 } 204 205 /* There should never be response records on the remote_broadcast subnet. 206 Sanity check to ensure this is so. */ 207 if(remote_broadcast_subnet->responselist != NULL) { 208 DEBUG(0,("find_response_record: response record found on subnet %s. This should \ 209never happen !\n", remote_broadcast_subnet->subnet_name)); 210 } 211 212 /* Now check the WINS server subnet if it exists. */ 213 if(wins_server_subnet != NULL) { 214 *ppsubrec = wins_server_subnet; 215 if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL) 216 return rrec; 217 } 218 219 DEBUG(0,("find_response_record: response packet id %hu received with no \ 220matching record.\n", id)); 221 222 *ppsubrec = NULL; 223 224 return NULL; 225} 226 227/**************************************************************************** 228 Check if a refresh is queued for a particular name on a particular subnet. 229 **************************************************************************/ 230 231BOOL is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec) 232{ 233 struct response_record *rrec = NULL; 234 235 for (rrec = subrec->responselist; rrec; rrec = rrec->next) { 236 struct packet_struct *p = rrec->packet; 237 struct nmb_packet *nmb = &p->packet.nmb; 238 239 if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || 240 (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9)) { 241 /* Yes it's a queued refresh - check if the name is correct. */ 242 if(nmb_name_equal(&nmb->question.question_name, &namerec->name)) 243 return True; 244 } 245 } 246 247 return False; 248} 249