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 * from: Id: nbns_rq.c,v 1.5 2001/02/17 03:07:24 bp Exp
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: nbns_rq.c,v 1.6 2009/09/06 17:02:36 pooka Exp $");
38 #include <sys/param.h>
39 #include <sys/socket.h>
51 #define NB_NEEDRESOLVER
52 #include <netsmb/netbios.h>
53 #include <netsmb/smb_lib.h>
54 #include <netsmb/nb_lib.h>
56 #include "smb_kernelops.h"
58 static int nbns_rq_create(int opcode
, struct nb_ctx
*ctx
, struct nbns_rq
**rqpp
);
59 static void nbns_rq_done(struct nbns_rq
*rqp
);
60 static int nbns_rq_getrr(struct nbns_rq
*rqp
, struct nbns_rr
*rrp
);
61 static int nbns_rq_prepare(struct nbns_rq
*rqp
);
62 static int nbns_rq(struct nbns_rq
*rqp
);
64 static struct nb_ifdesc
*nb_iflist
;
67 nbns_resolvename(const char *name
, struct nb_ctx
*ctx
, struct sockaddr
**adpp
)
72 struct sockaddr_in
*dest
;
73 int error
, rdrcount
, len
;
75 if (strlen(name
) > NB_NAMELEN
)
76 return NBERROR(NBERR_NAMETOOLONG
);
77 error
= nbns_rq_create(NBNS_OPCODE_QUERY
, ctx
, &rqp
);
80 bzero(&nn
, sizeof(nn
));
81 strcpy(nn
.nn_name
, name
);
82 nn
.nn_scope
= ctx
->nb_scope
;
83 nn
.nn_type
= NBT_SERVER
;
84 rqp
->nr_nmflags
= NBNS_NMFLAG_RD
;
86 rqp
->nr_qdtype
= NBNS_QUESTION_TYPE_NB
;
87 rqp
->nr_qdclass
= NBNS_QUESTION_CLASS_IN
;
91 dest
->sin_family
= AF_INET
;
92 dest
->sin_len
= sizeof(*dest
);
93 if (dest
->sin_port
== 0)
94 dest
->sin_port
= htons(137);
95 if (dest
->sin_addr
.s_addr
== INADDR_ANY
)
96 dest
->sin_addr
.s_addr
= htonl(INADDR_BROADCAST
);
97 if (dest
->sin_addr
.s_addr
== INADDR_BROADCAST
)
98 rqp
->nr_flags
|= NBRQF_BROADCAST
;
99 error
= nbns_rq_prepare(rqp
);
104 rdrcount
= NBNS_MAXREDIRECTS
;
106 error
= nbns_rq(rqp
);
109 if ((rqp
->nr_rpnmflags
& NBNS_NMFLAG_AA
) == 0) {
110 if (rdrcount
-- == 0) {
111 error
= NBERROR(NBERR_TOOMANYREDIRECTS
);
114 error
= nbns_rq_getrr(rqp
, &rr
);
117 error
= nbns_rq_getrr(rqp
, &rr
);
120 bcopy(rr
.rr_data
, &dest
->sin_addr
, 4);
121 rqp
->nr_flags
&= ~NBRQF_BROADCAST
;
124 if (rqp
->nr_rpancount
== 0) {
125 error
= NBERROR(NBERR_HOSTNOTFOUND
);
128 error
= nbns_rq_getrr(rqp
, &rr
);
131 len
= sizeof(struct sockaddr_in
);
137 dest
->sin_family
= AF_INET
;
138 bcopy(rr
.rr_data
+ 2, &dest
->sin_addr
.s_addr
, 4);
139 dest
->sin_port
= htons(SMB_TCP_PORT
);
140 *adpp
= (struct sockaddr
*)dest
;
141 ctx
->nb_lastns
= rqp
->nr_sender
;
149 nbns_rq_create(int opcode
, struct nb_ctx
*ctx
, struct nbns_rq
**rqpp
)
152 static u_int16_t trnid
;
155 rqp
= malloc(sizeof(*rqp
));
158 bzero(rqp
, sizeof(*rqp
));
159 error
= mb_init(&rqp
->nr_rq
, NBDG_MAXSIZE
);
164 rqp
->nr_opcode
= opcode
;
166 rqp
->nr_trnid
= trnid
++;
172 nbns_rq_done(struct nbns_rq
*rqp
)
177 smb_kops
.ko_close(rqp
->nr_fd
);
178 mb_done(&rqp
->nr_rq
);
179 mb_done(&rqp
->nr_rp
);
184 * Extract resource record from the packet. Assume that there is only
188 nbns_rq_getrr(struct nbns_rq
*rqp
, struct nbns_rr
*rrp
)
190 struct mbdata
*mbp
= &rqp
->nr_rp
;
194 bzero(rrp
, sizeof(*rrp
));
196 len
= nb_encname_len(cp
);
198 return NBERROR(NBERR_INVALIDRESPONSE
);
200 error
= mb_get_mem(mbp
, NULL
, len
);
203 mb_get_uint16be(mbp
, &rrp
->rr_type
);
204 mb_get_uint16be(mbp
, &rrp
->rr_class
);
205 mb_get_uint32be(mbp
, &rrp
->rr_ttl
);
206 mb_get_uint16be(mbp
, &rrp
->rr_rdlength
);
207 rrp
->rr_data
= mbp
->mb_pos
;
208 error
= mb_get_mem(mbp
, NULL
, rrp
->rr_rdlength
);
213 nbns_rq_prepare(struct nbns_rq
*rqp
)
215 struct nb_ctx
*ctx
= rqp
->nr_nbd
;
216 struct mbdata
*mbp
= &rqp
->nr_rq
;
221 error
= mb_init(&rqp
->nr_rp
, NBDG_MAXSIZE
);
224 if (rqp
->nr_dest
.sin_addr
.s_addr
== INADDR_BROADCAST
) {
225 rqp
->nr_nmflags
|= NBNS_NMFLAG_BCAST
;
226 if (nb_iflist
== NULL
) {
227 error
= nb_enum_if(&nb_iflist
, 100);
232 rqp
->nr_nmflags
&= ~NBNS_NMFLAG_BCAST
;
233 mb_put_uint16be(mbp
, rqp
->nr_trnid
);
234 nmflags
= ((rqp
->nr_opcode
& 0x1F) << 3) | ((rqp
->nr_nmflags
& 0x70) >> 4);
235 mb_put_uint8(mbp
, nmflags
);
236 mb_put_uint8(mbp
, (rqp
->nr_nmflags
& 0x0f) << 4 /* rcode */);
237 mb_put_uint16be(mbp
, rqp
->nr_qdcount
);
238 mb_put_uint16be(mbp
, rqp
->nr_ancount
);
239 mb_put_uint16be(mbp
, rqp
->nr_nscount
);
240 mb_put_uint16be(mbp
, rqp
->nr_arcount
);
241 if (rqp
->nr_qdcount
) {
242 if (rqp
->nr_qdcount
> 1)
244 len
= nb_name_len(rqp
->nr_qdname
);
245 error
= mb_fit(mbp
, len
, (void **)(void *)&cp
);
248 nb_name_encode(rqp
->nr_qdname
, cp
);
249 mb_put_uint16be(mbp
, rqp
->nr_qdtype
);
250 mb_put_uint16be(mbp
, rqp
->nr_qdclass
);
252 m_lineup(mbp
->mb_top
, &mbp
->mb_top
);
253 if (ctx
->nb_timo
== 0)
254 ctx
->nb_timo
= 1; /* by default 1 second */
259 nbns_rq_recv(struct nbns_rq
*rqp
)
261 struct mbdata
*mbp
= &rqp
->nr_rp
;
262 void *rpdata
= mtod(mbp
->mb_top
, void *);
263 struct sockaddr_in sender
;
267 len
= sizeof(sender
);
268 n
= smb_kops
.ko_recvfrom(s
, rpdata
, mbp
->mb_top
->m_maxlen
, 0,
269 (struct sockaddr
*)&sender
, &len
);
275 mbp
->mb_top
->m_len
= mbp
->mb_count
= n
;
276 rqp
->nr_sender
= sender
;
281 nbns_rq_opensocket(struct nbns_rq
*rqp
)
283 struct sockaddr_in locaddr
;
287 s
= rqp
->nr_fd
= smb_kops
.ko_socket(AF_INET
, SOCK_DGRAM
, 0);
290 if (rqp
->nr_flags
& NBRQF_BROADCAST
) {
292 if (smb_kops
.ko_setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
,
293 &opt
, sizeof(opt
)) < 0)
295 tv
.tv_sec
= rqp
->nr_nbd
->nb_timo
;
297 if (smb_kops
.ko_setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
,
298 &tv
, sizeof(tv
)) < 0)
300 if (rqp
->nr_if
== NULL
)
301 return NBERROR(NBERR_NOBCASTIFS
);
302 bzero(&locaddr
, sizeof(locaddr
));
303 locaddr
.sin_family
= AF_INET
;
304 locaddr
.sin_len
= sizeof(locaddr
);
305 locaddr
.sin_addr
= rqp
->nr_if
->id_addr
;
306 rqp
->nr_dest
.sin_addr
.s_addr
= rqp
->nr_if
->id_addr
.s_addr
| ~rqp
->nr_if
->id_mask
.s_addr
;
307 if (smb_kops
.ko_bind(s
, (struct sockaddr
*)&locaddr
, sizeof(locaddr
)) < 0)
314 nbns_rq_send(struct nbns_rq
*rqp
)
316 struct mbdata
*mbp
= &rqp
->nr_rq
;
319 if (smb_kops
.ko_sendto(s
, mtod(mbp
->mb_top
, char *), mbp
->mb_count
, 0,
320 (struct sockaddr
*)&rqp
->nr_dest
, sizeof(rqp
->nr_dest
)) < 0)
326 nbns_rq(struct nbns_rq
*rqp
)
328 struct mbdata
*mbp
= &rqp
->nr_rq
;
331 int error
, retrycount
;
333 rqp
->nr_if
= nb_iflist
;
335 error
= nbns_rq_opensocket(rqp
);
338 retrycount
= 3; /* XXX - configurable */
340 error
= nbns_rq_send(rqp
);
343 error
= nbns_rq_recv(rqp
);
345 if (error
!= ETIMEDOUT
|| retrycount
== 0) {
346 if ((rqp
->nr_nmflags
& NBNS_NMFLAG_BCAST
) &&
347 rqp
->nr_if
!= NULL
&&
348 rqp
->nr_if
->id_next
!= NULL
) {
349 rqp
->nr_if
= rqp
->nr_if
->id_next
;
350 smb_kops
.ko_close(rqp
->nr_fd
);
359 if (mbp
->mb_count
< 12)
360 return NBERROR(NBERR_INVALIDRESPONSE
);
361 mb_get_uint16be(mbp
, &rpid
);
362 if (rpid
!= rqp
->nr_trnid
)
363 return NBERROR(NBERR_INVALIDRESPONSE
);
366 mb_get_uint8(mbp
, &nmflags
);
367 rqp
->nr_rpnmflags
= (nmflags
& 7) << 4;
368 mb_get_uint8(mbp
, &nmflags
);
369 rqp
->nr_rpnmflags
|= (nmflags
& 0xf0) >> 4;
370 rqp
->nr_rprcode
= nmflags
& 0xf;
372 return NBERROR(rqp
->nr_rprcode
);
373 mb_get_uint16be(mbp
, &rpid
); /* QDCOUNT */
374 mb_get_uint16be(mbp
, &rqp
->nr_rpancount
);
375 mb_get_uint16be(mbp
, &rqp
->nr_rpnscount
);
376 mb_get_uint16be(mbp
, &rqp
->nr_rparcount
);