Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/aux/ncpfs/ncp.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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;
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].