Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "../port/error.h"
7
 
8
#include "ip.h"
9
 
10
static void	netdevbind(Ipifc *ifc, int argc, char **argv);
11
static void	netdevunbind(Ipifc *ifc);
12
static void	netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
13
static void	netdevread(void *a);
14
 
15
typedef struct	Netdevrock Netdevrock;
16
struct Netdevrock
17
{
18
	Fs	*f;		/* file system we belong to */
19
	Proc	*readp;		/* reading process */
20
	Chan	*mchan;		/* Data channel */
21
};
22
 
23
Medium netdevmedium =
24
{
25
.name=		"netdev",
26
.hsize=		0,
27
.mintu=	0,
28
.maxtu=	64000,
29
.maclen=	0,
30
.bind=		netdevbind,
31
.unbind=	netdevunbind,
32
.bwrite=	netdevbwrite,
33
.unbindonclose=	0,
34
};
35
 
36
/*
37
 *  called to bind an IP ifc to a generic network device
38
 *  called with ifc qlock'd
39
 */
40
static void
41
netdevbind(Ipifc *ifc, int argc, char **argv)
42
{
43
	Chan *mchan;
44
	Netdevrock *er;
45
 
46
	if(argc < 2)
47
		error(Ebadarg);
48
 
49
	mchan = namec(argv[2], Aopen, ORDWR, 0);
50
 
51
	er = smalloc(sizeof(*er));
52
	er->mchan = mchan;
53
	er->f = ifc->conv->p->f;
54
 
55
	ifc->arg = er;
56
 
57
	kproc("netdevread", netdevread, ifc);
58
}
59
 
60
/*
61
 *  called with ifc wlock'd
62
 */
63
static void
64
netdevunbind(Ipifc *ifc)
65
{
66
	Netdevrock *er = ifc->arg;
67
 
68
	if(er->readp != nil)
69
		postnote(er->readp, 1, "unbind", 0);
70
 
71
	/* wait for readers to die */
72
	while(er->readp != nil)
73
		tsleep(&up->sleep, return0, 0, 300);
74
 
75
	if(er->mchan != nil)
76
		cclose(er->mchan);
77
 
78
	free(er);
79
}
80
 
81
/*
82
 *  called by ipoput with a single block to write
83
 */
84
static void
85
netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*)
86
{
87
	Netdevrock *er = ifc->arg;
88
 
89
	if(bp->next)
90
		bp = concatblock(bp);
91
	if(BLEN(bp) < ifc->mintu)
92
		bp = adjustblock(bp, ifc->mintu);
93
 
94
	devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
95
	ifc->out++;
96
}
97
 
98
/*
99
 *  process to read from the device
100
 */
101
static void
102
netdevread(void *a)
103
{
104
	Ipifc *ifc;
105
	Block *bp;
106
	Netdevrock *er;
107
	char *argv[1];
108
 
109
	ifc = a;
110
	er = ifc->arg;
111
	er->readp = up;	/* hide identity under a rock for unbind */
112
	if(waserror()){
113
		er->readp = nil;
114
		pexit("hangup", 1);
115
	}
116
	for(;;){
117
		bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
118
		if(bp == nil){
119
			/*
120
			 * get here if mchan is a pipe and other side hangs up
121
			 * clean up this interface & get out
122
ZZZ is this a good idea?
123
			 */
124
			poperror();
125
			er->readp = nil;
126
			argv[0] = "unbind";
127
			if(!waserror())
128
				ifc->conv->p->ctl(ifc->conv, argv, 1);
129
			pexit("hangup", 1);
130
		}
131
		if(!canrlock(ifc)){
132
			freeb(bp);
133
			continue;
134
		}
135
		if(waserror()){
136
			runlock(ifc);
137
			nexterror();
138
		}
139
		ifc->in++;
140
		if(ifc->lifc == nil)
141
			freeb(bp);
142
		else
143
			ipiput4(er->f, ifc, bp);
144
		runlock(ifc);
145
		poperror();
146
	}
147
}
148
 
149
void
150
netdevmediumlink(void)
151
{
152
	addipmedium(&netdevmedium);
153
}