Home | History | Annotate | Download | only in smb
      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