xref: /freebsd/contrib/smbfs/lib/smb/nbns_rq.c (revision ccbbd187b1b61c3d15a1e830fd598a435442d21a)
1f1b9d127SSheldon Hearn /*
2f1b9d127SSheldon Hearn  * Copyright (c) 2000, Boris Popov
3f1b9d127SSheldon Hearn  * All rights reserved.
4f1b9d127SSheldon Hearn  *
5f1b9d127SSheldon Hearn  * Redistribution and use in source and binary forms, with or without
6f1b9d127SSheldon Hearn  * modification, are permitted provided that the following conditions
7f1b9d127SSheldon Hearn  * are met:
8f1b9d127SSheldon Hearn  * 1. Redistributions of source code must retain the above copyright
9f1b9d127SSheldon Hearn  *    notice, this list of conditions and the following disclaimer.
10f1b9d127SSheldon Hearn  * 2. Redistributions in binary form must reproduce the above copyright
11f1b9d127SSheldon Hearn  *    notice, this list of conditions and the following disclaimer in the
12f1b9d127SSheldon Hearn  *    documentation and/or other materials provided with the distribution.
13f1b9d127SSheldon Hearn  * 3. All advertising materials mentioning features or use of this software
14f1b9d127SSheldon Hearn  *    must display the following acknowledgement:
15f1b9d127SSheldon Hearn  *    This product includes software developed by Boris Popov.
16f1b9d127SSheldon Hearn  * 4. Neither the name of the author nor the names of any co-contributors
17f1b9d127SSheldon Hearn  *    may be used to endorse or promote products derived from this software
18f1b9d127SSheldon Hearn  *    without specific prior written permission.
19f1b9d127SSheldon Hearn  *
20f1b9d127SSheldon Hearn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21f1b9d127SSheldon Hearn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22f1b9d127SSheldon Hearn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23f1b9d127SSheldon Hearn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24f1b9d127SSheldon Hearn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25f1b9d127SSheldon Hearn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26f1b9d127SSheldon Hearn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27f1b9d127SSheldon Hearn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28f1b9d127SSheldon Hearn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29f1b9d127SSheldon Hearn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30f1b9d127SSheldon Hearn  * SUCH DAMAGE.
31f1b9d127SSheldon Hearn  *
32f1b9d127SSheldon Hearn  * $Id: nbns_rq.c,v 1.5 2001/02/17 03:07:24 bp Exp $
33ef29b0f6SBoris Popov  * $FreeBSD$
34f1b9d127SSheldon Hearn  */
35f1b9d127SSheldon Hearn #include <sys/param.h>
36f1b9d127SSheldon Hearn #include <sys/socket.h>
37f1b9d127SSheldon Hearn #include <sys/time.h>
38f1b9d127SSheldon Hearn 
39f1b9d127SSheldon Hearn #include <ctype.h>
40f1b9d127SSheldon Hearn #include <netdb.h>
41f1b9d127SSheldon Hearn #include <err.h>
42f1b9d127SSheldon Hearn #include <errno.h>
43f1b9d127SSheldon Hearn #include <stdlib.h>
44f1b9d127SSheldon Hearn #include <string.h>
45f1b9d127SSheldon Hearn #include <stdio.h>
46f1b9d127SSheldon Hearn #include <unistd.h>
47f1b9d127SSheldon Hearn 
48f1b9d127SSheldon Hearn #define NB_NEEDRESOLVER
49f1b9d127SSheldon Hearn #include <netsmb/netbios.h>
50f1b9d127SSheldon Hearn #include <netsmb/smb_lib.h>
51f1b9d127SSheldon Hearn #include <netsmb/nb_lib.h>
52f1b9d127SSheldon Hearn 
53f1b9d127SSheldon Hearn 
54f1b9d127SSheldon Hearn static int  nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp);
55f1b9d127SSheldon Hearn static void nbns_rq_done(struct nbns_rq *rqp);
56f1b9d127SSheldon Hearn static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
57f1b9d127SSheldon Hearn static int  nbns_rq_prepare(struct nbns_rq *rqp);
58f1b9d127SSheldon Hearn static int  nbns_rq(struct nbns_rq *rqp);
59f1b9d127SSheldon Hearn 
60f1b9d127SSheldon Hearn static struct nb_ifdesc *nb_iflist;
61f1b9d127SSheldon Hearn 
62f1b9d127SSheldon Hearn int
nbns_resolvename(const char * name,struct nb_ctx * ctx,struct sockaddr ** adpp)63f1b9d127SSheldon Hearn nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
64f1b9d127SSheldon Hearn {
65f1b9d127SSheldon Hearn 	struct nbns_rq *rqp;
66f1b9d127SSheldon Hearn 	struct nb_name nn;
67f1b9d127SSheldon Hearn 	struct nbns_rr rr;
68f1b9d127SSheldon Hearn 	struct sockaddr_in *dest;
69f1b9d127SSheldon Hearn 	int error, rdrcount, len;
70f1b9d127SSheldon Hearn 
71f1b9d127SSheldon Hearn 	if (strlen(name) > NB_NAMELEN)
72f1b9d127SSheldon Hearn 		return NBERROR(NBERR_NAMETOOLONG);
73f1b9d127SSheldon Hearn 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
74f1b9d127SSheldon Hearn 	if (error)
75f1b9d127SSheldon Hearn 		return error;
76f1b9d127SSheldon Hearn 	bzero(&nn, sizeof(nn));
77*ccbbd187SBrooks Davis 	strlcpy(nn.nn_name, name, sizeof(nn.nn_name));
78f1b9d127SSheldon Hearn 	nn.nn_scope = ctx->nb_scope;
79f1b9d127SSheldon Hearn 	nn.nn_type = NBT_SERVER;
80f1b9d127SSheldon Hearn 	rqp->nr_nmflags = NBNS_NMFLAG_RD;
81f1b9d127SSheldon Hearn 	rqp->nr_qdname = &nn;
82f1b9d127SSheldon Hearn 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
83f1b9d127SSheldon Hearn 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
84f1b9d127SSheldon Hearn 	rqp->nr_qdcount = 1;
85f1b9d127SSheldon Hearn 	dest = &rqp->nr_dest;
86f1b9d127SSheldon Hearn 	*dest = ctx->nb_ns;
87f1b9d127SSheldon Hearn 	dest->sin_family = AF_INET;
88f1b9d127SSheldon Hearn 	dest->sin_len = sizeof(*dest);
89f1b9d127SSheldon Hearn 	if (dest->sin_port == 0)
90ef29b0f6SBoris Popov 		dest->sin_port = htons(ctx->nb_nmbtcpport);
91f1b9d127SSheldon Hearn 	if (dest->sin_addr.s_addr == INADDR_ANY)
92f1b9d127SSheldon Hearn 		dest->sin_addr.s_addr = htonl(INADDR_BROADCAST);
93f1b9d127SSheldon Hearn 	if (dest->sin_addr.s_addr == INADDR_BROADCAST)
94f1b9d127SSheldon Hearn 		rqp->nr_flags |= NBRQF_BROADCAST;
95f1b9d127SSheldon Hearn 	error = nbns_rq_prepare(rqp);
96f1b9d127SSheldon Hearn 	if (error) {
97f1b9d127SSheldon Hearn 		nbns_rq_done(rqp);
98f1b9d127SSheldon Hearn 		return error;
99f1b9d127SSheldon Hearn 	}
100f1b9d127SSheldon Hearn 	rdrcount = NBNS_MAXREDIRECTS;
101f1b9d127SSheldon Hearn 	for (;;) {
102f1b9d127SSheldon Hearn 		error = nbns_rq(rqp);
103f1b9d127SSheldon Hearn 		if (error)
104f1b9d127SSheldon Hearn 			break;
105f1b9d127SSheldon Hearn 		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
106f1b9d127SSheldon Hearn 			if (rdrcount-- == 0) {
107f1b9d127SSheldon Hearn 				error = NBERROR(NBERR_TOOMANYREDIRECTS);
108f1b9d127SSheldon Hearn 				break;
109f1b9d127SSheldon Hearn 			}
110f1b9d127SSheldon Hearn 			error = nbns_rq_getrr(rqp, &rr);
111f1b9d127SSheldon Hearn 			if (error)
112f1b9d127SSheldon Hearn 				break;
113f1b9d127SSheldon Hearn 			error = nbns_rq_getrr(rqp, &rr);
114f1b9d127SSheldon Hearn 			if (error)
115f1b9d127SSheldon Hearn 				break;
116f1b9d127SSheldon Hearn 			bcopy(rr.rr_data, &dest->sin_addr, 4);
117f1b9d127SSheldon Hearn 			rqp->nr_flags &= ~NBRQF_BROADCAST;
118f1b9d127SSheldon Hearn 			continue;
119f1b9d127SSheldon Hearn 		}
120f1b9d127SSheldon Hearn 		if (rqp->nr_rpancount == 0) {
121f1b9d127SSheldon Hearn 			error = NBERROR(NBERR_HOSTNOTFOUND);
122f1b9d127SSheldon Hearn 			break;
123f1b9d127SSheldon Hearn 		}
124f1b9d127SSheldon Hearn 		error = nbns_rq_getrr(rqp, &rr);
125f1b9d127SSheldon Hearn 		if (error)
126f1b9d127SSheldon Hearn 			break;
127f1b9d127SSheldon Hearn 		len = sizeof(struct sockaddr_in);
128f1b9d127SSheldon Hearn 		dest = malloc(len);
129f1b9d127SSheldon Hearn 		if (dest == NULL)
130f1b9d127SSheldon Hearn 			return ENOMEM;
131f1b9d127SSheldon Hearn 		bzero(dest, len);
132f1b9d127SSheldon Hearn 		dest->sin_len = len;
133f1b9d127SSheldon Hearn 		dest->sin_family = AF_INET;
134f1b9d127SSheldon Hearn 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
135ef29b0f6SBoris Popov 		dest->sin_port = htons(ctx->nb_smbtcpport);
136f1b9d127SSheldon Hearn 		*adpp = (struct sockaddr*)dest;
137f1b9d127SSheldon Hearn 		ctx->nb_lastns = rqp->nr_sender;
138f1b9d127SSheldon Hearn 		break;
139f1b9d127SSheldon Hearn 	}
140f1b9d127SSheldon Hearn 	nbns_rq_done(rqp);
141f1b9d127SSheldon Hearn 	return error;
142f1b9d127SSheldon Hearn }
143f1b9d127SSheldon Hearn 
144f1b9d127SSheldon Hearn int
nbns_rq_create(int opcode,struct nb_ctx * ctx,struct nbns_rq ** rqpp)145f1b9d127SSheldon Hearn nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
146f1b9d127SSheldon Hearn {
147f1b9d127SSheldon Hearn 	struct nbns_rq *rqp;
148f1b9d127SSheldon Hearn 	static u_int16_t trnid;
149f1b9d127SSheldon Hearn 	int error;
150f1b9d127SSheldon Hearn 
151f1b9d127SSheldon Hearn 	rqp = malloc(sizeof(*rqp));
152f1b9d127SSheldon Hearn 	if (rqp == NULL)
153f1b9d127SSheldon Hearn 		return ENOMEM;
154f1b9d127SSheldon Hearn 	bzero(rqp, sizeof(*rqp));
155f1b9d127SSheldon Hearn 	error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
156f1b9d127SSheldon Hearn 	if (error) {
157f1b9d127SSheldon Hearn 		free(rqp);
158f1b9d127SSheldon Hearn 		return error;
159f1b9d127SSheldon Hearn 	}
160f1b9d127SSheldon Hearn 	rqp->nr_opcode = opcode;
161f1b9d127SSheldon Hearn 	rqp->nr_nbd = ctx;
162f1b9d127SSheldon Hearn 	rqp->nr_trnid = trnid++;
163f1b9d127SSheldon Hearn 	*rqpp = rqp;
164f1b9d127SSheldon Hearn 	return 0;
165f1b9d127SSheldon Hearn }
166f1b9d127SSheldon Hearn 
167f1b9d127SSheldon Hearn void
nbns_rq_done(struct nbns_rq * rqp)168f1b9d127SSheldon Hearn nbns_rq_done(struct nbns_rq *rqp)
169f1b9d127SSheldon Hearn {
170f1b9d127SSheldon Hearn 	if (rqp == NULL)
171f1b9d127SSheldon Hearn 		return;
172f1b9d127SSheldon Hearn 	if (rqp->nr_fd >= 0)
173f1b9d127SSheldon Hearn 		close(rqp->nr_fd);
174f1b9d127SSheldon Hearn 	mb_done(&rqp->nr_rq);
175f1b9d127SSheldon Hearn 	mb_done(&rqp->nr_rp);
176f1b9d127SSheldon Hearn 	free(rqp);
177f1b9d127SSheldon Hearn }
178f1b9d127SSheldon Hearn 
179f1b9d127SSheldon Hearn /*
180f1b9d127SSheldon Hearn  * Extract resource record from the packet. Assume that there is only
181f1b9d127SSheldon Hearn  * one mbuf.
182f1b9d127SSheldon Hearn  */
183f1b9d127SSheldon Hearn int
nbns_rq_getrr(struct nbns_rq * rqp,struct nbns_rr * rrp)184f1b9d127SSheldon Hearn nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
185f1b9d127SSheldon Hearn {
186f1b9d127SSheldon Hearn 	struct mbdata *mbp = &rqp->nr_rp;
187f1b9d127SSheldon Hearn 	u_char *cp;
188f1b9d127SSheldon Hearn 	int error, len;
189f1b9d127SSheldon Hearn 
190f1b9d127SSheldon Hearn 	bzero(rrp, sizeof(*rrp));
191f1b9d127SSheldon Hearn 	cp = mbp->mb_pos;
192f1b9d127SSheldon Hearn 	len = nb_encname_len(cp);
193f1b9d127SSheldon Hearn 	if (len < 1)
194f1b9d127SSheldon Hearn 		return NBERROR(NBERR_INVALIDRESPONSE);
195f1b9d127SSheldon Hearn 	rrp->rr_name = cp;
196f1b9d127SSheldon Hearn 	error = mb_get_mem(mbp, NULL, len);
197f1b9d127SSheldon Hearn 	if (error)
198f1b9d127SSheldon Hearn 		return error;
199f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rrp->rr_type);
200f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rrp->rr_class);
201f1b9d127SSheldon Hearn 	mb_get_uint32be(mbp, &rrp->rr_ttl);
202f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rrp->rr_rdlength);
203f1b9d127SSheldon Hearn 	rrp->rr_data = mbp->mb_pos;
204f1b9d127SSheldon Hearn 	error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
205f1b9d127SSheldon Hearn 	return error;
206f1b9d127SSheldon Hearn }
207f1b9d127SSheldon Hearn 
208f1b9d127SSheldon Hearn int
nbns_rq_prepare(struct nbns_rq * rqp)209f1b9d127SSheldon Hearn nbns_rq_prepare(struct nbns_rq *rqp)
210f1b9d127SSheldon Hearn {
211f1b9d127SSheldon Hearn 	struct nb_ctx *ctx = rqp->nr_nbd;
212f1b9d127SSheldon Hearn 	struct mbdata *mbp = &rqp->nr_rq;
213f1b9d127SSheldon Hearn 	u_int8_t nmflags;
214f1b9d127SSheldon Hearn 	u_char *cp;
215f1b9d127SSheldon Hearn 	int len, error;
216f1b9d127SSheldon Hearn 
217f1b9d127SSheldon Hearn 	error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
218f1b9d127SSheldon Hearn 	if (error)
219f1b9d127SSheldon Hearn 		return error;
220f1b9d127SSheldon Hearn 	if (rqp->nr_dest.sin_addr.s_addr == INADDR_BROADCAST) {
221f1b9d127SSheldon Hearn 		rqp->nr_nmflags |= NBNS_NMFLAG_BCAST;
222f1b9d127SSheldon Hearn 		if (nb_iflist == NULL) {
223f1b9d127SSheldon Hearn 			error = nb_enum_if(&nb_iflist, 100);
224f1b9d127SSheldon Hearn 			if (error)
225f1b9d127SSheldon Hearn 				return error;
226f1b9d127SSheldon Hearn 		}
227f1b9d127SSheldon Hearn 	} else
228f1b9d127SSheldon Hearn 		rqp->nr_nmflags &= ~NBNS_NMFLAG_BCAST;
229f1b9d127SSheldon Hearn 	mb_put_uint16be(mbp, rqp->nr_trnid);
230f1b9d127SSheldon Hearn 	nmflags = ((rqp->nr_opcode & 0x1F) << 3) | ((rqp->nr_nmflags & 0x70) >> 4);
231f1b9d127SSheldon Hearn 	mb_put_uint8(mbp, nmflags);
232f1b9d127SSheldon Hearn 	mb_put_uint8(mbp, (rqp->nr_nmflags & 0x0f) << 4 /* rcode */);
233f1b9d127SSheldon Hearn 	mb_put_uint16be(mbp, rqp->nr_qdcount);
234f1b9d127SSheldon Hearn 	mb_put_uint16be(mbp, rqp->nr_ancount);
235f1b9d127SSheldon Hearn 	mb_put_uint16be(mbp, rqp->nr_nscount);
236f1b9d127SSheldon Hearn 	mb_put_uint16be(mbp, rqp->nr_arcount);
237f1b9d127SSheldon Hearn 	if (rqp->nr_qdcount) {
238f1b9d127SSheldon Hearn 		if (rqp->nr_qdcount > 1)
239f1b9d127SSheldon Hearn 			return EINVAL;
240f1b9d127SSheldon Hearn 		len = nb_name_len(rqp->nr_qdname);
241f1b9d127SSheldon Hearn 		error = mb_fit(mbp, len, (char**)&cp);
242f1b9d127SSheldon Hearn 		if (error)
243f1b9d127SSheldon Hearn 			return error;
244f1b9d127SSheldon Hearn 		nb_name_encode(rqp->nr_qdname, cp);
245f1b9d127SSheldon Hearn 		mb_put_uint16be(mbp, rqp->nr_qdtype);
246f1b9d127SSheldon Hearn 		mb_put_uint16be(mbp, rqp->nr_qdclass);
247f1b9d127SSheldon Hearn 	}
248f1b9d127SSheldon Hearn 	m_lineup(mbp->mb_top, &mbp->mb_top);
249f1b9d127SSheldon Hearn 	if (ctx->nb_timo == 0)
250f1b9d127SSheldon Hearn 		ctx->nb_timo = 1;	/* by default 1 second */
251f1b9d127SSheldon Hearn 	return 0;
252f1b9d127SSheldon Hearn }
253f1b9d127SSheldon Hearn 
254f1b9d127SSheldon Hearn static int
nbns_rq_recv(struct nbns_rq * rqp)255f1b9d127SSheldon Hearn nbns_rq_recv(struct nbns_rq *rqp)
256f1b9d127SSheldon Hearn {
257f1b9d127SSheldon Hearn 	struct mbdata *mbp = &rqp->nr_rp;
258f1b9d127SSheldon Hearn 	void *rpdata = mtod(mbp->mb_top, void *);
259f1b9d127SSheldon Hearn 	fd_set rd, wr, ex;
260f1b9d127SSheldon Hearn 	struct timeval tv;
261f1b9d127SSheldon Hearn 	struct sockaddr_in sender;
262f1b9d127SSheldon Hearn 	int s = rqp->nr_fd;
263f1b9d127SSheldon Hearn 	int n, len;
264f1b9d127SSheldon Hearn 
265f1b9d127SSheldon Hearn 	FD_ZERO(&rd);
266f1b9d127SSheldon Hearn 	FD_ZERO(&wr);
267f1b9d127SSheldon Hearn 	FD_ZERO(&ex);
268f1b9d127SSheldon Hearn 	FD_SET(s, &rd);
269f1b9d127SSheldon Hearn 
270f1b9d127SSheldon Hearn 	tv.tv_sec = rqp->nr_nbd->nb_timo;
271f1b9d127SSheldon Hearn 	tv.tv_usec = 0;
272f1b9d127SSheldon Hearn 
273f1b9d127SSheldon Hearn 	n = select(s + 1, &rd, &wr, &ex, &tv);
274f1b9d127SSheldon Hearn 	if (n == -1)
275f1b9d127SSheldon Hearn 		return -1;
276f1b9d127SSheldon Hearn 	if (n == 0)
277f1b9d127SSheldon Hearn 		return ETIMEDOUT;
278f1b9d127SSheldon Hearn 	if (FD_ISSET(s, &rd) == 0)
279f1b9d127SSheldon Hearn 		return ETIMEDOUT;
280f1b9d127SSheldon Hearn 	len = sizeof(sender);
281f1b9d127SSheldon Hearn 	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
282f1b9d127SSheldon Hearn 	    (struct sockaddr*)&sender, &len);
283f1b9d127SSheldon Hearn 	if (n < 0)
284f1b9d127SSheldon Hearn 		return errno;
285f1b9d127SSheldon Hearn 	mbp->mb_top->m_len = mbp->mb_count = n;
286f1b9d127SSheldon Hearn 	rqp->nr_sender = sender;
287f1b9d127SSheldon Hearn 	return 0;
288f1b9d127SSheldon Hearn }
289f1b9d127SSheldon Hearn 
290f1b9d127SSheldon Hearn static int
nbns_rq_opensocket(struct nbns_rq * rqp)291f1b9d127SSheldon Hearn nbns_rq_opensocket(struct nbns_rq *rqp)
292f1b9d127SSheldon Hearn {
293f1b9d127SSheldon Hearn 	struct sockaddr_in locaddr;
294f1b9d127SSheldon Hearn 	int opt, s;
295f1b9d127SSheldon Hearn 
296f1b9d127SSheldon Hearn 	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
297f1b9d127SSheldon Hearn 	if (s < 0)
298f1b9d127SSheldon Hearn 		return errno;
299f1b9d127SSheldon Hearn 	if (rqp->nr_flags & NBRQF_BROADCAST) {
300f1b9d127SSheldon Hearn 		opt = 1;
301f1b9d127SSheldon Hearn 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0)
302f1b9d127SSheldon Hearn 			return errno;
303f1b9d127SSheldon Hearn 		if (rqp->nr_if == NULL)
304f1b9d127SSheldon Hearn 			return NBERROR(NBERR_NOBCASTIFS);
305f1b9d127SSheldon Hearn 		bzero(&locaddr, sizeof(locaddr));
306f1b9d127SSheldon Hearn 		locaddr.sin_family = AF_INET;
307f1b9d127SSheldon Hearn 		locaddr.sin_len = sizeof(locaddr);
308f1b9d127SSheldon Hearn 		locaddr.sin_addr = rqp->nr_if->id_addr;
309f1b9d127SSheldon Hearn 		rqp->nr_dest.sin_addr.s_addr = rqp->nr_if->id_addr.s_addr | ~rqp->nr_if->id_mask.s_addr;
310f1b9d127SSheldon Hearn 		if (bind(s, (struct sockaddr*)&locaddr, sizeof(locaddr)) < 0)
311f1b9d127SSheldon Hearn 			return errno;
312f1b9d127SSheldon Hearn 	}
313f1b9d127SSheldon Hearn 	return 0;
314f1b9d127SSheldon Hearn }
315f1b9d127SSheldon Hearn 
316f1b9d127SSheldon Hearn static int
nbns_rq_send(struct nbns_rq * rqp)317f1b9d127SSheldon Hearn nbns_rq_send(struct nbns_rq *rqp)
318f1b9d127SSheldon Hearn {
319f1b9d127SSheldon Hearn 	struct mbdata *mbp = &rqp->nr_rq;
320f1b9d127SSheldon Hearn 	int s = rqp->nr_fd;
321f1b9d127SSheldon Hearn 
322f1b9d127SSheldon Hearn 	if (sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
323f1b9d127SSheldon Hearn 	      (struct sockaddr*)&rqp->nr_dest, sizeof(rqp->nr_dest)) < 0)
324f1b9d127SSheldon Hearn 		return errno;
325f1b9d127SSheldon Hearn 	return 0;
326f1b9d127SSheldon Hearn }
327f1b9d127SSheldon Hearn 
328f1b9d127SSheldon Hearn int
nbns_rq(struct nbns_rq * rqp)329f1b9d127SSheldon Hearn nbns_rq(struct nbns_rq *rqp)
330f1b9d127SSheldon Hearn {
331f1b9d127SSheldon Hearn 	struct mbdata *mbp = &rqp->nr_rq;
332f1b9d127SSheldon Hearn 	u_int16_t rpid;
333f1b9d127SSheldon Hearn 	u_int8_t nmflags;
334f1b9d127SSheldon Hearn 	int error, retrycount;
335f1b9d127SSheldon Hearn 
336f1b9d127SSheldon Hearn 	rqp->nr_if = nb_iflist;
337f1b9d127SSheldon Hearn again:
338f1b9d127SSheldon Hearn 	error = nbns_rq_opensocket(rqp);
339f1b9d127SSheldon Hearn 	if (error)
340f1b9d127SSheldon Hearn 		return error;
341f1b9d127SSheldon Hearn 	retrycount = 3;	/* XXX - configurable */
342f1b9d127SSheldon Hearn 	for (;;) {
343f1b9d127SSheldon Hearn 		error = nbns_rq_send(rqp);
344f1b9d127SSheldon Hearn 		if (error)
345f1b9d127SSheldon Hearn 			return error;
346f1b9d127SSheldon Hearn 		error = nbns_rq_recv(rqp);
347f1b9d127SSheldon Hearn 		if (error) {
348f1b9d127SSheldon Hearn 			if (error != ETIMEDOUT || retrycount == 0) {
349f1b9d127SSheldon Hearn 				if ((rqp->nr_nmflags & NBNS_NMFLAG_BCAST) &&
350f1b9d127SSheldon Hearn 				    rqp->nr_if != NULL &&
351f1b9d127SSheldon Hearn 				    rqp->nr_if->id_next != NULL) {
352f1b9d127SSheldon Hearn 					rqp->nr_if = rqp->nr_if->id_next;
353f1b9d127SSheldon Hearn 					close(rqp->nr_fd);
354f1b9d127SSheldon Hearn 					goto again;
355f1b9d127SSheldon Hearn 				} else
356f1b9d127SSheldon Hearn 					return error;
357f1b9d127SSheldon Hearn 			}
358f1b9d127SSheldon Hearn 			retrycount--;
359f1b9d127SSheldon Hearn 			continue;
360f1b9d127SSheldon Hearn 		}
361f1b9d127SSheldon Hearn 		mbp = &rqp->nr_rp;
362f1b9d127SSheldon Hearn 		if (mbp->mb_count < 12)
363f1b9d127SSheldon Hearn 			return NBERROR(NBERR_INVALIDRESPONSE);
364f1b9d127SSheldon Hearn 		mb_get_uint16be(mbp, &rpid);
365f1b9d127SSheldon Hearn 		if (rpid != rqp->nr_trnid)
366f1b9d127SSheldon Hearn 			return NBERROR(NBERR_INVALIDRESPONSE);
367f1b9d127SSheldon Hearn 		break;
368f1b9d127SSheldon Hearn 	}
369f1b9d127SSheldon Hearn 	mb_get_uint8(mbp, &nmflags);
370f1b9d127SSheldon Hearn 	rqp->nr_rpnmflags = (nmflags & 7) << 4;
371f1b9d127SSheldon Hearn 	mb_get_uint8(mbp, &nmflags);
372f1b9d127SSheldon Hearn 	rqp->nr_rpnmflags |= (nmflags & 0xf0) >> 4;
373f1b9d127SSheldon Hearn 	rqp->nr_rprcode = nmflags & 0xf;
374f1b9d127SSheldon Hearn 	if (rqp->nr_rprcode)
375f1b9d127SSheldon Hearn 		return NBERROR(rqp->nr_rprcode);
376f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rpid);	/* QDCOUNT */
377f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rqp->nr_rpancount);
378f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rqp->nr_rpnscount);
379f1b9d127SSheldon Hearn 	mb_get_uint16be(mbp, &rqp->nr_rparcount);
380f1b9d127SSheldon Hearn 	return 0;
381f1b9d127SSheldon Hearn }
382