All qlocks are initialized
[akaros.git] / kern / src / net / netlog.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 enum {
17         Nlog            = 4*1024,
18 };
19
20 /*
21  *  action log
22  */
23 struct Netlog {
24         spinlock_t lock;
25         int     opens;
26         char*   buf;
27         char    *end;
28         char    *rptr;
29         int     len;
30
31         int     logmask;                        /* mask of things to debug */
32         uint8_t iponly[IPaddrlen];              /* ip address to print debugging for */
33         int     iponlyset;
34
35         qlock_t qlock;
36         struct rendez r;
37 };
38
39 typedef struct Netlogflag {
40         char*   name;
41         int     mask;
42 } Netlogflag;
43
44 static Netlogflag flags[] =
45 {
46         { "ppp",        Logppp, },
47         { "ip",         Logip, },
48         { "fs",         Logfs, },
49         { "tcp",        Logtcp, },
50         { "il",         Logil, },
51         { "icmp",       Logicmp, },
52         { "udp",        Logudp, },
53         { "compress",   Logcompress, },
54         { "ilmsg",      Logil|Logilmsg, },
55         { "gre",        Loggre, },
56         { "tcpwin",     Logtcp|Logtcpwin, },
57         { "tcprxmt",    Logtcp|Logtcprxmt, },
58         { "udpmsg",     Logudp|Logudpmsg, },
59         { "ipmsg",      Logip|Logipmsg, },
60         { "esp",        Logesp, },
61         { NULL,         0, },
62 };
63
64 char Ebadnetctl[] = "too few arguments for netlog control message";
65
66 enum
67 {
68         CMset,
69         CMclear,
70         CMonly,
71 };
72
73 static
74 struct cmdtab routecmd[] = {
75         {CMset,         "set",          0},
76         {CMclear,       "clear",        0},
77         {CMonly,                "only",         0},
78 };
79
80 void
81 netloginit(struct Fs *f)
82 {
83         f->alog = kzmalloc(sizeof(struct Netlog), 0);
84         spinlock_init(&f->alog->lock);
85         qlock_init(&f->alog->qlock);
86         rendez_init(&f->alog->r);
87 }
88
89 void
90 netlogopen(struct Fs *f)
91 {
92         ERRSTACK(1);
93         spin_lock(&f->alog->lock);
94         if(waserror()){
95                 spin_unlock(&f->alog->lock);
96                 nexterror();
97         }
98         if(f->alog->opens == 0){
99                 if(f->alog->buf == NULL)
100                         f->alog->buf = kzmalloc(Nlog, 0);
101                 f->alog->rptr = f->alog->buf;
102                 f->alog->end = f->alog->buf + Nlog;
103         }
104         f->alog->opens++;
105         spin_unlock(&f->alog->lock);
106         poperror();
107 }
108
109 void
110 netlogclose(struct Fs *f)
111 {
112         ERRSTACK(1);
113         spin_lock(&f->alog->lock);
114         if(waserror()){
115                 spin_unlock(&f->alog->lock);
116                 nexterror();
117         }
118         f->alog->opens--;
119         if(f->alog->opens == 0){
120                 kfree(f->alog->buf);
121                 f->alog->buf = NULL;
122         }
123         spin_unlock(&f->alog->lock);
124         poperror();
125 }
126
127 static int
128 netlogready(void *a)
129 {
130         struct Fs *f = a;
131
132         return f->alog->len;
133 }
134
135 long
136 netlogread(struct Fs *f, void *a, uint32_t unused, long n)
137 {
138         ERRSTACK(1);
139         int i, d;
140         char *p, *rptr;
141
142         qlock(&f->alog->qlock);
143         if(waserror()){
144                 qunlock(&f->alog->qlock);
145                 nexterror();
146         }
147
148         for(;;){
149                 spin_lock(&f->alog->lock);
150                 if(f->alog->len){
151                         if(n > f->alog->len)
152                                 n = f->alog->len;
153                         d = 0;
154                         rptr = f->alog->rptr;
155                         f->alog->rptr += n;
156                         if(f->alog->rptr >= f->alog->end){
157                                 d = f->alog->rptr - f->alog->end;
158                                 f->alog->rptr = f->alog->buf + d;
159                         }
160                         f->alog->len -= n;
161                         spin_unlock(&f->alog->lock);
162
163                         i = n-d;
164                         p = a;
165                         memmove(p, rptr, i);
166                         memmove(p+i, f->alog->buf, d);
167                         break;
168                 }
169                 else
170                         spin_unlock(&f->alog->lock);
171
172                 rendez_sleep(&f->alog->r, netlogready, f);
173         }
174
175         qunlock(&f->alog->qlock);
176         poperror();
177
178         return n;
179 }
180
181 void
182 netlogctl(struct Fs *f, char* s, int n)
183 {
184         ERRSTACK(1);
185         int i, set = 0;
186         Netlogflag *fp;
187         struct cmdbuf *cb;
188         struct cmdtab *ct;
189
190         cb = parsecmd(s, n);
191         if(waserror()){
192                 kfree(cb);
193                 nexterror();
194         }
195
196         if(cb->nf < 2)
197                 error(Ebadnetctl);
198
199         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
200
201         switch(ct->index){
202         case CMset:
203                 set = 1;
204                 break;
205
206         case CMclear:
207                 set = 0;
208                 break;
209
210         case CMonly:
211                 parseip(f->alog->iponly, cb->f[1]);
212                 if(ipcmp(f->alog->iponly, IPnoaddr) == 0)
213                         f->alog->iponlyset = 0;
214                 else
215                         f->alog->iponlyset = 1;
216                 kfree(cb);
217                 poperror();
218                 return;
219
220         default:
221                 cmderror(cb, "unknown ip control message");
222         }
223
224         for(i = 1; i < cb->nf; i++){
225                 for(fp = flags; fp->name; fp++)
226                         if(strcmp(fp->name, cb->f[i]) == 0)
227                                 break;
228                 if(fp->name == NULL)
229                         continue;
230                 if(set)
231                         f->alog->logmask |= fp->mask;
232                 else
233                         f->alog->logmask &= ~fp->mask;
234         }
235
236         kfree(cb);
237         poperror();
238 }
239
240 void
241 netlog(struct Fs *f, int mask, char *fmt, ...)
242 {
243         char buf[128], *t, *fp;
244         int i, n;
245         va_list arg;
246
247         if(!(f->alog->logmask & mask))
248                 return;
249
250         if(f->alog->opens == 0)
251                 return;
252
253         va_start(arg, fmt);
254         n = snprintf(buf, sizeof(buf), fmt, arg);
255         va_end(arg);
256
257         spin_lock(&f->alog->lock);
258         i = f->alog->len + n - Nlog;
259         if(i > 0){
260                 f->alog->len -= i;
261                 f->alog->rptr += i;
262                 if(f->alog->rptr >= f->alog->end)
263                         f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
264         }
265         t = f->alog->rptr + f->alog->len;
266         fp = buf;
267         f->alog->len += n;
268         while(n-- > 0){
269                 if(t >= f->alog->end)
270                         t = f->alog->buf + (t - f->alog->end);
271                 *t++ = *fp++;
272         }
273         spin_unlock(&f->alog->lock);
274
275         rendez_wakeup(&f->alog->r);
276 }