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 26int num_response_packets = 0; 27 28/*************************************************************************** 29 Add an expected response record into the list 30 **************************************************************************/ 31 32static void add_response_record(struct subnet_record *subrec, 33 struct response_record *rrec) 34{ 35 struct response_record *rrec2; 36 37 num_response_packets++; /* count of total number of packets still around */ 38 39 DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n", 40 rrec->response_id, subrec->subnet_name, num_response_packets)); 41 42 if (!subrec->responselist) { 43 subrec->responselist = rrec; 44 rrec->prev = NULL; 45 rrec->next = NULL; 46 return; 47 } 48 49 for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next) 50 ; 51 52 rrec2->next = rrec; 53 rrec->next = NULL; 54 rrec->prev = rrec2; 55} 56 57/*************************************************************************** 58 Remove an expected response record from the list 59 **************************************************************************/ 60 61void remove_response_record(struct subnet_record *subrec, 62 struct response_record *rrec) 63{ 64 if (rrec->prev) 65 rrec->prev->next = rrec->next; 66 if (rrec->next) 67 rrec->next->prev = rrec->prev; 68 69 if (subrec->responselist == rrec) 70 subrec->responselist = rrec->next; 71 72 if(rrec->userdata) { 73 if(rrec->userdata->free_fn) { 74 (*rrec->userdata->free_fn)(rrec->userdata); 75 } else { 76 ZERO_STRUCTP(rrec->userdata); 77 SAFE_FREE(rrec->userdata); 78 } 79 } 80 81 /* Ensure we can delete. */ 82 rrec->packet->locked = False; 83 free_packet(rrec->packet); 84 85 ZERO_STRUCTP(rrec); 86 SAFE_FREE(rrec); 87 88 num_response_packets--; /* count of total number of packets still around */ 89} 90 91/**************************************************************************** 92 Create a response record for an outgoing packet. 93 **************************************************************************/ 94 95struct response_record *make_response_record( struct subnet_record *subrec, 96 struct packet_struct *p, 97 response_function resp_fn, 98 timeout_response_function timeout_fn, 99 success_function success_fn, 100 fail_function fail_fn, 101 struct userdata_struct *userdata) 102{ 103 struct response_record *rrec; 104 struct nmb_packet *nmb = &p->packet.nmb; 105 106 if (!(rrec = SMB_MALLOC_P(struct response_record))) { 107 DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n")); 108 return NULL; 109 } 110 111 memset((char *)rrec, '\0', sizeof(*rrec)); 112 113 rrec->response_id = nmb->header.name_trn_id; 114 115 rrec->resp_fn = resp_fn; 116 rrec->timeout_fn = timeout_fn; 117 rrec->success_fn = success_fn; 118 rrec->fail_fn = fail_fn; 119 120 rrec->packet = p; 121 122 if(userdata) { 123 /* Intelligent userdata. */ 124 if(userdata->copy_fn) { 125 if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL) { 126 DEBUG(0,("make_response_queue_record: copy fail for userdata.\n")); 127 ZERO_STRUCTP(rrec); 128 SAFE_FREE(rrec); 129 return NULL; 130 } 131 } else { 132 /* Primitive userdata, do a memcpy. */ 133 if((rrec->userdata = (struct userdata_struct *) 134 SMB_MALLOC(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL) { 135 DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n")); 136 ZERO_STRUCTP(rrec); 137 SAFE_FREE(rrec); 138 return NULL; 139 } 140 rrec->userdata->copy_fn = userdata->copy_fn; 141 rrec->userdata->free_fn = userdata->free_fn; 142 rrec->userdata->userdata_len = userdata->userdata_len; 143 memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len); 144 } 145 } else { 146 rrec->userdata = NULL; 147 } 148 149 rrec->num_msgs = 0; 150 151 if(!nmb->header.nm_flags.bcast) 152 rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */ 153 else 154 rrec->repeat_interval = 1; /* XXXX should be in ms */ 155 rrec->repeat_count = 3; /* 3 retries */ 156 rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */ 157 158 /* This packet is not being processed. */ 159 rrec->in_expiration_processing = False; 160 161 /* Lock the packet so we won't lose it while it's on the list. */ 162 p->locked = True; 163 164 add_response_record(subrec, rrec); 165 166 return rrec; 167} 168 169/**************************************************************************** 170 Find a response in a subnet's name query response list. 171 **************************************************************************/ 172 173static struct response_record *find_response_record_on_subnet( 174 struct subnet_record *subrec, uint16 id) 175{ 176 struct response_record *rrec = NULL; 177 178 for (rrec = subrec->responselist; rrec; rrec = rrec->next) { 179 if (rrec->response_id == id) { 180 DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n", 181 id, subrec->subnet_name)); 182 break; 183 } 184 } 185 return rrec; 186} 187 188/**************************************************************************** 189 Find a response in any subnet's name query response list. 190 **************************************************************************/ 191 192struct response_record *find_response_record(struct subnet_record **ppsubrec, 193 uint16 id) 194{ 195 struct response_record *rrec = NULL; 196 197 for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec); 198 (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) { 199 if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL) 200 return rrec; 201 } 202 203 /* There should never be response records on the remote_broadcast subnet. 204 Sanity check to ensure this is so. */ 205 if(remote_broadcast_subnet->responselist != NULL) { 206 DEBUG(0,("find_response_record: response record found on subnet %s. This should \ 207never happen !\n", remote_broadcast_subnet->subnet_name)); 208 } 209 210 /* Now check the WINS server subnet if it exists. */ 211 if(wins_server_subnet != NULL) { 212 *ppsubrec = wins_server_subnet; 213 if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL) 214 return rrec; 215 } 216 217 DEBUG(3,("find_response_record: response packet id %hu received with no \ 218matching record.\n", id)); 219 220 *ppsubrec = NULL; 221 222 return NULL; 223} 224 225/**************************************************************************** 226 Check if a refresh is queued for a particular name on a particular subnet. 227 **************************************************************************/ 228 229BOOL is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec) 230{ 231 struct response_record *rrec = NULL; 232 233 for (rrec = subrec->responselist; rrec; rrec = rrec->next) { 234 struct packet_struct *p = rrec->packet; 235 struct nmb_packet *nmb = &p->packet.nmb; 236 237 if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || 238 (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9)) { 239 /* Yes it's a queued refresh - check if the name is correct. */ 240 if(nmb_name_equal(&nmb->question.question_name, &namerec->name)) 241 return True; 242 } 243 } 244 245 return False; 246} 247