1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 NBT netbios routines and daemon - version 2 5 Copyright (C) Andrew Tridgell 1994-1998 6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 7 Copyright (C) Jeremy Allison 1994-1998 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 23*/ 24 25#include "includes.h" 26 27extern int DEBUGLEVEL; 28 29/**************************************************************************** 30 Deal with a response packet when releasing one of our names. 31****************************************************************************/ 32 33static void release_name_response(struct subnet_record *subrec, 34 struct response_record *rrec, struct packet_struct *p) 35{ 36 /* 37 * If we are releasing broadcast, then getting a response is an 38 * error. If we are releasing unicast, then we expect to get a response. 39 */ 40 41 struct nmb_packet *nmb = &p->packet.nmb; 42 BOOL bcast = nmb->header.nm_flags.bcast; 43 BOOL success = True; 44 struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; 45 struct nmb_name *answer_name = &nmb->answers->rr_name; 46 struct in_addr released_ip; 47 48 /* Sanity check. Ensure that the answer name in the incoming packet is the 49 same as the requested name in the outgoing packet. */ 50 51 if(!nmb_name_equal(question_name, answer_name)) 52 { 53 DEBUG(0,("release_name_response: Answer name %s differs from question \ 54name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name))); 55 return; 56 } 57 58 if(bcast) 59 { 60 /* Someone sent a response. This shouldn't happen/ */ 61 DEBUG(1,("release_name_response: A response for releasing name %s was received on a \ 62broadcast subnet %s. This should not happen !\n", nmb_namestr(answer_name), subrec->subnet_name)); 63 return; 64 } 65 else 66 { 67 /* Unicast - check to see if the response allows us to release the name. */ 68 if(nmb->header.rcode != 0) 69 { 70 /* Error code - we were told not to release the name ! What now ! */ 71 success = False; 72 73 DEBUG(0,("release_name_response: WINS server at IP %s rejected our \ 74name release of name %s with error code %d.\n", inet_ntoa(p->ip), 75 nmb_namestr(answer_name), nmb->header.rcode)); 76 77 } 78 else if(nmb->header.opcode == NMB_WACK_OPCODE) 79 { 80 /* WINS server is telling us to wait. Pretend we didn't get 81 the response but don't send out any more release requests. */ 82 83 DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \ 84name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name)); 85 86 rrec->repeat_count = 0; 87 /* How long we should wait for. */ 88 rrec->repeat_time = p->timestamp + nmb->answers->ttl; 89 rrec->num_msgs--; 90 return; 91 } 92 } 93 94 DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n", 95 success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name)); 96 97 if(success) 98 { 99 putip((char*)&released_ip ,&nmb->answers->rdata[2]); 100 101 if(rrec->success_fn) 102 (*rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip); 103 standard_success_release( subrec, rrec->userdata, answer_name, released_ip); 104 } 105 else 106 { 107 /* We have no standard_fail_release - maybe we should add one ? */ 108 if(rrec->fail_fn) 109 (*rrec->fail_fn)(subrec, rrec, answer_name); 110 } 111 112 remove_response_record(subrec, rrec); 113} 114 115/**************************************************************************** 116 Deal with a timeout when releasing one of our names. 117****************************************************************************/ 118 119static void release_name_timeout_response(struct subnet_record *subrec, 120 struct response_record *rrec) 121{ 122 /* 123 * If we are releasing unicast, then NOT getting a response is an 124 * error - we could not release the name. If we are releasing broadcast, 125 * then we don't expect to get a response. 126 */ 127 128 struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; 129 BOOL bcast = sent_nmb->header.nm_flags.bcast; 130 BOOL success = False; 131 struct nmb_name *question_name = &sent_nmb->question.question_name; 132 struct in_addr released_ip; 133 134 if(bcast) 135 { 136 if(rrec->num_msgs == 0) 137 { 138 /* Not receiving a message is success for broadcast release. */ 139 success = True; 140 141 /* Get the ip address we were trying to release. */ 142 putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]); 143 } 144 } 145 else 146 { 147 /* Unicast - if no responses then it's an error. */ 148 if(rrec->num_msgs == 0) 149 { 150 DEBUG(2,("release_name_timeout_response: WINS server at address %s is not \ 151responding.\n", inet_ntoa(rrec->packet->ip))); 152 153 /* Keep trying to contact the WINS server periodically. This allows 154 us to work correctly if the WINS server is down temporarily when 155 we want to delete the name. */ 156 157 /* Reset the number of attempts to zero and double the interval between 158 retries. Max out at 5 minutes. */ 159 rrec->repeat_count = 3; 160 rrec->repeat_interval *= 2; 161 if(rrec->repeat_interval > (5 * 60)) 162 rrec->repeat_interval = (5 * 60); 163 rrec->repeat_time = time(NULL) + rrec->repeat_interval; 164 165 DEBUG(5,("release_name_timeout_response: increasing WINS timeout to %d seconds.\n", 166 (int)rrec->repeat_interval)); 167 return; /* Don't remove the response record. */ 168 } 169 } 170 171 DEBUG(5,("release_name_timeout_response: %s in releasing name %s on subnet %s.\n", 172 success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name)); 173 174 if(success && rrec->success_fn) 175 { 176 if(rrec->success_fn) 177 (*rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip); 178 standard_success_release( subrec, rrec->userdata, question_name, released_ip); 179 } 180 else 181 { 182 /* We have no standard_fail_release - maybe we should add one ? */ 183 if( rrec->fail_fn) 184 (*rrec->fail_fn)(subrec, rrec, question_name); 185 } 186 187 remove_response_record(subrec, rrec); 188} 189 190/**************************************************************************** 191 Try and release one of our names. 192****************************************************************************/ 193 194BOOL release_name(struct subnet_record *subrec, struct name_record *namerec, 195 release_name_success_function success_fn, 196 release_name_fail_function fail_fn, 197 struct userdata_struct *userdata) 198{ 199 int i; 200 201 /* Ensure it's a SELF name, and in the ACTIVE state. */ 202 if((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) 203 { 204 DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n", 205 nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source)); 206 return True; 207 } 208 209 /* Set the name into the deregistering state. */ 210 namerec->data.nb_flags |= NB_DEREG; 211 212 /* 213 * Go through and release the name for all known ip addresses. 214 * Only call the success/fail function on the last one (it should 215 * only be done once). 216 */ 217 218 for( i = 0; i < namerec->data.num_ips; i++) 219 { 220 if(queue_release_name( subrec, 221 release_name_response, 222 release_name_timeout_response, 223 (i == (namerec->data.num_ips - 1)) ? success_fn : NULL, 224 (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL, 225 (i == (namerec->data.num_ips - 1)) ? userdata : NULL, 226 &namerec->name, 227 namerec->data.nb_flags, 228 namerec->data.ip[i]) == NULL) 229 { 230 DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n", 231 nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) )); 232 return True; 233 } 234 } 235 return False; 236} 237