Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/ndb/glean/browse.c

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


#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include "nbcache.h"

enum {	/* service type */
	STdfs = 0x00800000,
	STwin95 = 0x00400000,			/* win 95 or later */
	STvms = 0x00200000,
	STosf = 0x00100000,
	STdomain_master = 0x00080000,
	STmaster_browser = 0x00040000,
	STbackup_browser = 0x00020000,
	STpotential_browser = 0x00010000,
	STnt_server = 0x00008000,
	STmfpn = 0x00004000,			/* no one knows what this is */
	STwin_for_workgroups = 0x00002000,
	STnt_client = 0x00001000,
	STunix = 0x00000800,
	STdialin = 0x00000400,
	STprintq = 0x00000200,
	STdomain_member = 0x00000100,
	STnovell = 0x00000080,			/* is a novell server offering SMB */
	STapple = 0x00000040,			/* is an apple server offering SMB */
	STtime_source = 0x00000020,
	STdomain_bakctrl = 0x00000010,
	STdomain_ctrl = 0x00000008,
	STsqlserver = 0x00000004,
	STserver = 0x00000002,
	STworkstation = 0x00000001,
};

static void
nbrole(Attr *a, int type)
{
	int i, len;
	char buf[1023];
	struct {
		int n;
		char *s;
	} tab[] = {
		{ STdomain_master, "DMB" },
		{ STmaster_browser, "LMB" },
		{ STbackup_browser, "BMB" },
/*		{ STpotential_browser, "PMB" }, */
	};
	
	len = 0;
	*buf = 0;
	for(i = 0; i < nelem(tab); i++)
		if(tab[i].n & type)
			len += snprint(buf+len, sizeof(buf)-len, "%s ", tab[i].s);
	if(len >1){
		buf[len-1] = 0;
		addval(a, "nb-role", "%s", buf);
	}
}

static void
domrole(Attr *a, int type)
{
	int i, len;
	char buf[1023];
	struct {
		int n;
		char *s;
	} tab[] = {
		{ STdomain_ctrl, "DC" },
		{ STdomain_bakctrl, "BDC" },
	};
	
	len = 0;
	*buf = 0;
	for(i = 0; i < nelem(tab); i++)
		if(tab[i].n & type)
			len += snprint(buf+len, sizeof(buf)-len, "%s ", tab[i].s);
	if(len >1){
		buf[len-1] = 0;
		addval(a, "dom-role", "%s", buf);
	}
}

static void
host_info(Node *n, int type)
{
	int i, len;
	char buf[1023];
	struct {
		int n;
		char *s;
	} tab[] = {
		{ STsqlserver, "SQL" },
		{ STtime_source, "time" },
		{ STprintq, "print" },
		{ STdialin, "dialup" },
		{ STdfs, "DFS" }
	};
	
	len = 0;
	*buf = 0;
	for(i = 0; i < nelem(tab); i++)
		if(tab[i].n & type)
			len += snprint(buf+len, sizeof(buf)-len, "%s ", tab[i].s);
	if(len >1){
		buf[len-1] = 0;
		setval(n, "srv", "%s", buf);
	}
}


