#include <u.h>
#include <libc.h>
#include <ctype.h>
#include "ncp.h"
/* nameing - pb32() == put, bigendian, 32bit value etc. */
int
ncphdr(Session *s, int func, int type)
{
s->type = type;
s->p = s->buf;
memset(s->buf, 0, s->mtu);
pb32(s, s->txsig); // signature
pb32(s, 0); // packet len (filled in later)
pb32(s, NCPVER); // packet version
pb32(s, s->mtu); // max reply length
pb16(s, Mrequest); // packet type = request
p8(s, s->seq); // sequence number
p8(s, s->conn & 0xff); // server's connection # MSB
p8(s, s->task); // client's transaction nesting
p8(s, (s->conn >> 8) & 0xff); // server's connection # MSB
p8(s, (func >> 8) & 0xff); // function # MSB
switch(s->type){
case Tvarlen:
pb16(s, 0); // subfunction length (filled in later)
p8(s, func & 0xff); // subfunction code
break;
case Tsubfun:
p8(s, func & 0xff); // subfunction code
break;
case Tsimple:
break;
default:
sysfatal("internal error: bad subfunc type 0x%02x\n", type);
}
return 0;
}
static int
getpkt(Session *s)
{
long sig;
int want, got;
uchar preamble = s->rxsig >> 24;
s->p = s->buf;
memset(s->buf, 0, s->mtu);
do {
if (read(s->fd, s->p, 1) < 1)
return -1;
} while (*s->p != preamble);
s->p++;
want = 7;
if ((got = readn(s->fd, s->p, want)) != want){
if (got >= 0)
werrstr("media: short read (%d < %d)", got, want);
return -1;
}
s->p = s->buf;
if ((sig = gb32(s)) != s->rxsig){
werrstr("media: bad packet signature (%lux != %lux)", sig, s->rxsig);
return -1;
}
if ((s->rxlen = gb32(s)) > s->mtu){
werrstr("media: packet too big (%d > %d)", s->rxlen, s->mtu);
return -1;
}
want = s->rxlen - (s->p - s->buf);
if ((got = readn(s->fd, s->p, want)) != want){
werrstr("media: short payload read (%d < %d)", got, want);
return -1;
}
return s->rxlen;
}
int
ncpcall(Session *s)
{
int err;
ushort msg;
int len = (s->p - s->buf);
s->buf[4] = len >> 24;
s->buf[5] = len >> 16;
s->buf[6] = len >> 8;
s->buf[7] = len;
if (s->type == Tvarlen){
s->buf[23] = (len-26) >> 8;
s->buf[24] = (len-26);
}
if (s->buf[16] != 0x22 || s->buf[17] != 0x22){
fprint(2, "ncpcall() called before ncphdr()\n");
abort();
}
if (Debug)
fprint(2, "TX %N", s->buf);
if (write(s->fd, s->buf, s->p - s->buf) == -1){
werrstr("media: write failed");
return -1;
}
if (getpkt(s) == -1)
return -1;
if (Debug)
fprint(2, "RX %N", s->buf);
/*
* NB: signature and packet length
* already parsed and checked
*/
msg = gb16(s);
switch(msg){
case Mreply:
break;
case Mdisconnected: /* experience tells us this */
sysfatal("disconnected");
return -1;
default:
werrstr("0x%04x - unexpected packet type", msg);
return -1;
}
if (g8(s) != s->seq){
werrstr("incorrect sequence number");
return -1;
}
s->seq = (s->seq +1) % 256;
if (g8(s) != (s->conn & 0xff)){
werrstr("bad connection # LSB");
return -1;
}
if (g8(s) != s->task){
werrstr("unexpected task #");
return -1;
}
if (g8(s) != ((s->conn >> 8) & 0xff)){
werrstr("bad connection # MSB");
return -1;
}
if ((err = g8(s)) != 0){
werrstr("%s", nwerrstr(err));
return -1;
}
if ((err = g8(s)) != 0){
if (err & (1 << 6))
fprint(2, "broadcast message waiting");
else{
if (err & (1 << 0))
werrstr("bad service connection");
if (err & (1 << 2))
werrstr("no connections avaliable");
if (err & (1 << 4))
werrstr("server is down");
return -1;
}
}
return 0;
}
void
pmem(Session *s, void *v, int len)
{
uchar *str = v;
while(len--)
*s->p++ = *str++;
}
void
pstr(Session *s, char *str)
{
*s->p++ = strlen(str);
while(*str)
*s->p++ = *str++;
}
void
pb32(Session *s, uint n)
{
*(s->p++) = (n >> 24) & 0xff;
*(s->p++) = (n >> 16) & 0xff;
*(s->p++) = (n >> 8) & 0xff;
*(s->p++) = n & 0xff;
}
void
pl32(Session *s, uint n)
{
*(s->p++) = n & 0xff;
*(s->p++) = (n >> 8) & 0xff;
*(s->p++) = (n >> 16) & 0xff;
*(s->p++) = (n >> 24) & 0xff;
}
void
pb16(Session *s, ushort n)
{
*(s->p++) = (n >> 8) & 0xff;
*(s->p++) = n & 0xff;
}
void
pl16(Session *s, ushort n)
{
*(s->p++) = n & 0xff;
*(s->p++) = (n >> 8) & 0xff;
}
void
p8(Session *s, uchar n)
{
*(s->p++) = n & 0xff;
}
/*
* get & translate 32bit file descriptor
* into a 48 bit file handle
*/
void
gfhand32(Session *s, Fh fh)
{
uchar *p = fh;
long n = gb32(s);
*p++ = ((n+1) >> 8) & 0xff;
*p++ = (n+1) & 0xff;
*p++ = (n >> 24) & 0xff;
*p++ = (n >> 16) & 0xff;
*p++ = (n >> 8) & 0xff;
*p++ = n & 0xff;
USED(p);
}
void
ginfo(Session *s, FInfo *fi)
{
gl32(s); // data space allocated - in 4k blocks
fi->attr = gl32(s);
fi->flags = gl16(s);
fi->size = gl32(s);
gl32(s); // total space allocated - in 4k blocks
gl16(s); // number of data streams
fi->created = gdatetime(s);
fi->creator = gb32(s);
fi->modified = gdatetime(s);
fi->modifier = gb32(s);
fi->accessed = gdate(s);
fi->archived = gdatetime(s);
fi->archiver = gb32(s);
fi->rights = gl16(s);
fi->dirent = gl32(s);
fi->dosdir = gl32(s);
fi->vol = gl32(s);
gl32(s); // extended attributes
gl32(s); // extended attributes
gl32(s); // extended attributes
fi->creatns = gl32(s);
gstr(s, fi->name, PATHLEN);
}
/*
* Convert Unix style path to a NetwareHandlePathStruct
*/
void
phps(Session *s, char *str)
{
uchar *noc; // num of components
uchar *ccl; // current component length
if (*str == '/') // should always be absolute paths
str++;
p8(s, 0); // volume number (none)
pl32(s, 0); // directory base / handle (none)
p8(s, 0xff); // flags (no handles present)
noc = s->p++; // path component count
*noc = 0;
for(ccl = s->p++ ; ; str++, s->p++){
if (! *str){
*ccl = (s->p - ccl) -1;
(*noc)++;
break;
}
if (*str == '/'){
*ccl = (s->p - ccl) -1;
ccl = s->p;
(*noc)++;
}
*s->p = *str;
}
}
/*
* Special, two path version of PathHandleStruct used only by
* Rename Or Move a File or Subdirectory,
* appearently to save space (though it doesn't).
*/
void
pphs2(Session *s, char *s1, char *s2)
{
int i;
uchar *noc[2]; // num of components
uchar *ccl; // current component length
char *str[2] = {s1, s2};
if (*str[0] == '/') // should always be absolute paths
str[0]++;
p8(s, 0); // volume number (none)
pl32(s, 0); // directory base / handle (none)
p8(s, 0xff); // flags (no handles present)
noc[0] = s->p++; // path component count
*noc[0] = 0;
if (*str[1] == '/') // should always be absolute paths
str[1]++;
p8(s, 0); // volume number (none)
pl32(s, 0); // directory base / handle (none)
p8(s, 0xff); // flags (no handles present)
noc[1] = s->p++; // path component count
*noc[1] = 0;
for (i = 0; i < 2; i++){
for(ccl = s->p++ ; ; str[i]++, s->p++){
if (! *str[i]){
*ccl = (s->p - ccl) -1;
(*noc[i])++;
break;
}
if (*str[i] == '/'){
*ccl = (s->p - ccl) -1;
ccl = s->p;
(*noc[i])++;
}
*s->p = *str[i];
}
}
}
void
gmem(Session *s, void *v, int len)
{
uchar *str = v;
while(len--)
*str++ = *s->p++;
}
void
gstr(Session *s, char *str, int maxlen)
{
int len;
char *eos;
len = *s->p++;
if (len > maxlen)
len = maxlen;
eos = str + len;
while(len--)
*str++ = *s->p++;
*eos = 0;
}
uint
gb32(Session *s)
{
uint n;
n = *s->p++ << 24;
n |= *s->p++ << 16;
n |= *s->p++ << 8;
n |= *s->p++;
return n;
}
uint
gl32(Session *s)
{
uint n;
n = *s->p++;
n |= *s->p++ << 8;
n |= *s->p++ << 16;
n |= *s->p++ << 24;
return n;
}
ushort
gb16(Session *s)
{
ushort n;
n = *s->p++ << 8;
n |= *s->p++;
return n;
}
ushort
gl16(Session *s)
{
ushort n;
n = *s->p++;
n |= *s->p++ << 8;
return n;
}
uchar
g8(Session *s)
{
return *s->p++;
}
void
pdatetime(Session *s, long utc)
{
Tm *tm = localtime(utc);
pl16(s, tm->mday | ((tm->mon +1) << 5) | ((tm->year -80) << 9));
pl16(s, (tm->hour << 11) | (tm->min << 5) | (tm->sec >> 1));
}
void
pdate(Session *s, long utc)
{
Tm *tm = localtime(utc);
pl16(s, tm->mday | ((tm->mon +1) << 5) | ((tm->year -80) << 9));
}
/*
* get a packed date and time
*/
long
gdatetime(Session *s)
{
int ti = gl16(s);
int da = gl16(s);
Tm *tm = localtime(time(nil));
tm->year = (da >> 9) + 80;
tm->mon = ((da >> 5) & 0xf) - 1;
tm->mday = da & 0x1f;
tm->hour = ti >> 11;
tm->min = (ti >> 5) & 0x3f;
tm->sec = (ti << 1) & 0x3f;
return tm2sec(tm);
}
/*
* get a packed date only
*/
long
gdate(Session *s)
{
int da = gl16(s);
Tm *tm = localtime(time(nil));
tm->hour = 0;
tm->min = 0;
tm->sec = 0;
tm->year = (da >> 9) +80;
tm->mon = ((da >> 5) & 0xf) -1;
tm->mday = da & 0x1f;
return tm2sec(tm);
}
long
gtbuf(Session *s)
{
Tm *tm;
tm = localtime(time(nil));
tm->year = *(s->p++);
tm->mon = *(s->p++) -1;
tm->mday = *(s->p++);
tm->hour = *(s->p++);
tm->min = *(s->p++);
tm->sec = *(s->p++);
return tm2sec(tm);
}
char *
strupr(char *s)
{
char *p;
for(p = s; *p; p++)
if (islower(*p))
*p = toupper(*p);
return s;
}
char *
strlwr(char *s)
{
char *p;
for(p = s; *p; p++)
if (isupper(*p))
*p = tolower(*p);
return s;
}
|