--- /sys/./arch/i386/conf/files.i386	Sun Mar 16 04:26:46 2003
+++ /home/s0mbre/OpenBSD/sys/./arch/i386/conf/files.i386	Thu Mar 13 17:20:38 2003
@@ -87,6 +81,10 @@
 file	arch/i386/i386/mainbus.c	mainbus
 
 #device	mca at root {...}
+
+device ncons
+attach ncons at mainbus
+file dev/ncons.c			ncons
 
 #
 # PCI-only drivers
--- /sys/./arch/i386/i386/conf.c	Tue Mar 11 03:44:23 2003
+++ /home/s0mbre/OpenBSD/sys/./arch/i386/i386/conf.c	Wed Mar 12 21:21:25 2003
@@ -498,6 +496,10 @@
 cons_decl(com);
 cons_decl(ws);
 
+#include <dev/ncons.h>
+cons_decl(nc_);
+
+
 struct	consdev constab[] = {
 #if NWSDISPLAY > 0
 	cons_init(ws),
@@ -505,5 +507,6 @@
 #if NCOM + NPCCOM > 0
 	cons_init(com),
 #endif
+	cons_init(nc_),
 	{ 0 },
 };
--- /dev/null	Mon Mar 24 23:36:23 2003
+++ /home/s0mbre/OpenBSD/sys/./dev/ncons.h	Thu Mar 20 19:38:30 2003
@@ -0,0 +1,33 @@
+/*
+ * dev/ncons.h
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef NCONS_H
+#define NCONS_H
+
+#define NCONS_MAJ	123
+
+void nc_cnprobe(struct consdev *);
+void nc_cninit(struct consdev *);
+int  nc_cngetc(dev_t);
+void nc_cnputc(dev_t, int);
+void nc_cnpollc(dev_t, int);
+
+#endif
--- /dev/null	Mon Mar 24 23:36:23 2003
+++ /home/s0mbre/OpenBSD/sys/./dev/ncons.c	Mon Mar 24 23:32:05 2003
@@ -0,0 +1,347 @@
+/*	$OpenBSD$	*/
+/*
+ * dev/ncons.c
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>	
+#include <sys/queue.h>
+#include <sys/domain.h>
+#include <sys/tty.h>
+
+#include <machine/biosvar.h>
+#include <machine/conf.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <dev/cons.h>
+#include <dev/ncons.h>
+#include <dev/rndvar.h>
+
+
+#undef NC_DEBUG
+
+struct nconf_softc {
+	struct device dev;
+};
+
+static int ncons_activated, ncons_in_use;
+static struct ifnet **nc_ifp;
+static int nc_ifp_count;
+
+#define SIZE	2
+static char buf[SIZE];
+
+/* Error "messages" displayed while struct mbuf is processed.
+ *
+ * 'G' - can't get struct mbuf from pool... 
+ * 		It looks like machine will simply reboot in this case.
+ * 'f' - per interface queue is full after IFQ_ENQUEUE().
+ * 		This will be displayed before m_free() will be called.
+ * 'F' - per interface queue is full even after m_free() was called.
+ * 		Is it really possible?
+ * 'E' - failed to enqueue new struct mbuf into the per interface queue.
+ */
+extern void wscnputc(dev_t, int); /* For error "messages" */
+
+int ncons_match(struct device *, void *, void *);
+void ncons_attach(struct device *, struct device *, void *);
+int ncons_detach(struct device *, int);
+int ncons_activate(struct device *, enum devact);
+
+struct cfattach ncons_ca = {
+	sizeof(struct nconf_softc),
+	ncons_match,
+	ncons_attach,
+	ncons_detach,
+	ncons_activate
+};
+
+struct cfdriver ncons_cd = {
+	NULL, "ncons", DV_TTY
+};
+
+int ncons_match(struct device *parent, void *match, void *aux)
+{
+	return 1;
+}
+
+void ncons_attach(struct device *parent, struct device *self, void *aux)
+{	
+	printf(" : Network console attached.\n");
+}
+
+int ncons_detach(struct device *self, int flags)
+{
+	printf("Network console detached.\n");
+	ncons_activated = 0;
+	if (nc_ifp)
+		free(nc_ifp, M_MBUF);
+	return 1;
+}
+
+int ncons_activate(struct device *self, enum devact act)
+{
+	struct ifnet *ifp = NULL;
+
+	if (ncons_activated)
+		return nc_ifp_count;
+
+	nc_ifp = (struct ifnet **)malloc(if_index*sizeof(struct ifnet *), 
+						M_MBUF, M_NOWAIT);
+	if (nc_ifp == NULL)
+	{
+		printf("%s: malloc problems. Exiting.\n", __func__);
+		return nc_ifp_count;
+	}
+	memset(nc_ifp, 0, if_index*sizeof(struct ifnet *));
+
+	TAILQ_FOREACH(ifp, &ifnet, if_list)
+	{
+		if ((ifp->if_flags & IFF_LOOPBACK) || 
+				(ifp->if_flags & IFF_POINTOPOINT))
+			continue;
+		
+		/* Mark interface running ... */
+		/* It looks like it is not sufficient ... */
+		/* FIXME */
+		ifp->if_flags |= IFF_UP;
+		ifp->if_flags |= IFF_RUNNING;
+//		IFQ_SET_MAXLEN(&ifp->if_snd, 100);
+		//ifp->if_flags |= IFF_OACTIVE;
+		nc_ifp[nc_ifp_count++] = ifp;
+	}
+	if (nc_ifp_count == 0)
+		return 0;
+	
+	ncons_activated = 1;
+	
+	return (nc_ifp_count);
+}
+
+void nc_cnprobe(struct consdev *dev)
+{
+	dev->cn_pri = CN_NORMAL;
+	dev->cn_dev = makedev(NCONS_MAJ, 0);
+}
+
+void nc_cninit(struct consdev *dev)
+{
+}
+
+int nc_cngetc(dev_t dev)
+{
+	return 0;
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ *	By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ *	Arnt Gulbrandsen.
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+					  unsigned int ihl)
+{
+	unsigned int sum;
+
+	__asm__ __volatile__(
+	    "movl (%1), %0	;\n"
+	    "subl $4, %2	;\n"
+	    "jbe 2f		;\n"
+	    "addl 4(%1), %0	;\n"
+	    "adcl 8(%1), %0	;\n"
+	    "adcl 12(%1), %0	;\n"
+"1:	    adcl 16(%1), %0	;\n"
+	    "lea 4(%1), %1	;\n"
+	    "decl %2		;\n"
+	    "jne 1b		;\n"
+	    "adcl $0, %0	;\n"
+	    "movl %0, %2	;\n"
+	    "shrl $16, %0	;\n"
+	    "addw %w2, %w0	;\n"
+	    "adcl $0, %0	;\n"
+	    "notl %0		;\n"
+"2:				;\n"
+	/* Since the input registers which are loaded with iph and ipl
+	   are modified, we must also specify them as outputs, or gcc
+	   will assume they contain their original values. */
+	: "=r" (sum), "=r" (iph), "=r" (ihl)
+	: "1" (iph), "2" (ihl));
+	return(sum);
+}
+
+void nc_cnputc(dev_t dev, int c)
+{
+	struct mbuf *m;
+	struct ifnet *ifp;
+	struct ip *ip;
+	struct udphdr * udp;
+	struct ether_header *eth;
+	char e_daddr[ETHER_ADDR_LEN] = {0,0x01,0x02,0x6d,0x31,0x7a};
+	char e_saddr[ETHER_ADDR_LEN] = {0,0xc0,0xdf,0xfa,0x80,0x9a};
+	int error = 0, msg_len = SIZE, s, i;
+	static int count = 0;
+
+	/* Races */
+	if (!ncons_activated || ncons_in_use)
+		return;
+	
+	ncons_in_use = 1;
+
+	s = splimp();
+
+	if (count < msg_len)
+	{
+		if ((char)c == 0)
+			(char)c = '_';
+		buf[count] = (char)c;
+		if (++count < msg_len) 
+		{
+			splx(s);
+			ncons_in_use = 0;
+			return;
+		}
+	}
+	count = 0;
+
+	MGETHDR(m, M_DONTWAIT, MT_DATA); 
+	/* Hope MHLEN is sufficient... */
+	if (m == NULL)
+	{
+		splx(s);
+		wscnputc(dev, 'G');
+		ncons_in_use = 0;
+		return;
+	}
+	m->m_len = m->m_pkthdr.len = 
+				sizeof(struct ip) + 
+				sizeof(struct udphdr) + 
+				sizeof(struct ether_header) + msg_len;
+	MH_ALIGN(m, m->m_len);
+	memset(m->m_data, '_', m->m_len);
+
+	eth = mtod(m, struct ether_header *);
+	bcopy(e_daddr, eth->ether_dhost, ETHER_ADDR_LEN);
+	bcopy(e_saddr, eth->ether_shost, ETHER_ADDR_LEN);
+	eth->ether_type = htons(ETHERTYPE_IP);
+
+	m->m_data += sizeof(struct ether_header);
+	ip = mtod(m, struct ip *);
+	ip->ip_v 		= 	4;
+	ip->ip_off 		= 	0;
+	ip->ip_hl 		= 	5;
+	ip->ip_tos 		= 	0;
+	ip->ip_id 		= 	arc4random();
+	ip->ip_ttl		=	64;
+	ip->ip_p		=	IPPROTO_UDP;
+	ip->ip_len 		= 	htons(m->m_len - sizeof(struct ether_header));
+	ip->ip_sum		=	0;
+	ip->ip_src.s_addr	=	0x0100000a;
+	ip->ip_dst.s_addr	=	0x0200000a;
+	ip->ip_sum		=	ip_fast_csum((unsigned char *)ip, 
+							ip->ip_hl);
+	
+	m->m_data += sizeof(struct ip);
+	udp = mtod(m, struct udphdr *);
+	udp->uh_sport		=	htons(5555);
+	udp->uh_dport		=	htons(6666);
+	udp->uh_ulen		=	htons(msg_len + sizeof(struct udphdr));
+	udp->uh_sum		=	0;
+	udp->uh_sum		=	ip_fast_csum((unsigned char *)
+						(m->m_data - sizeof(struct ip)), 
+						(m->m_len>>3));
+	
+	bcopy(buf, m->m_data + sizeof(struct udphdr), msg_len);
+
+	m->m_data -= (sizeof(struct ip) + sizeof(struct ether_header));
+	
+	for (i=0; i<nc_ifp_count; ++i)
+	{
+		ifp = nc_ifp[i];
+		if (!m)
+			break;
+		
+		if (!strncmp(ifp->if_xname, "ne", 2))
+		{
+			if (IF_QFULL(&ifp->if_snd))
+			{
+				if (m)
+					m_free(m);
+				m = NULL;
+				wscnputc(dev, 'f');
+				break;
+			}
+			error = 0;
+			IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
+			if (error)
+			{
+				/* m already freed */
+				m = NULL;
+				wscnputc(dev, 'E');
+				if (IF_QFULL(&ifp->if_snd))
+					wscnputc(dev, 'F');
+				break;
+			}
+			ifp->if_obytes += m->m_len;
+			
+			/* If it doesn't work, see netinet/if_ether.c:revarprequest() */
+//			if (!(ifp->if_flags & IFF_OACTIVE))
+				(*ifp->if_start)(ifp);
+			(*ifp->if_intr)(ifp->if_softc);
+			m = NULL;
+			break;
+		}
+	}
+
+	if (m)
+		m_free(m);
+	m = NULL;
+	memset(buf, '_', SIZE);
+	
+	splx(s);
+	
+	ncons_in_use = 0;
+	
+}
+
+void nc_cnpollc(dev_t dev, int i)
+{
+}
--- /sys/./dev/cons.c	Tue Apr 17 08:30:49 2001
+++ /home/s0mbre/OpenBSD/sys/./dev/cons.c	Thu Mar 13 19:55:34 2003
@@ -55,6 +55,7 @@
 #include <sys/vnode.h>
 
 #include <dev/cons.h>
