2 * Copyright (c) 2000, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: nbns_rq.c,v 1.5 2001/02/17 03:07:24 bp Exp $
35 #include <sys/param.h>
36 #include <sys/socket.h>
48 #define NB_NEEDRESOLVER
49 #include <netsmb/netbios.h>
50 #include <netsmb/smb_lib.h>
51 #include <netsmb/nb_lib.h>
54 static int nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp);
55 static void nbns_rq_done(struct nbns_rq *rqp);
56 static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
57 static int nbns_rq_prepare(struct nbns_rq *rqp);
58 static int nbns_rq(struct nbns_rq *rqp);
60 static struct nb_ifdesc *nb_iflist;
63 nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
68 struct sockaddr_in *dest;
69 int error, rdrcount, len;
71 if (strlen(name) > NB_NAMELEN)
72 return NBERROR(NBERR_NAMETOOLONG);
73 error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
76 bzero(&nn, sizeof(nn));
77 strcpy(nn.nn_name, name);
78 nn.nn_scope = ctx->nb_scope;
79 nn.nn_type = NBT_SERVER;
80 rqp->nr_nmflags = NBNS_NMFLAG_RD;
82 rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
83 rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
87 dest->sin_family = AF_INET;
88 dest->sin_len = sizeof(*dest);
89 if (dest->sin_port == 0)
90 dest->sin_port = htons(ctx->nb_nmbtcpport);
91 if (dest->sin_addr.s_addr == INADDR_ANY)
92 dest->sin_addr.s_addr = htonl(INADDR_BROADCAST);
93 if (dest->sin_addr.s_addr == INADDR_BROADCAST)
94 rqp->nr_flags |= NBRQF_BROADCAST;
95 error = nbns_rq_prepare(rqp);
100 rdrcount = NBNS_MAXREDIRECTS;
102 error = nbns_rq(rqp);
105 if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
106 if (rdrcount-- == 0) {
107 error = NBERROR(NBERR_TOOMANYREDIRECTS);
110 error = nbns_rq_getrr(rqp, &rr);
113 error = nbns_rq_getrr(rqp, &rr);
116 bcopy(rr.rr_data, &dest->sin_addr, 4);
117 rqp->nr_flags &= ~NBRQF_BROADCAST;
120 if (rqp->nr_rpancount == 0) {
121 error = NBERROR(NBERR_HOSTNOTFOUND);
124 error = nbns_rq_getrr(rqp, &rr);
127 len = sizeof(struct sockaddr_in);
133 dest->sin_family = AF_INET;
134 bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
135 dest->sin_port = htons(ctx->nb_smbtcpport);
136 *adpp = (struct sockaddr*)dest;
137 ctx->nb_lastns = rqp->nr_sender;
145 nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
148 static u_int16_t trnid;
151 rqp = malloc(sizeof(*rqp));
154 bzero(rqp, sizeof(*rqp));
155 error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
160 rqp->nr_opcode = opcode;
162 rqp->nr_trnid = trnid++;
168 nbns_rq_done(struct nbns_rq *rqp)
174 mb_done(&rqp->nr_rq);
175 mb_done(&rqp->nr_rp);
180 * Extract resource record from the packet. Assume that there is only
184 nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
186 struct mbdata *mbp = &rqp->nr_rp;
190 bzero(rrp, sizeof(*rrp));
192 len = nb_encname_len(cp);
194 return NBERROR(NBERR_INVALIDRESPONSE);
196 error = mb_get_mem(mbp, NULL, len);
199 mb_get_uint16be(mbp, &rrp->rr_type);
200 mb_get_uint16be(mbp, &rrp->rr_class);
201 mb_get_uint32be(mbp, &rrp->rr_ttl);
202 mb_get_uint16be(mbp, &rrp->rr_rdlength);
203 rrp->rr_data = mbp->mb_pos;
204 error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
209 nbns_rq_prepare(struct nbns_rq *rqp)
211 struct nb_ctx *ctx = rqp->nr_nbd;
212 struct mbdata *mbp = &rqp->nr_rq;
217 error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
220 if (rqp->nr_dest.sin_addr.s_addr == INADDR_BROADCAST) {
221 rqp->nr_nmflags |= NBNS_NMFLAG_BCAST;
222 if (nb_iflist == NULL) {
223 error = nb_enum_if(&nb_iflist, 100);
228 rqp->nr_nmflags &= ~NBNS_NMFLAG_BCAST;
229 mb_put_uint16be(mbp, rqp->nr_trnid);
230 nmflags = ((rqp->nr_opcode & 0x1F) << 3) | ((rqp->nr_nmflags & 0x70) >> 4);
231 mb_put_uint8(mbp, nmflags);
232 mb_put_uint8(mbp, (rqp->nr_nmflags & 0x0f) << 4 /* rcode */);
233 mb_put_uint16be(mbp, rqp->nr_qdcount);
234 mb_put_uint16be(mbp, rqp->nr_ancount);
235 mb_put_uint16be(mbp, rqp->nr_nscount);
236 mb_put_uint16be(mbp, rqp->nr_arcount);
237 if (rqp->nr_qdcount) {
238 if (rqp->nr_qdcount > 1)
240 len = nb_name_len(rqp->nr_qdname);
241 error = mb_fit(mbp, len, (char**)&cp);
244 nb_name_encode(rqp->nr_qdname, cp);
245 mb_put_uint16be(mbp, rqp->nr_qdtype);
246 mb_put_uint16be(mbp, rqp->nr_qdclass);
248 m_lineup(mbp->mb_top, &mbp->mb_top);
249 if (ctx->nb_timo == 0)
250 ctx->nb_timo = 1; /* by default 1 second */
255 nbns_rq_recv(struct nbns_rq *rqp)
257 struct mbdata *mbp = &rqp->nr_rp;
258 void *rpdata = mtod(mbp->mb_top, void *);
261 struct sockaddr_in sender;
270 tv.tv_sec = rqp->nr_nbd->nb_timo;
273 n = select(s + 1, &rd, &wr, &ex, &tv);
278 if (FD_ISSET(s, &rd) == 0)
280 len = sizeof(sender);
281 n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
282 (struct sockaddr*)&sender, &len);
285 mbp->mb_top->m_len = mbp->mb_count = n;
286 rqp->nr_sender = sender;
291 nbns_rq_opensocket(struct nbns_rq *rqp)
293 struct sockaddr_in locaddr;
296 s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
299 if (rqp->nr_flags & NBRQF_BROADCAST) {
301 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0)
303 if (rqp->nr_if == NULL)
304 return NBERROR(NBERR_NOBCASTIFS);
305 bzero(&locaddr, sizeof(locaddr));
306 locaddr.sin_family = AF_INET;
307 locaddr.sin_len = sizeof(locaddr);
308 locaddr.sin_addr = rqp->nr_if->id_addr;
309 rqp->nr_dest.sin_addr.s_addr = rqp->nr_if->id_addr.s_addr | ~rqp->nr_if->id_mask.s_addr;
310 if (bind(s, (struct sockaddr*)&locaddr, sizeof(locaddr)) < 0)
317 nbns_rq_send(struct nbns_rq *rqp)
319 struct mbdata *mbp = &rqp->nr_rq;
322 if (sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
323 (struct sockaddr*)&rqp->nr_dest, sizeof(rqp->nr_dest)) < 0)
329 nbns_rq(struct nbns_rq *rqp)
331 struct mbdata *mbp = &rqp->nr_rq;
334 int error, retrycount;
336 rqp->nr_if = nb_iflist;
338 error = nbns_rq_opensocket(rqp);
341 retrycount = 3; /* XXX - configurable */
343 error = nbns_rq_send(rqp);
346 error = nbns_rq_recv(rqp);
348 if (error != ETIMEDOUT || retrycount == 0) {
349 if ((rqp->nr_nmflags & NBNS_NMFLAG_BCAST) &&
350 rqp->nr_if != NULL &&
351 rqp->nr_if->id_next != NULL) {
352 rqp->nr_if = rqp->nr_if->id_next;
362 if (mbp->mb_count < 12)
363 return NBERROR(NBERR_INVALIDRESPONSE);
364 mb_get_uint16be(mbp, &rpid);
365 if (rpid != rqp->nr_trnid)
366 return NBERROR(NBERR_INVALIDRESPONSE);
369 mb_get_uint8(mbp, &nmflags);
370 rqp->nr_rpnmflags = (nmflags & 7) << 4;
371 mb_get_uint8(mbp, &nmflags);
372 rqp->nr_rpnmflags |= (nmflags & 0xf0) >> 4;
373 rqp->nr_rprcode = nmflags & 0xf;
375 return NBERROR(rqp->nr_rprcode);
376 mb_get_uint16be(mbp, &rpid); /* QDCOUNT */
377 mb_get_uint16be(mbp, &rqp->nr_rpancount);
378 mb_get_uint16be(mbp, &rqp->nr_rpnscount);
379 mb_get_uint16be(mbp, &rqp->nr_rparcount);