xref: /illumos-gate/usr/src/lib/libsmbfs/smb/nbns_rq.c (revision a547be5d)
1 /*
2  * Copyright (c) 2000, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
33  */
34 
35 /*
36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42 #include <ctype.h>
43 #include <netdb.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <stdio.h>
49 #include <unistd.h>
50 #include <libintl.h>
51 
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <tsol/label.h>
55 
56 #define	NB_NEEDRESOLVER
57 #include <netsmb/netbios.h>
58 #include <netsmb/smb_lib.h>
59 #include <netsmb/nb_lib.h>
60 #include <netsmb/mchain.h>
61 
62 #include "charsets.h"
63 #include "private.h"
64 
65 /*
66  * nbns request
67  */
68 struct nbns_rq {
69 	int		nr_opcode;
70 	int		nr_nmflags;
71 	int		nr_rcode;
72 	int		nr_qdcount;
73 	int		nr_ancount;
74 	int		nr_nscount;
75 	int		nr_arcount;
76 	struct nb_name	*nr_qdname;
77 	uint16_t	nr_qdtype;
78 	uint16_t	nr_qdclass;
79 	struct in_addr	nr_dest;	/* receiver of query */
80 	struct sockaddr_in nr_sender;	/* sender of response */
81 	int		nr_rpnmflags;
82 	int		nr_rprcode;
83 	uint16_t	nr_rpancount;
84 	uint16_t	nr_rpnscount;
85 	uint16_t	nr_rparcount;
86 	uint16_t	nr_trnid;
87 	struct nb_ctx	*nr_nbd;
88 	struct mbdata	nr_rq;
89 	struct mbdata	nr_rp;
90 	struct nb_ifdesc *nr_if;
91 	int		nr_flags;
92 	int		nr_fd;
93 	int		nr_maxretry;
94 };
95 typedef struct nbns_rq nbns_rq_t;
96 
97 static int  nbns_rq_create(int opcode, struct nb_ctx *ctx,
98     struct nbns_rq **rqpp);
99 static void nbns_rq_done(struct nbns_rq *rqp);
100 static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
101 static int  nbns_rq_prepare(struct nbns_rq *rqp);
102 static int  nbns_rq(struct nbns_rq *rqp);
103 
104 /*
105  * Call NetBIOS name lookup and return a result in the
106  * same form as getaddrinfo(3) returns.  Return code is
107  * zero or one of the EAI_xxx codes like getaddrinfo.
108  */
109 int
nbns_getaddrinfo(const char * name,struct nb_ctx * nbc,struct addrinfo ** res)110 nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
111 {
112 	struct addrinfo *nai = NULL;
113 	struct sockaddr *sap = NULL;
114 	char *ucname = NULL;
115 	int err;
116 
117 	/*
118 	 * Try NetBIOS name lookup.
119 	 */
120 	if (strlen(name) >= NB_NAMELEN) {
121 		err = EAI_OVERFLOW;
122 		goto out;
123 	}
124 	ucname = utf8_str_toupper(name);
125 	if (ucname == NULL)
126 		goto nomem;
127 
128 	/* Note: this returns an NBERROR value. */
129 	err = nbns_resolvename(ucname, nbc, &sap);
130 	if (err) {
131 		if (smb_verbose)
132 			smb_error(dgettext(TEXT_DOMAIN,
133 			    "nbns_resolvename: %s"),
134 			    err, name);
135 		err = EAI_NODATA;
136 		goto out;
137 	}
138 	/* Note: sap allocated */
139 
140 	/*
141 	 * Build the addrinfo struct to return.
142 	 */
143 	nai = malloc(sizeof (*nai));
144 	if (nai == NULL)
145 		goto nomem;
146 	bzero(nai, sizeof (*nai));
147 
148 	nai->ai_flags = AI_CANONNAME;
149 	nai->ai_family = sap->sa_family;
150 	nai->ai_socktype = SOCK_STREAM;
151 	nai->ai_canonname = ucname;
152 	ucname = NULL;
153 
154 	/*
155 	 * The type of this is really sockaddr_in,
156 	 * but is returned in the generic form.
157 	 * See nbns_resolvename.
158 	 */
159 	nai->ai_addrlen = sizeof (struct sockaddr_in);
160 	nai->ai_addr = sap;
161 
162 	*res = nai;
163 	return (0);
164 
165 nomem:
166 	err = EAI_MEMORY;
167 out:
168 	if (nai != NULL)
169 		free(nai);
170 	if (sap)
171 		free(sap);
172 	if (ucname)
173 		free(ucname);
174 	*res = NULL;
175 
176 	return (err);
177 }
178 
179 int
nbns_resolvename(const char * name,struct nb_ctx * ctx,struct sockaddr ** adpp)180 nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
181 {
182 	struct nbns_rq *rqp;
183 	struct nb_name nn;
184 	struct nbns_rr rr;
185 	struct sockaddr_in *dest;
186 	int error, rdrcount, len;
187 
188 	if (strlen(name) >= NB_NAMELEN)
189 		return (NBERROR(NBERR_NAMETOOLONG));
190 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
191 	if (error)
192 		return (error);
193 	/*
194 	 * Pad the name with blanks, but
195 	 * leave the "type" byte NULL.
196 	 * nb_name_encode adds the type.
197 	 */
198 	bzero(&nn, sizeof (nn));
199 	snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
200 	nn.nn_type = NBT_SERVER;
201 	nn.nn_scope = ctx->nb_scope;
202 	rqp->nr_nmflags = NBNS_NMFLAG_RD;
203 	rqp->nr_qdname = &nn;
204 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
205 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
206 	rqp->nr_qdcount = 1;
207 	rqp->nr_maxretry = 5;
208 
209 	error = nbns_rq_prepare(rqp);
210 	if (error) {
211 		nbns_rq_done(rqp);
212 		return (error);
213 	}
214 	rdrcount = NBNS_MAXREDIRECTS;
215 	for (;;) {
216 		error = nbns_rq(rqp);
217 		if (error)
218 			break;
219 		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
220 			/*
221 			 * Not an authoritative answer.  Query again
222 			 * using the NS address in the 2nd record.
223 			 */
224 			if (rdrcount-- == 0) {
225 				error = NBERROR(NBERR_TOOMANYREDIRECTS);
226 				break;
227 			}
228 			error = nbns_rq_getrr(rqp, &rr);
229 			if (error)
230 				break;
231 			error = nbns_rq_getrr(rqp, &rr);
232 			if (error)
233 				break;
234 			bcopy(rr.rr_data, &rqp->nr_dest, 4);
235 			continue;
236 		}
237 		if (rqp->nr_rpancount == 0) {
238 			error = NBERROR(NBERR_HOSTNOTFOUND);
239 			break;
240 		}
241 		error = nbns_rq_getrr(rqp, &rr);
242 		if (error)
243 			break;
244 		len = sizeof (struct sockaddr_in);
245 		dest = malloc(len);
246 		if (dest == NULL)
247 			return (ENOMEM);
248 		bzero(dest, len);
249 		/*
250 		 * Solaris sockaddr_in doesn't a sin_len field.
251 		 * dest->sin_len = len;
252 		 */
253 		dest->sin_family = AF_NETBIOS;	/* nb_lib.h */
254 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
255 		*adpp = (struct sockaddr *)dest;
256 		ctx->nb_lastns = rqp->nr_sender;
257 		break;
258 	}
259 	nbns_rq_done(rqp);
260 	return (error);
261 }
262 
263 /*
264  * NB: system, workgroup are both NB_NAMELEN
265  */
266 int
nbns_getnodestatus(struct nb_ctx * ctx,struct in_addr * targethost,char * system,char * workgroup)267 nbns_getnodestatus(struct nb_ctx *ctx,
268     struct in_addr *targethost, char *system, char *workgroup)
269 {
270 	struct nbns_rq *rqp;
271 	struct nbns_rr rr;
272 	struct nb_name nn;
273 	struct nbns_nr *nrp;
274 	char nrtype;
275 	char *cp, *retname = NULL;
276 	unsigned char nrcount;
277 	int error, i, foundserver = 0, foundgroup = 0;
278 
279 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
280 	if (error)
281 		return (error);
282 	bzero(&nn, sizeof (nn));
283 	strcpy((char *)nn.nn_name, "*");
284 	nn.nn_scope = ctx->nb_scope;
285 	nn.nn_type = NBT_WKSTA;
286 	rqp->nr_nmflags = 0;
287 	rqp->nr_qdname = &nn;
288 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
289 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
290 	rqp->nr_qdcount = 1;
291 	rqp->nr_maxretry = 2;
292 
293 	rqp->nr_dest = *targethost;
294 	error = nbns_rq_prepare(rqp);
295 	if (error) {
296 		nbns_rq_done(rqp);
297 		return (error);
298 	}
299 
300 	/*
301 	 * Darwin had a loop here, allowing redirect, etc.
302 	 * but we only handle point-to-point for node status.
303 	 */
304 	error = nbns_rq(rqp);
305 	if (error)
306 		goto out;
307 	if (rqp->nr_rpancount == 0) {
308 		error = NBERROR(NBERR_HOSTNOTFOUND);
309 		goto out;
310 	}
311 	error = nbns_rq_getrr(rqp, &rr);
312 	if (error)
313 		goto out;
314 
315 	/* Compiler didn't like cast on lvalue++ */
316 	nrcount = *((unsigned char *)rr.rr_data);
317 	rr.rr_data++;
318 	/* LINTED */
319 	for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
320 	    i <= nrcount; ++i, ++nrp) {
321 		nrtype = nrp->ns_name[NB_NAMELEN-1];
322 		/* Terminate the string: */
323 		nrp->ns_name[NB_NAMELEN-1] = (char)0;
324 		/* Strip off trailing spaces */
325 		for (cp = &nrp->ns_name[NB_NAMELEN-2];
326 		    cp >= nrp->ns_name; --cp) {
327 			if (*cp != (char)0x20)
328 				break;
329 			*cp = (char)0;
330 		}
331 		nrp->ns_flags = ntohs(nrp->ns_flags);
332 		DPRINT(" %s[%02x] Flags 0x%x",
333 		    nrp->ns_name, nrtype, nrp->ns_flags);
334 		if (nrp->ns_flags & NBNS_GROUPFLG) {
335 			if (!foundgroup ||
336 			    (foundgroup != NBT_WKSTA+1 &&
337 			    nrtype == NBT_WKSTA)) {
338 				strlcpy(workgroup, nrp->ns_name,
339 				    NB_NAMELEN);
340 				foundgroup = nrtype+1;
341 			}
342 		} else {
343 			/*
344 			 * Track at least ONE name, in case
345 			 * no server name is found
346 			 */
347 			retname = nrp->ns_name;
348 		}
349 		/*
350 		 * Keep the first NBT_SERVER name.
351 		 */
352 		if (nrtype == NBT_SERVER && foundserver == 0) {
353 			strlcpy(system, nrp->ns_name,
354 			    NB_NAMELEN);
355 			foundserver = 1;
356 		}
357 	}
358 	if (foundserver == 0 && retname != NULL)
359 		strlcpy(system, retname, NB_NAMELEN);
360 	ctx->nb_lastns = rqp->nr_sender;
361 
362 out:
363 	nbns_rq_done(rqp);
364 	return (error);
365 }
366 
367 int
nbns_rq_create(int opcode,struct nb_ctx * ctx,struct nbns_rq ** rqpp)368 nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
369 {
370 	struct nbns_rq *rqp;
371 	static uint16_t trnid;
372 	int error;
373 
374 	if (trnid == 0)
375 		trnid = getpid();
376 	rqp = malloc(sizeof (*rqp));
377 	if (rqp == NULL)
378 		return (ENOMEM);
379 	bzero(rqp, sizeof (*rqp));
380 	error = mb_init_sz(&rqp->nr_rq, NBDG_MAXSIZE);
381 	if (error) {
382 		free(rqp);
383 		return (error);
384 	}
385 	rqp->nr_opcode = opcode;
386 	rqp->nr_nbd = ctx;
387 	rqp->nr_trnid = trnid++;
388 	*rqpp = rqp;
389 	return (0);
390 }
391 
392 void
nbns_rq_done(struct nbns_rq * rqp)393 nbns_rq_done(struct nbns_rq *rqp)
394 {
395 	if (rqp == NULL)
396 		return;
397 	if (rqp->nr_fd >= 0)
398 		close(rqp->nr_fd);
399 	mb_done(&rqp->nr_rq);
400 	mb_done(&rqp->nr_rp);
401 	if (rqp->nr_if)
402 		free(rqp->nr_if);
403 	free(rqp);
404 }
405 
406 /*
407  * Extract resource record from the packet. Assume that there is only
408  * one mbuf.
409  */
410 int
nbns_rq_getrr(struct nbns_rq * rqp,struct nbns_rr * rrp)411 nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
412 {
413 	struct mbdata *mbp = &rqp->nr_rp;
414 	uchar_t *cp;
415 	int error, len;
416 
417 	bzero(rrp, sizeof (*rrp));
418 	cp = (uchar_t *)mbp->mb_pos;
419 	len = nb_encname_len(cp);
420 	if (len < 1)
421 		return (NBERROR(NBERR_INVALIDRESPONSE));
422 	rrp->rr_name = cp;
423 	error = md_get_mem(mbp, NULL, len, MB_MSYSTEM);
424 	if (error)
425 		return (error);
426 	md_get_uint16be(mbp, &rrp->rr_type);
427 	md_get_uint16be(mbp, &rrp->rr_class);
428 	md_get_uint32be(mbp, &rrp->rr_ttl);
429 	md_get_uint16be(mbp, &rrp->rr_rdlength);
430 	rrp->rr_data = (uchar_t *)mbp->mb_pos;
431 	error = md_get_mem(mbp, NULL, rrp->rr_rdlength, MB_MSYSTEM);
432 	return (error);
433 }
434 
435 int
nbns_rq_prepare(struct nbns_rq * rqp)436 nbns_rq_prepare(struct nbns_rq *rqp)
437 {
438 	struct nb_ctx *ctx = rqp->nr_nbd;
439 	struct mbdata *mbp = &rqp->nr_rq;
440 	uint16_t ofr; /* opcode, flags, rcode */
441 	int error;
442 
443 	error = mb_init_sz(&rqp->nr_rp, NBDG_MAXSIZE);
444 	if (error)
445 		return (error);
446 
447 	/*
448 	 * When looked into the ethereal trace, 'nmblookup' command sets this
449 	 * flag. We will also set.
450 	 */
451 	mb_put_uint16be(mbp, rqp->nr_trnid);
452 	ofr = ((rqp->nr_opcode & 0x1F) << 11) |
453 	    ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
454 	mb_put_uint16be(mbp, ofr);
455 	mb_put_uint16be(mbp, rqp->nr_qdcount);
456 	mb_put_uint16be(mbp, rqp->nr_ancount);
457 	mb_put_uint16be(mbp, rqp->nr_nscount);
458 	error = mb_put_uint16be(mbp, rqp->nr_arcount);
459 	if (rqp->nr_qdcount) {
460 		if (rqp->nr_qdcount > 1)
461 			return (EINVAL);
462 		(void) nb_name_encode(mbp, rqp->nr_qdname);
463 		mb_put_uint16be(mbp, rqp->nr_qdtype);
464 		error = mb_put_uint16be(mbp, rqp->nr_qdclass);
465 	}
466 	if (error)
467 		return (error);
468 	error = m_lineup(mbp->mb_top, &mbp->mb_top);
469 	if (error)
470 		return (error);
471 	if (ctx->nb_timo == 0)
472 		ctx->nb_timo = 1;	/* by default 1 second */
473 	return (0);
474 }
475 
476 static int
nbns_rq_recv(struct nbns_rq * rqp)477 nbns_rq_recv(struct nbns_rq *rqp)
478 {
479 	struct mbdata *mbp = &rqp->nr_rp;
480 	void *rpdata = mtod(mbp->mb_top, void *);
481 	fd_set rd, wr, ex;
482 	struct timeval tv;
483 	struct sockaddr_in sender;
484 	int s = rqp->nr_fd;
485 	int n, len;
486 
487 	FD_ZERO(&rd);
488 	FD_ZERO(&wr);
489 	FD_ZERO(&ex);
490 	FD_SET(s, &rd);
491 
492 	tv.tv_sec = rqp->nr_nbd->nb_timo;
493 	tv.tv_usec = 0;
494 
495 	n = select(s + 1, &rd, &wr, &ex, &tv);
496 	if (n == -1)
497 		return (-1);
498 	if (n == 0)
499 		return (ETIMEDOUT);
500 	if (FD_ISSET(s, &rd) == 0)
501 		return (ETIMEDOUT);
502 	len = sizeof (sender);
503 	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
504 	    (struct sockaddr *)&sender, &len);
505 	if (n < 0)
506 		return (errno);
507 	mbp->mb_top->m_len = mbp->mb_count = n;
508 	rqp->nr_sender = sender;
509 	return (0);
510 }
511 
512 static int
nbns_rq_opensocket(struct nbns_rq * rqp)513 nbns_rq_opensocket(struct nbns_rq *rqp)
514 {
515 	struct sockaddr_in locaddr;
516 	int opt = 1, s;
517 	struct nb_ctx *ctx = rqp->nr_nbd;
518 
519 	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
520 	if (s < 0)
521 		return (errno);
522 	if (ctx->nb_flags & NBCF_BC_ENABLE) {
523 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
524 		    sizeof (opt)) < 0)
525 			return (errno);
526 	}
527 	if (is_system_labeled())
528 		(void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
529 		    sizeof (opt));
530 	bzero(&locaddr, sizeof (locaddr));
531 	locaddr.sin_family = AF_INET;
532 	/* locaddr.sin_len = sizeof (locaddr); */
533 	if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
534 		return (errno);
535 	return (0);
536 }
537 
538 static int
nbns_rq_send(struct nbns_rq * rqp,in_addr_t ina)539 nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
540 {
541 	struct sockaddr_in dest;
542 	struct mbdata *mbp = &rqp->nr_rq;
543 	int s = rqp->nr_fd;
544 	uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
545 	uint16_t *datap;
546 	uint8_t nmflags;
547 	int rc;
548 
549 	bzero(&dest, sizeof (dest));
550 	dest.sin_family = AF_INET;
551 	dest.sin_port = htons(IPPORT_NETBIOS_NS);
552 	dest.sin_addr.s_addr = ina;
553 
554 	if (ina == INADDR_BROADCAST) {
555 		/* Turn on the broadcast bit. */
556 		nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
557 		/*LINTED*/
558 		datap = mtod(mbp->mb_top, uint16_t *);
559 		ofr = ((rqp->nr_opcode & 0x1F) << 11) |
560 		    ((nmflags & 0x7F) << 4); /* rcode=0 */
561 		ofr_save = datap[1];
562 		datap[1] = htons(ofr);
563 	}
564 
565 	rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
566 	    (struct sockaddr *)&dest, sizeof (dest));
567 
568 	if (ina == INADDR_BROADCAST) {
569 		/* Turn the broadcast bit back off. */
570 		datap[1] = ofr_save;
571 	}
572 
573 
574 	if (rc < 0)
575 		return (errno);
576 
577 	return (0);
578 }
579 
580 int
nbns_rq(struct nbns_rq * rqp)581 nbns_rq(struct nbns_rq *rqp)
582 {
583 	struct nb_ctx *ctx = rqp->nr_nbd;
584 	struct mbdata *mbp = &rqp->nr_rq;
585 	uint16_t ofr, rpid;
586 	int error, tries, maxretry;
587 
588 	error = nbns_rq_opensocket(rqp);
589 	if (error)
590 		return (error);
591 
592 	maxretry = rqp->nr_maxretry;
593 	for (tries = 0; tries < maxretry; tries++) {
594 
595 		/*
596 		 * Minor hack: If nr_dest is set, send there only.
597 		 * Used by _getnodestatus, _resolvname redirects.
598 		 */
599 		if (rqp->nr_dest.s_addr) {
600 			error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
601 			if (error) {
602 				smb_error(dgettext(TEXT_DOMAIN,
603 				    "nbns error %d sending to %s"),
604 				    0, error, inet_ntoa(rqp->nr_dest));
605 			}
606 			goto do_recv;
607 		}
608 
609 		if (ctx->nb_wins1) {
610 			error = nbns_rq_send(rqp, ctx->nb_wins1);
611 			if (error) {
612 				smb_error(dgettext(TEXT_DOMAIN,
613 				    "nbns error %d sending to wins1"),
614 				    0, error);
615 			}
616 		}
617 
618 		if (ctx->nb_wins2 && (tries > 0)) {
619 			error = nbns_rq_send(rqp, ctx->nb_wins2);
620 			if (error) {
621 				smb_error(dgettext(TEXT_DOMAIN,
622 				    "nbns error %d sending to wins2"),
623 				    0, error);
624 			}
625 		}
626 
627 		/*
628 		 * If broadcast is enabled, start broadcasting
629 		 * only after wins servers fail to respond, or
630 		 * immediately if no WINS servers configured.
631 		 */
632 		if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
633 		    ((tries > 1) || (ctx->nb_wins1 == 0))) {
634 			error = nbns_rq_send(rqp, INADDR_BROADCAST);
635 			if (error) {
636 				smb_error(dgettext(TEXT_DOMAIN,
637 				    "nbns error %d sending broadcast"),
638 				    0, error);
639 			}
640 		}
641 
642 		/*
643 		 * Wait for responses from ANY of the above.
644 		 */
645 do_recv:
646 		error = nbns_rq_recv(rqp);
647 		if (error == ETIMEDOUT)
648 			continue;
649 		if (error) {
650 			smb_error(dgettext(TEXT_DOMAIN,
651 			    "nbns recv error %d"),
652 			    0, error);
653 			return (error);
654 		}
655 
656 		mbp = &rqp->nr_rp;
657 		if (mbp->mb_count < 12)
658 			return (NBERROR(NBERR_INVALIDRESPONSE));
659 		md_get_uint16be(mbp, &rpid);
660 		if (rpid != rqp->nr_trnid)
661 			return (NBERROR(NBERR_INVALIDRESPONSE));
662 		break;
663 	}
664 	if (tries == maxretry)
665 		return (NBERROR(NBERR_HOSTNOTFOUND));
666 
667 	md_get_uint16be(mbp, &ofr);
668 	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
669 	rqp->nr_rprcode = ofr & 0xf;
670 	if (rqp->nr_rprcode)
671 		return (NBERROR(rqp->nr_rprcode));
672 	md_get_uint16be(mbp, &rpid);	/* QDCOUNT */
673 	md_get_uint16be(mbp, &rqp->nr_rpancount);
674 	md_get_uint16be(mbp, &rqp->nr_rpnscount);
675 	md_get_uint16be(mbp, &rqp->nr_rparcount);
676 	return (0);
677 }
678