+#include <dev/ncons.h> /* For NCONS_MAJ */
 
 struct	tty *constty = NULL;	/* virtual console output device */
 struct	consdev *cn_tab;	/* physical console device info */
@@ -67,10 +68,14 @@
 	struct proc *p;
 {
 	dev_t cndev;
+	struct consdev *cp;
 
 	if (cn_tab == NULL)
 		return (0);
-
+	
+	for (cp = constab; cp->cn_probe; cp++)
+		(*cp->cn_probe)(cp);
+	
 	/*
 	 * always open the 'real' console device, so we don't get nailed
 	 * later.  This follows normal device semantics; they always get
@@ -157,6 +162,7 @@
 		return ENXIO;
 	else
 		dev = cn_tab->cn_dev;
+
 	return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
 }
 
@@ -257,14 +263,19 @@
 cnputc(c)
 	register int c;
 {
+	struct consdev *cp;
 
 	if (cn_tab == NULL)
 		return;			
 
 	if (c) {
-		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
-		if (c == '\n')
-			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+		for (cp = constab; cp->cn_putc; cp++) {
+			if (major(cp->cn_dev) != NCONS_MAJ && cp != constab)
+				continue;
+			(*cp->cn_putc)(cp->cn_dev, c);
+			if (c == '\n')
+				(*cp->cn_putc)(cp->cn_dev, '\r');
+		}
 	}
 }
 
--- /sys/./kern/init_main.c	Thu Mar  6 20:06:18 2003
+++ /home/s0mbre/OpenBSD/sys/./kern/init_main.c	Thu Mar 20 23:02:01 2003
@@ -159,6 +159,8 @@
 	esigcode,
 };
 
+extern int consintr;
+
 /*
  * System startup; initialize the world, create process 0, mount root
  * filesystem, and fork to create init and pagedaemon.  Most of the
@@ -170,23 +172,27 @@
 main(framep)
 	void *framep;				/* XXX should go away */
 {
-	struct proc *p;
-	struct pdevinit *pdev;
+	register struct proc *p;
+	register struct pdevinit *pdev;
 	struct timeval rtv;
+	register int i;
 	quad_t lim;
-	int s, i;
+	int s;
 	register_t rval[2];
 	extern struct pdevinit pdevinit[];
 	extern void scheduler_start(void);
 	extern void disk_init(void);
 	extern void endtsleep(void *);
 	extern void realitexpire(void *);
+	struct device *dev, *next_dev;
+	int savintr, rv;
 
 	/*
 	 * Initialize the current process pointer (curproc) before
 	 * any possible traps/probes to simplify trap processing.
 	 */
-	curproc = p = &proc0;
+	p = &proc0;
+	curproc = p;
 
 	/*
 	 * Attempt to find console and initialize
 
@@ -358,6 +357,32 @@
 	if_attachdomain();
 	splx(s);
 
+	rv = 0;
+	s = splhigh();
+	savintr = consintr;
+	consintr = 0;
+//	printf("%s: probing devices: ", __func__);
+	for (dev = TAILQ_FIRST(&alldevs); dev != NULL; dev = next_dev) 
+	{
+		next_dev = TAILQ_NEXT(dev, dv_list);
+//		printf ("%s ", dev->dv_xname);
+		if (!strncmp(dev->dv_xname, "ncons", 5))
+		{
+			struct cfattach *ca = dev->dv_cfdata->cf_attach;
+		
+			if (ca->ca_activate)
+				/* We will activate network console directly */
+				rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
+//			printf("\n%s: %s %s activated [%d]...\n", 
+//					__func__, dev->dv_xname,
+//					(dev->dv_flags & DVF_ACTIVE)?
+//						"is":"is not", rv);
+			break;
+		}
+	}
+	splx(s);
+	consintr = savintr;
+
 #ifdef GPROF
 	/* Initialize kernel profiling. */
 	kmstartup();

