Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / smbfs / lib / smb / nbns_rq.c
blob098daeb0f811d2cafb7ecc61444cf5cd76c1fec8
1 /*
2 * Copyright (c) 2000, Boris Popov
3 * All rights reserved.
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.
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.
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>
40 #include <sys/time.h>
42 #include <ctype.h>
43 #include <netdb.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <unistd.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;
66 int
67 nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
69 struct nbns_rq *rqp;
70 struct nb_name nn;
71 struct nbns_rr rr;
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);
78 if (error)
79 return error;
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;
85 rqp->nr_qdname = &nn;
86 rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
87 rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
88 rqp->nr_qdcount = 1;
89 dest = &rqp->nr_dest;
90 *dest = ctx->nb_ns;
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);
100 if (error) {
101 nbns_rq_done(rqp);
102 return error;
104 rdrcount = NBNS_MAXREDIRECTS;
105 for (;;) {
106 error = nbns_rq(rqp);
107 if (error)
108 break;
109 if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
110 if (rdrcount-- == 0) {
111 error = NBERROR(NBERR_TOOMANYREDIRECTS);
112 break;
114 error = nbns_rq_getrr(rqp, &rr);
115 if (error)
116 break;
117 error = nbns_rq_getrr(rqp, &rr);
118 if (error)
119 break;
120 bcopy(rr.rr_data, &dest->sin_addr, 4);
121 rqp->nr_flags &= ~NBRQF_BROADCAST;
122 continue;
124 if (rqp->nr_rpancount == 0) {
125 error = NBERROR(NBERR_HOSTNOTFOUND);
126 break;
128 error = nbns_rq_getrr(rqp, &rr);
129 if (error)
130 break;
131 len = sizeof(struct sockaddr_in);
132 dest = malloc(len);
133 if (dest == NULL)
134 return ENOMEM;
135 bzero(dest, len);
136 dest->sin_len = len;
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;
142 break;
144 nbns_rq_done(rqp);
145 return error;
149 nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
151 struct nbns_rq *rqp;
152 static u_int16_t trnid;
153 int error;
155 rqp = malloc(sizeof(*rqp));
156 if (rqp == NULL)
157 return ENOMEM;
158 bzero(rqp, sizeof(*rqp));
159 error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
160 if (error) {
161 free(rqp);
162 return error;
164 rqp->nr_opcode = opcode;
165 rqp->nr_nbd = ctx;
166 rqp->nr_trnid = trnid++;
167 *rqpp = rqp;
168 return 0;
171 void
172 nbns_rq_done(struct nbns_rq *rqp)
174 if (rqp == NULL)
175 return;
176 if (rqp->nr_fd >= 0)
177 smb_kops.ko_close(rqp->nr_fd);
178 mb_done(&rqp->nr_rq);
179 mb_done(&rqp->nr_rp);
180 free(rqp);
184 * Extract resource record from the packet. Assume that there is only
185 * one mbuf.
188 nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
190 struct mbdata *mbp = &rqp->nr_rp;
191 u_char *cp;
192 int error, len;
194 bzero(rrp, sizeof(*rrp));
195 cp = mbp->mb_pos;
196 len = nb_encname_len(cp);
197 if (len < 1)
198 return NBERROR(NBERR_INVALIDRESPONSE);
199 rrp->rr_name = cp;
200 error = mb_get_mem(mbp, NULL, len);
201 if (error)
202 return error;
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);
209 return error;
213 nbns_rq_prepare(struct nbns_rq *rqp)
215 struct nb_ctx *ctx = rqp->nr_nbd;
216 struct mbdata *mbp = &rqp->nr_rq;
217 u_int8_t nmflags;
218 u_char *cp;
219 int len, error;
221 error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
222 if (error)
223 return error;
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);
228 if (error)
229 return error;
231 } else
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)
243 return EINVAL;
244 len = nb_name_len(rqp->nr_qdname);
245 error = mb_fit(mbp, len, (void **)(void *)&cp);
246 if (error)
247 return error;
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 */
255 return 0;
258 static int
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;
264 int s = rqp->nr_fd;
265 int n, len;
267 len = sizeof(sender);
268 n = smb_kops.ko_recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
269 (struct sockaddr*)&sender, &len);
270 if (n < 0) {
271 if (errno == EAGAIN)
272 return ETIMEDOUT;
273 return errno;
275 mbp->mb_top->m_len = mbp->mb_count = n;
276 rqp->nr_sender = sender;
277 return 0;
280 static int
281 nbns_rq_opensocket(struct nbns_rq *rqp)
283 struct sockaddr_in locaddr;
284 struct timeval tv;
285 int opt, s;
287 s = rqp->nr_fd = smb_kops.ko_socket(AF_INET, SOCK_DGRAM, 0);
288 if (s < 0)
289 return errno;
290 if (rqp->nr_flags & NBRQF_BROADCAST) {
291 opt = 1;
292 if (smb_kops.ko_setsockopt(s, SOL_SOCKET, SO_BROADCAST,
293 &opt, sizeof(opt)) < 0)
294 return errno;
295 tv.tv_sec = rqp->nr_nbd->nb_timo;
296 tv.tv_usec = 0;
297 if (smb_kops.ko_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
298 &tv, sizeof(tv)) < 0)
299 return errno;
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)
308 return errno;
310 return 0;
313 static int
314 nbns_rq_send(struct nbns_rq *rqp)
316 struct mbdata *mbp = &rqp->nr_rq;
317 int s = rqp->nr_fd;
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)
321 return errno;
322 return 0;
326 nbns_rq(struct nbns_rq *rqp)
328 struct mbdata *mbp = &rqp->nr_rq;
329 u_int16_t rpid;
330 u_int8_t nmflags;
331 int error, retrycount;
333 rqp->nr_if = nb_iflist;
334 again:
335 error = nbns_rq_opensocket(rqp);
336 if (error)
337 return error;
338 retrycount = 3; /* XXX - configurable */
339 for (;;) {
340 error = nbns_rq_send(rqp);
341 if (error)
342 return error;
343 error = nbns_rq_recv(rqp);
344 if (error) {
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);
351 goto again;
352 } else
353 return error;
355 retrycount--;
356 continue;
358 mbp = &rqp->nr_rp;
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);
364 break;
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;
371 if (rqp->nr_rprcode)
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);
377 return 0;