Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : NBT netbios routines and daemon - version 2
4 : Copyright (C) Andrew Tridgell 1994-1998
5 : Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6 : Copyright (C) Jeremy Allison 1994-2003
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 : This file contains all the code to process NetBIOS requests coming
22 : in on port 137. It does not deal with the code needed to service
23 : WINS server requests, but only broadcast and unicast requests.
24 :
25 : */
26 :
27 : #include "includes.h"
28 : #include "nmbd/nmbd.h"
29 :
30 : /****************************************************************************
31 : Send a name release response.
32 : **************************************************************************/
33 :
34 0 : static void send_name_release_response(int rcode, struct packet_struct *p)
35 : {
36 0 : struct nmb_packet *nmb = &p->packet.nmb;
37 : char rdata[6];
38 :
39 0 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
40 :
41 0 : reply_netbios_packet(p, /* Packet to reply to. */
42 : rcode, /* Result code. */
43 : NMB_REL, /* nmbd type code. */
44 : NMB_NAME_RELEASE_OPCODE, /* opcode. */
45 : 0, /* ttl. */
46 : rdata, /* data to send. */
47 : 6); /* data length. */
48 0 : }
49 :
50 : /****************************************************************************
51 : Process a name release packet on a broadcast subnet.
52 : Ignore it if it's not one of our names.
53 : ****************************************************************************/
54 :
55 0 : void process_name_release_request(struct subnet_record *subrec,
56 : struct packet_struct *p)
57 : {
58 0 : struct nmb_packet *nmb = &p->packet.nmb;
59 : struct in_addr owner_ip;
60 0 : struct nmb_name *question = &nmb->question.question_name;
61 : unstring qname;
62 0 : bool bcast = nmb->header.nm_flags.bcast;
63 0 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
64 0 : bool group = (nb_flags & NB_GROUP) ? True : False;
65 : struct name_record *namerec;
66 0 : int rcode = 0;
67 :
68 0 : putip((char *)&owner_ip,&nmb->additional->rdata[2]);
69 :
70 0 : if(!bcast) {
71 : /* We should only get broadcast name release packets here.
72 : Anyone trying to release unicast should be going to a WINS
73 : server. If the code gets here, then either we are not a wins
74 : server and they sent it anyway, or we are a WINS server and
75 : the request was malformed. Either way, log an error here.
76 : and send an error reply back.
77 : */
78 0 : DEBUG(0,("process_name_release_request: unicast name release request \
79 : received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
80 : nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
81 :
82 0 : send_name_release_response(FMT_ERR, p);
83 0 : return;
84 : }
85 :
86 0 : DEBUG(3,("process_name_release_request: Name release on name %s, \
87 : subnet %s from owner IP %s\n",
88 : nmb_namestr(&nmb->question.question_name),
89 : subrec->subnet_name, inet_ntoa(owner_ip)));
90 :
91 : /* If someone is releasing a broadcast group name, just ignore it. */
92 0 : if( group && !ismyip_v4(owner_ip) )
93 0 : return;
94 :
95 : /*
96 : * Code to work around a bug in FTP OnNet software NBT implementation.
97 : * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
98 : * names and *don't set the group bit* !!!!!
99 : */
100 :
101 0 : pull_ascii_nstring(qname, sizeof(qname), question->name);
102 0 : if( !group && !ismyip_v4(owner_ip) && strequal(qname, lp_workgroup()) &&
103 0 : ((question->name_type == 0x0) || (question->name_type == 0x1e))) {
104 0 : DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
105 : group release name %s from IP %s on subnet %s with no group bit set.\n",
106 : nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
107 0 : return;
108 : }
109 :
110 0 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
111 :
112 : /* We only care about someone trying to release one of our names. */
113 0 : if( namerec && ( (namerec->data.source == SELF_NAME)
114 0 : || (namerec->data.source == PERMANENT_NAME) ) ) {
115 0 : rcode = ACT_ERR;
116 0 : DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
117 : on subnet %s being rejected as it is one of our names.\n",
118 : nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
119 : }
120 :
121 0 : if(rcode == 0)
122 0 : return;
123 :
124 : /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
125 0 : send_name_release_response(rcode, p);
126 : }
127 :
128 : /****************************************************************************
129 : Send a name registration response.
130 : **************************************************************************/
131 :
132 0 : static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
133 : {
134 0 : struct nmb_packet *nmb = &p->packet.nmb;
135 : char rdata[6];
136 :
137 0 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
138 :
139 0 : reply_netbios_packet(p, /* Packet to reply to. */
140 : rcode, /* Result code. */
141 : NMB_REG, /* nmbd type code. */
142 : NMB_NAME_REG_OPCODE, /* opcode. */
143 : ttl, /* ttl. */
144 : rdata, /* data to send. */
145 : 6); /* data length. */
146 0 : }
147 :
148 : /****************************************************************************
149 : Process a name refresh request on a broadcast subnet.
150 : **************************************************************************/
151 :
152 0 : void process_name_refresh_request(struct subnet_record *subrec,
153 : struct packet_struct *p)
154 : {
155 0 : struct nmb_packet *nmb = &p->packet.nmb;
156 0 : struct nmb_name *question = &nmb->question.question_name;
157 0 : bool bcast = nmb->header.nm_flags.bcast;
158 : struct in_addr from_ip;
159 :
160 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
161 :
162 0 : if(!bcast) {
163 : /* We should only get broadcast name refresh packets here.
164 : Anyone trying to refresh unicast should be going to a WINS
165 : server. If the code gets here, then either we are not a wins
166 : server and they sent it anyway, or we are a WINS server and
167 : the request was malformed. Either way, log an error here.
168 : and send an error reply back.
169 : */
170 0 : DEBUG(0,("process_name_refresh_request: unicast name registration request \
171 : received for name %s from IP %s on subnet %s.\n",
172 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
173 0 : DEBUG(0,("Error - should be sent to WINS server\n"));
174 :
175 0 : send_name_registration_response(FMT_ERR, 0, p);
176 0 : return;
177 : }
178 :
179 : /* Just log a message. We really don't care about broadcast name refreshes. */
180 :
181 0 : DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
182 : IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
183 : }
184 :
185 : /****************************************************************************
186 : Process a name registration request on a broadcast subnet.
187 : **************************************************************************/
188 :
189 1425 : void process_name_registration_request(struct subnet_record *subrec,
190 : struct packet_struct *p)
191 : {
192 1425 : struct nmb_packet *nmb = &p->packet.nmb;
193 1425 : struct nmb_name *question = &nmb->question.question_name;
194 1425 : bool bcast = nmb->header.nm_flags.bcast;
195 1425 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
196 1425 : bool group = (nb_flags & NB_GROUP) ? True : False;
197 1425 : struct name_record *namerec = NULL;
198 1425 : int ttl = nmb->additional->ttl;
199 : struct in_addr from_ip;
200 :
201 1425 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
202 :
203 1425 : if(!bcast) {
204 : /* We should only get broadcast name registration packets here.
205 : Anyone trying to register unicast should be going to a WINS
206 : server. If the code gets here, then either we are not a wins
207 : server and they sent it anyway, or we are a WINS server and
208 : the request was malformed. Either way, log an error here.
209 : and send an error reply back.
210 : */
211 0 : DEBUG(0,("process_name_registration_request: unicast name registration request \
212 : received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
213 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
214 :
215 0 : send_name_registration_response(FMT_ERR, 0, p);
216 0 : return;
217 : }
218 :
219 1425 : DEBUG(3,("process_name_registration_request: Name registration for name %s \
220 : IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
221 :
222 : /* See if the name already exists. */
223 1425 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
224 :
225 : /*
226 : * If the name being registered exists and is a WINS_PROXY_NAME
227 : * then delete the WINS proxy name entry so we don't reply erroneously
228 : * later to queries.
229 : */
230 :
231 1425 : if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
232 0 : remove_name_from_namelist( subrec, namerec );
233 0 : namerec = NULL;
234 : }
235 :
236 1425 : if (!group) {
237 : /* Unique name. */
238 :
239 878 : if( (namerec != NULL)
240 0 : && ( (namerec->data.source == SELF_NAME)
241 0 : || (namerec->data.source == PERMANENT_NAME)
242 0 : || NAME_GROUP(namerec) ) ) {
243 : /* No-one can register one of Samba's names, nor can they
244 : register a name that's a group name as a unique name */
245 :
246 0 : send_name_registration_response(ACT_ERR, 0, p);
247 0 : return;
248 878 : } else if(namerec != NULL) {
249 : /* Update the namelist record with the new information. */
250 0 : namerec->data.ip[0] = from_ip;
251 0 : update_name_ttl(namerec, ttl);
252 :
253 0 : DEBUG(3,("process_name_registration_request: Updated name record %s \
254 : with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
255 0 : return;
256 : }
257 : } else {
258 : /* Group name. */
259 :
260 547 : if( (namerec != NULL)
261 140 : && !NAME_GROUP(namerec)
262 0 : && ( (namerec->data.source == SELF_NAME)
263 0 : || (namerec->data.source == PERMANENT_NAME) ) ) {
264 : /* Disallow group names when we have a unique name. */
265 0 : send_name_registration_response(ACT_ERR, 0, p);
266 0 : return;
267 : }
268 : }
269 : }
270 :
271 : /****************************************************************************
272 : This is used to sort names for a name status into a sensible order.
273 : We put our own names first, then in alphabetical order.
274 : **************************************************************************/
275 :
276 592 : static int status_compare(char *n1,char *n2)
277 : {
278 : unstring name1, name2;
279 : int l1,l2,l3;
280 :
281 592 : memset(name1, '\0', sizeof(name1));
282 592 : memset(name2, '\0', sizeof(name2));
283 592 : pull_ascii_nstring(name1, sizeof(name1), n1);
284 592 : pull_ascii_nstring(name2, sizeof(name2), n2);
285 592 : n1 = name1;
286 592 : n2 = name2;
287 :
288 : /* It's a bit tricky because the names are space padded */
289 2471 : for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++)
290 : ;
291 2082 : for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++)
292 : ;
293 592 : l3 = strlen(lp_netbios_name());
294 :
295 592 : if ((l1==l3) && strncmp(n1,lp_netbios_name(),l3) == 0 &&
296 48 : (l2!=l3 || strncmp(n2,lp_netbios_name(),l3) != 0))
297 86 : return -1;
298 :
299 506 : if ((l2==l3) && strncmp(n2,lp_netbios_name(),l3) == 0 &&
300 48 : (l1!=l3 || strncmp(n1,lp_netbios_name(),l3) != 0))
301 42 : return 1;
302 :
303 464 : return memcmp(n1,n2,sizeof(name1));
304 : }
305 :
306 : /****************************************************************************
307 : Process a node status query
308 : ****************************************************************************/
309 :
310 4 : void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
311 : {
312 4 : struct nmb_packet *nmb = &p->packet.nmb;
313 : unstring qname;
314 4 : int ques_type = nmb->question.question_name.name_type;
315 : char rdata[MAX_DGRAM_SIZE];
316 : char *countptr, *buf, *bufend, *buf0;
317 : int names_added,i;
318 4 : struct name_record *namerec = NULL;
319 :
320 4 : pull_ascii_nstring(qname, sizeof(qname), nmb->question.question_name.name);
321 :
322 4 : DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
323 : subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
324 :
325 4 : if(find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME) == 0) {
326 0 : DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
327 : subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
328 : inet_ntoa(p->ip), subrec->subnet_name));
329 :
330 0 : return;
331 : }
332 :
333 : /* this is not an exact calculation. the 46 is for the stats buffer
334 : and the 60 is to leave room for the header etc */
335 4 : bufend = &rdata[MAX_DGRAM_SIZE-1] - (18 + 46 + 60);
336 4 : countptr = buf = rdata;
337 4 : buf += 1;
338 4 : buf0 = buf;
339 :
340 4 : names_added = 0;
341 :
342 4 : namerec = subrec->namelist;
343 :
344 59 : while (PTR_DIFF(bufend, buf) > 0) {
345 56 : if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
346 56 : int name_type = namerec->name.name_type;
347 : unstring name;
348 :
349 56 : pull_ascii_nstring(name, sizeof(name), namerec->name.name);
350 56 : if (!strupper_m(name)) {
351 0 : DEBUG(2,("strupper_m %s failed\n", name));
352 0 : return;
353 : }
354 89 : if (!strequal(name,"*") &&
355 75 : !strequal(name,"__SAMBA__") &&
356 18 : (name_type < 0x1b || name_type >= 0x20 ||
357 12 : ques_type < 0x1b || ques_type >= 0x20 ||
358 6 : strequal(qname, name))) {
359 : /* Start with the name. */
360 : size_t len;
361 40 : push_ascii_nstring(buf, name);
362 40 : len = strlen(buf);
363 40 : memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - len - 1);
364 40 : buf[MAX_NETBIOSNAME_LEN - 1] = '\0';
365 :
366 : /* Put the name type and netbios flags in the buffer. */
367 :
368 40 : buf[15] = name_type;
369 40 : set_nb_flags( &buf[16],namerec->data.nb_flags );
370 40 : buf[16] |= NB_ACTIVE; /* all our names are active */
371 :
372 40 : buf += 18;
373 :
374 40 : names_added++;
375 : }
376 : }
377 :
378 : /* Remove duplicate names. */
379 56 : if (names_added > 1) {
380 : /* TODO: should use a real type and
381 : TYPESAFE_QSORT() */
382 52 : qsort( buf0, names_added, 18, QSORT_CAST status_compare );
383 : }
384 :
385 398 : for( i=1; i < names_added ; i++ ) {
386 342 : if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
387 0 : names_added--;
388 0 : if (names_added == i)
389 0 : break;
390 0 : memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
391 0 : i--;
392 : }
393 : }
394 :
395 56 : buf = buf0 + 18*names_added;
396 :
397 56 : namerec = namerec->next;
398 :
399 56 : if (!namerec) {
400 : /* End of the subnet specific name list. Now
401 : add the names on the unicast subnet . */
402 4 : struct subnet_record *uni_subrec = unicast_subnet;
403 :
404 4 : if (uni_subrec != subrec) {
405 0 : subrec = uni_subrec;
406 0 : namerec = subrec->namelist;
407 : }
408 : }
409 56 : if (!namerec)
410 4 : break;
411 :
412 : }
413 :
414 4 : SCVAL(countptr,0,names_added);
415 :
416 : /* We don't send any stats as they could be used to attack
417 : the protocol. */
418 4 : memset(buf,'\0',46);
419 :
420 4 : buf += 46;
421 :
422 : /* Send a NODE STATUS RESPONSE */
423 4 : reply_netbios_packet(p, /* Packet to reply to. */
424 : 0, /* Result code. */
425 : NMB_STATUS, /* nmbd type code. */
426 : NMB_NAME_QUERY_OPCODE, /* opcode. */
427 : 0, /* ttl. */
428 : rdata, /* data to send. */
429 4 : PTR_DIFF(buf,rdata)); /* data length. */
430 : }
431 :
432 :
433 : /***************************************************************************
434 : Process a name query.
435 :
436 : For broadcast name queries:
437 :
438 : - Only reply if the query is for one of YOUR names.
439 : - NEVER send a negative response to a broadcast query.
440 :
441 : ****************************************************************************/
442 :
443 1276 : void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
444 : {
445 1276 : struct nmb_packet *nmb = &p->packet.nmb;
446 1276 : struct nmb_name *question = &nmb->question.question_name;
447 1276 : int name_type = question->name_type;
448 1276 : bool bcast = nmb->header.nm_flags.bcast;
449 1276 : int ttl=0;
450 1276 : int rcode = 0;
451 1276 : char *prdata = NULL;
452 : char rdata[6];
453 1276 : bool success = False;
454 1276 : struct name_record *namerec = NULL;
455 1276 : int reply_data_len = 0;
456 : int i;
457 :
458 1276 : DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
459 : inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
460 :
461 : /* Look up the name in the cache - if the request is a broadcast request that
462 : came from a subnet we don't know about then search all the broadcast subnets
463 : for a match (as we don't know what interface the request came in on). */
464 :
465 1276 : if(subrec == remote_broadcast_subnet)
466 0 : namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
467 : else
468 1276 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
469 :
470 : /* Check if it is a name that expired */
471 1441 : if (namerec &&
472 262 : ((namerec->data.death_time != PERMANENT_TTL) &&
473 0 : (namerec->data.death_time < p->timestamp))) {
474 0 : DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
475 0 : namerec = NULL;
476 : }
477 :
478 1276 : if (namerec) {
479 : /*
480 : * Always respond to unicast queries.
481 : * Don't respond to broadcast queries unless the query is for
482 : * a name we own, a Primary Domain Controller name, or a WINS_PROXY
483 : * name with type 0 or 0x20. WINS_PROXY names are only ever added
484 : * into the namelist if we were configured as a WINS proxy.
485 : */
486 :
487 262 : if (!bcast ||
488 244 : (bcast && ((name_type == 0x1b) ||
489 195 : (namerec->data.source == SELF_NAME) ||
490 64 : (namerec->data.source == PERMANENT_NAME) ||
491 0 : ((namerec->data.source == WINS_PROXY_NAME) &&
492 0 : ((name_type == 0) || (name_type == 0x20)))))) {
493 : /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
494 : or it's a Domain Master type. */
495 :
496 : /*
497 : * If this is a WINS_PROXY_NAME, then ceck that none of the IP
498 : * addresses we are returning is on the same broadcast subnet
499 : * as the requesting packet. If it is then don't reply as the
500 : * actual machine will be replying also and we don't want two
501 : * replies to a broadcast query.
502 : */
503 :
504 262 : if (namerec->data.source == WINS_PROXY_NAME) {
505 0 : for( i = 0; i < namerec->data.num_ips; i++) {
506 0 : if (same_net_v4(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
507 0 : DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n",
508 : nmb_namestr(&namerec->name), subrec->subnet_name ));
509 1014 : return;
510 : }
511 : }
512 : }
513 :
514 262 : ttl = (namerec->data.death_time != PERMANENT_TTL) ?
515 97 : namerec->data.death_time - p->timestamp : lp_max_ttl();
516 :
517 : /* Copy all known ip addresses into the return data. */
518 : /* Optimise for the common case of one IP address so
519 : we don't need a malloc. */
520 :
521 262 : if (namerec->data.num_ips == 1) {
522 262 : prdata = rdata;
523 : } else {
524 0 : if ((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
525 0 : DEBUG(0,("process_name_query_request: malloc fail !\n"));
526 0 : return;
527 : }
528 : }
529 :
530 524 : for (i = 0; i < namerec->data.num_ips; i++) {
531 262 : set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
532 262 : putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
533 : }
534 :
535 262 : sort_query_replies(prdata, i, p->ip);
536 :
537 262 : reply_data_len = namerec->data.num_ips * 6;
538 262 : success = True;
539 : }
540 : }
541 :
542 : /*
543 : * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
544 : * set we should initiate a WINS query here. On success we add the resolved name
545 : * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
546 : */
547 :
548 1276 : if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
549 0 : bcast && (subrec != remote_broadcast_subnet)) {
550 0 : make_wins_proxy_name_query_request( subrec, p, question );
551 0 : return;
552 : }
553 :
554 1276 : if (!success && bcast) {
555 1014 : if(prdata != rdata)
556 1014 : SAFE_FREE(prdata);
557 1014 : return; /* Never reply with a negative response to broadcasts. */
558 : }
559 :
560 : /*
561 : * Final check. From observation, if a unicast packet is sent
562 : * to a non-WINS server with the recursion desired bit set
563 : * then never send a negative response.
564 : */
565 :
566 262 : if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
567 0 : if(prdata != rdata)
568 0 : SAFE_FREE(prdata);
569 0 : return;
570 : }
571 :
572 262 : if (success) {
573 262 : rcode = 0;
574 262 : DEBUG(3,("OK\n"));
575 : } else {
576 0 : rcode = NAM_ERR;
577 0 : DEBUG(3,("UNKNOWN\n"));
578 : }
579 :
580 : /* See rfc1002.txt 4.2.13. */
581 :
582 262 : reply_netbios_packet(p, /* Packet to reply to. */
583 : rcode, /* Result code. */
584 : NMB_QUERY, /* nmbd type code. */
585 : NMB_NAME_QUERY_OPCODE, /* opcode. */
586 : ttl, /* ttl. */
587 : prdata, /* data to send. */
588 : reply_data_len); /* data length. */
589 :
590 262 : if(prdata != rdata)
591 0 : SAFE_FREE(prdata);
592 : }
|