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