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 183 : static void add_response_record(struct subnet_record *subrec,
33 : struct response_record *rrec)
34 : {
35 183 : num_response_packets++; /* count of total number of packets still around */
36 :
37 183 : 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 183 : DLIST_ADD_END(subrec->responselist, rrec);
41 183 : }
42 :
43 : /***************************************************************************
44 : Remove an expected response record from the list
45 : **************************************************************************/
46 :
47 181 : 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 inderect into rrec, search for it
53 : on the responselist first. Bug #3617. JRA. */
54 :
55 181 : struct response_record *p = NULL;
56 :
57 216 : for (p = subrec->responselist; p; p = p->next) {
58 216 : if (p == rrec) {
59 181 : break;
60 : }
61 : }
62 :
63 181 : if (p == NULL) {
64 : /* We didn't find rrec on the list. */
65 0 : return;
66 : }
67 :
68 181 : DLIST_REMOVE(subrec->responselist, rrec);
69 :
70 181 : if(rrec->userdata) {
71 12 : if(rrec->userdata->free_fn) {
72 0 : (*rrec->userdata->free_fn)(rrec->userdata);
73 : } else {
74 12 : ZERO_STRUCTP(rrec->userdata);
75 12 : SAFE_FREE(rrec->userdata);
76 : }
77 : }
78 :
79 : /* Ensure we can delete. */
80 181 : rrec->packet->locked = False;
81 181 : free_packet(rrec->packet);
82 :
83 181 : ZERO_STRUCTP(rrec);
84 181 : SAFE_FREE(rrec);
85 :
86 181 : 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 183 : 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 183 : struct nmb_packet *nmb = &p->packet.nmb;
103 :
104 183 : 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 183 : memset((char *)rrec, '\0', sizeof(*rrec));
110 :
111 183 : rrec->response_id = nmb->header.name_trn_id;
112 :
113 183 : rrec->resp_fn = resp_fn;
114 183 : rrec->timeout_fn = timeout_fn;
115 183 : rrec->success_fn = success_fn;
116 183 : rrec->fail_fn = fail_fn;
117 :
118 183 : rrec->packet = p;
119 :
120 183 : if(userdata) {
121 : /* Intelligent userdata. */
122 13 : 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 13 : if((rrec->userdata = (struct userdata_struct *)
132 13 : 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 13 : rrec->userdata->copy_fn = userdata->copy_fn;
139 13 : rrec->userdata->free_fn = userdata->free_fn;
140 13 : rrec->userdata->userdata_len = userdata->userdata_len;
141 13 : memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
142 : }
143 : } else {
144 170 : rrec->userdata = NULL;
145 : }
146 :
147 183 : rrec->num_msgs = 0;
148 :
149 183 : if(!nmb->header.nm_flags.bcast)
150 0 : rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
151 : else
152 183 : rrec->repeat_interval = 1; /* XXXX should be in ms */
153 183 : rrec->repeat_count = 3; /* 3 retries */
154 183 : rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
155 :
156 : /* This packet is not being processed. */
157 183 : rrec->in_expiration_processing = False;
158 :
159 : /* Lock the packet so we won't lose it while it's on the list. */
160 183 : p->locked = True;
161 :
162 183 : add_response_record(subrec, rrec);
163 :
164 183 : return rrec;
165 : }
166 :
167 : /****************************************************************************
168 : Find a response in a subnet's name query response list.
169 : **************************************************************************/
170 :
171 9 : static struct response_record *find_response_record_on_subnet(
172 : struct subnet_record *subrec, uint16_t id)
173 : {
174 9 : struct response_record *rrec = NULL;
175 :
176 44 : for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
177 44 : if (rrec->response_id == id) {
178 9 : DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
179 : id, subrec->subnet_name));
180 9 : break;
181 : }
182 : }
183 9 : return rrec;
184 : }
185 :
186 : /****************************************************************************
187 : Find a response in any subnet's name query response list.
188 : **************************************************************************/
189 :
190 9 : struct response_record *find_response_record(struct subnet_record **ppsubrec,
191 : uint16_t id)
192 : {
193 9 : struct response_record *rrec = NULL;
194 :
195 14 : for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec);
196 0 : (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) {
197 9 : if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
198 9 : 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 0 : 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 0 : 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 0 : DEBUG(3,("find_response_record: response packet id %hu received with no \
216 : matching record.\n", id));
217 :
218 0 : *ppsubrec = NULL;
219 :
220 0 : 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 : }
|