static void
osversion(Node *n, int svs, int osver, int brover)
{
	char buf[32], *base, *os;

	/* see http://msdn.microsoft.com/en-us/library/ms724833(VS.85).aspx  */

	switch(osver){
	case 0x2104:
		os = "Windows NT 4";
		break;
	case 0x0f01:
		if(svs & STunix)
			os = "FreeBSD Samba";
		else
			os = "Windows NT4";
		break;
	case 0x0601:
		if(svs & STworkstation)
			os = "Windows 7";
		else
			os = "Windows 2008 R2";
		break;
	case 0x0600:
		if(svs & STworkstation)
			os = "Windows Vista";
		else
			os = "Windows 2008";
		break;
	case 0x0502:
		if(svs & STworkstation)
			os = "Windows XP pro";
		else
			os = "Windows 2003";
		break;
	case 0x0501:
		os = "Windows XP";
		break;
	case 0x0500:
		os = "Windows 2000";
		break;
	case 0x045a:
		os = "Windows ME";
		break;
	case 0x040a:
		os = "Windows 98";
		break;
	case 0x041f:
		os = "HP laserjet";
		break;
	/*
	 * samba is somwhat unreliable as it is configurable
	 * using the "announce version" parameter in smb.conf,
	 * however these appear to be common values.
	 */
	case 0x0409:
	case 0x0402:				/* Pluto disk stores - FreeBSD and samba */
	case 0x0405:
		os = "Unix Samba";
		break;
	case 0x0403:
		os = "Windows 95 osr2";
		break;
	case 0x0400:
		if(svs & STwin95)
			os = "Windowsn 95";
		else
		if(brover == 0x0f01)
			os = "Netware NFA";
		else
			os = "Windows NT4";
		break;
	case 0x0333:
		os = "Windows NS 3.15";
		break;
	case 0x0300:
		os = "Windows CE 3.0";
		break;
	case 0x0201:
		os = "Windows CE 2.1";
		break;
	case 0x0200:
		os = "Windows CE 2.0";
		break;
	case 0x0100:
		os = "Windows CE 1.0";
		break;
	default:
		base = "Windows";
		if(svs & STunix)
			base = "Unix";
		if(svs & STosf)
			base = "OSF Unix";
		if(svs & STvms)
			base = "VMS Pathworks";
		if(svs & STwin_for_workgroups)
			base = "Windows for workgroups";
		if(svs & STnovell)
			base = "Novell";
		if(svs & STapple)
			base = "Apple";
		snprint(buf, sizeof(buf), "%s os=%d.%d brow=%d.%d", base,
			osver >> 8, osver & 0xff,
			brover >> 8, brover & 0xff);
		os = buf;
		break;
	}

	setval(n, "hinfo", "%s", os);
}

/* NB: we don't need dom= if it is same as the name without its suffix */

void
browse(Pkt *p)
{
	Node *n;
	Attr *a;
	ulong ttl, period;
	uchar ip[IPv4addrlen];
	int type, brover, osver, cmd;
	char *s, name[20], comment[48], srcname[64], dstname[64];
	static uchar zeros[IPv4addrlen];

	/**************************
	 * Netbios header
	 */
	if(r8(p) != 0x11)		/* type != direct datagram */
		return;
	r8(p);				/* flags */
	rl16(p);			/* datagram ID */
	rmem(p, ip, IPv4addrlen);	/* source IP */
	rl16(p);			/* source port */
	rl16(p);			/* datagram length */
	rl16(p);			/* packet offset */
	rnbname(p, srcname, sizeof(srcname));	/* source name */
	srcname[15] = 0;
	strlwr(srcname);
	trim(srcname, ' ');
	rnbname(p, dstname, sizeof(dstname));	/* destination name */
	dstname[15] = 0;
	strlwr(dstname);
	trim(dstname, ' ');

	/**************************
	 * SMB header
	 */
	skip(p, 32);
	
	/**************************
	 * SMB mailslot protocol header
	 */
	skip(p, 36 +18);

	/**************************
	 * Browser protocol packet
	 */
	cmd = r8(p);			/* command */
	if(cmd != 1 && cmd != 12 && cmd != 15)
		return;

	r8(p);				/* update count */
	period = rl32(p);		/* update period in milliseconds */
	rmem(p, name, 16);		/* netbios name */
	name[15] = 0;
	strlwr(name);
	osver = rb16(p);		/* OS version */
	type = rl32(p);			/* server type */

	/*
	 * Update period is in milliseconds.
	 * Names expire after 3 re-broadcast intervals.
	 * This appears to be 3 * 12 mins.
	 */
	ttl = period / 333;

	switch(cmd){
	case 1:				/* workstation announcemenet */
	case 15:			/* Local master announcement */
		brover = rb16(p);	/* protocol version */
		rl16(p);		/* magic number */
		rstr(p, comment, sizeof(comment));
		n = getnode(Thost, ttl, "%s", name);
		if(memcmp(ip, zeros, IPv4addrlen) != 0){
			a = setval(n, "ip", "%V", ip);
			adapter_status(a, ttl, ip);
		}
		else
		if((s = csgetvalue(Netdir, "sys", name, "ip", nil)) != nil){
			a = setval(n, "ip", "%s", s);	
			v4parseip(ip, s);
			adapter_status(a, ttl, ip);
		}
		if(*comment)
			setval(n, "txt", "%s", comment);
		osversion(n, type, osver, brover);
		host_info(n, type);
		if(Debug)
			setval(n, "src", "browse");

		n = getnode(Tdomain, ttl, "%s", dstname);
		a = setval(n, "member", "%s", name);
		nbrole(a, type);
		domrole(a, type);
		break;
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.