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