• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/nmbd/
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