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