import less(1)
[unleashed/tickless.git] / usr / src / lib / libsmbfs / smb / nb_ssn.c
blob319e2502967d0da0cfdfb01dac58970553a77516
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * NetBIOS session service functions
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <libintl.h>
36 #include <xti.h>
37 #include <assert.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/poll.h>
43 #include <netsmb/netbios.h>
44 #include <netsmb/smb_lib.h>
45 #include <netsmb/nb_lib.h>
46 #include <netsmb/mchain.h>
48 #include "private.h"
49 #include "charsets.h"
51 static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
52 static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
53 static int nb_ssn_pollin(struct smb_ctx *, int);
56 * Send a data message.
58 int
59 smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
61 return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
65 * Send a NetBIOS message, after
66 * prepending the 4-byte header.
68 static int
69 nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
70 int mtype, int mlen)
72 mbuf_t *m;
73 uint32_t hdr, hdrbuf;
74 int err;
76 m = mbp->mb_top;
77 if (m == NULL)
78 return (EINVAL);
81 * Prepend the NetBIOS header.
82 * Our mbufs leave space for this.
84 hdr = (mtype << 24) | mlen;
85 hdrbuf = htonl(hdr);
86 m->m_data -= 4;
87 m->m_len += 4;
88 bcopy(&hdrbuf, m->m_data, 4);
91 * Get contiguous data (so TCP won't fragment)
92 * Note: replaces mb_top.
94 err = m_lineup(mbp->mb_top, &mbp->mb_top);
95 if (err)
96 return (err);
97 m = mbp->mb_top;
100 * Send it.
102 if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
103 if (t_errno == TSYSERR)
104 err = errno;
105 else
106 err = EPROTO;
107 DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
108 return (err);
111 return (0);
115 * Receive a data message. Discard anything else.
116 * Caller must deal with EAGAIN, EINTR.
119 smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
121 int err, mtype, mlen;
122 err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
123 if (err)
124 return (err);
125 if (mtype != NB_SSN_MESSAGE) {
126 DPRINT("discard type 0x%x", mtype);
127 mb_done(mbp);
128 return (EAGAIN);
130 if (mlen == 0) {
131 DPRINT("zero length");
132 mb_done(mbp);
133 return (EAGAIN);
136 return (0);
140 * Receive a NetBIOS message, any type.
141 * Give caller type and length.
143 static int
144 nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
145 int *mtype, int *mlen)
147 char *buf;
148 uint32_t hdr, hdrbuf;
149 int cnt, len, err, moreflag;
150 int fd = ctx->ct_tran_fd;
151 int tmo = smb_recv_timeout * 1000;
154 * Start by getting the header
155 * (four bytes)
157 if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
158 DPRINT("pollin err %d", err);
159 return (err);
161 moreflag = 0;
162 cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
163 if (cnt < 0) {
164 err = get_xti_err(fd);
165 DPRINT("t_errno %d err %d", t_errno, err);
166 return (err);
169 if (cnt != sizeof (hdrbuf)) {
170 DPRINT("hdr cnt %d", cnt);
171 return (EPROTO);
175 * Decode the header, get the length.
177 hdr = ntohl(hdrbuf);
178 *mtype = (hdr >> 24) & 0xff;
179 *mlen = hdr & 0xffffff;
181 if (mlen == 0)
182 return (0);
185 * Get a message buffer, read the payload
187 if ((err = mb_init_sz(mb, *mlen)) != 0)
188 return (err);
189 buf = mb->mb_top->m_data;
190 len = *mlen;
191 while (len > 0) {
192 if (!moreflag) {
193 if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
194 DPRINT("pollin err %d", err);
195 return (err);
199 moreflag = 0;
200 cnt = t_rcv(fd, buf, len, &moreflag);
201 if (cnt < 0) {
202 err = get_xti_err(fd);
203 DPRINT("t_errno %d err %d", t_errno, err);
204 return (err);
206 buf += cnt;
207 len -= cnt;
209 mb->mb_top->m_len = *mlen;
210 mb->mb_count = *mlen;
212 return (0);
216 get_xti_err(int fd)
218 int look;
219 if (t_errno == TSYSERR)
220 return (errno);
222 if (t_errno == TLOOK) {
223 look = t_look(fd);
224 switch (look) {
225 case T_DISCONNECT:
226 (void) t_rcvdis(fd, NULL);
227 (void) t_snddis(fd, NULL);
228 return (ECONNRESET);
229 case T_ORDREL:
230 /* Received orderly release indication */
231 (void) t_rcvrel(fd);
232 /* Send orderly release indicator */
233 (void) t_sndrel(fd);
234 return (ECONNRESET);
237 return (EPROTO);
241 * Wait for data we can receive.
242 * Timeout is mSec., as for poll(2)
244 static int
245 nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
247 struct pollfd pfd[1];
248 int cnt, err;
250 pfd[0].fd = ctx->ct_tran_fd;
251 pfd[0].events = POLLIN | POLLPRI;
252 pfd[0].revents = 0;
253 cnt = poll(pfd, 1, tmo);
254 switch (cnt) {
255 case 0:
256 err = ETIME;
257 break;
258 case -1:
259 err = errno;
260 break;
261 default:
262 err = 0;
263 break;
265 return (err);
269 * Send a NetBIOS session request and
270 * wait for the response.
273 nb_ssn_request(struct smb_ctx *ctx, char *srvname)
275 struct mbdata req, res;
276 struct nb_name lcl, srv;
277 int err, mtype, mlen;
278 char *ucwks;
280 bzero(&req, sizeof (req));
281 bzero(&res, sizeof (res));
283 if ((err = mb_init(&req)) != 0)
284 goto errout;
286 ucwks = utf8_str_toupper(ctx->ct_locname);
287 if (ucwks == NULL) {
288 err = ENOMEM;
289 goto errout;
292 /* Local NB name. */
293 snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
294 lcl.nn_type = NBT_WKSTA;
295 lcl.nn_scope = ctx->ct_nb->nb_scope;
297 /* Server NB name */
298 snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
299 srv.nn_type = NBT_SERVER;
300 srv.nn_scope = ctx->ct_nb->nb_scope;
303 * Build the request. Header is prepended later.
305 if ((err = nb_name_encode(&req, &srv)) != 0)
306 goto errout;
307 if ((err = nb_name_encode(&req, &lcl)) != 0)
308 goto errout;
311 * Send it, wait for the reply.
313 err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
314 if (err) {
315 DPRINT("send, err %d", err);
316 goto errout;
318 err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
319 if (err) {
320 DPRINT("recv, err %d", err);
321 goto errout;
324 if (mtype != NB_SSN_POSRESP) {
325 DPRINT("recv, mtype 0x%x", mtype);
326 err = ECONNREFUSED;
327 goto errout;
330 return (0);
332 errout:
333 mb_done(&res);
334 mb_done(&req);
335 return (err);