Added explicit errno reporting from error() API.
[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         {"ppp", Logppp,},
46         {"ip", Logip,},
47         {"fs", Logfs,},
48         {"tcp", Logtcp,},
49         {"il", Logil,},
50         {"icmp", Logicmp,},
51         {"udp", Logudp,},
52         {"compress", Logcompress,},
53         {"ilmsg", Logil | Logilmsg,},
54         {"gre", Loggre,},
55         {"tcpwin", Logtcp | Logtcpwin,},
56         {"tcprxmt", Logtcp | Logtcprxmt,},
57         {"udpmsg", Logudp | Logudpmsg,},
58         {"ipmsg", Logip | Logipmsg,},
59         {"esp", Logesp,},
60         {NULL, 0,},
61 };
62
63 enum {
64         CMset,
65         CMclear,
66         CMonly,
67 };
68
69 static
70 struct cmdtab routecmd[] = {
71         {CMset, "set", 0},
72         {CMclear, "clear", 0},
73         {CMonly, "only", 0},
74 };
75
76 void netloginit(struct Fs *f)
77 {
78         f->alog = kzmalloc(sizeof(struct Netlog), 0);
79         spinlock_init(&f->alog->lock);
80         qlock_init(&f->alog->qlock);
81         rendez_init(&f->alog->r);
82 }
83
84 void netlogopen(struct Fs *f)
85 {
86         ERRSTACK(1);
87         spin_lock(&f->alog->lock);
88         if (waserror()) {
89                 spin_unlock(&f->alog->lock);
90                 nexterror();
91         }
92         if (f->alog->opens == 0) {
93                 if (f->alog->buf == NULL)
94                         f->alog->buf = kzmalloc(Nlog, 0);
95                 f->alog->rptr = f->alog->buf;
96                 f->alog->end = f->alog->buf + Nlog;
97         }
98         f->alog->opens++;
99         spin_unlock(&f->alog->lock);
100         poperror();
101 }
102
103 void netlogclose(struct Fs *f)
104 {
105         ERRSTACK(1);
106         spin_lock(&f->alog->lock);
107         if (waserror()) {
108                 spin_unlock(&f->alog->lock);
109                 nexterror();
110         }
111         f->alog->opens--;
112         if (f->alog->opens == 0) {
113                 kfree(f->alog->buf);
114                 f->alog->buf = NULL;
115         }
116         spin_unlock(&f->alog->lock);
117         poperror();
118 }
119
120 static int netlogready(void *a)
121 {
122         struct Fs *f = a;
123
124         return f->alog->len;
125 }
126
127 long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
128 {
129         ERRSTACK(1);
130         int i, d;
131         char *p, *rptr;
132
133         qlock(&f->alog->qlock);
134         if (waserror()) {
135                 qunlock(&f->alog->qlock);
136                 nexterror();
137         }
138
139         for (;;) {
140                 spin_lock(&f->alog->lock);
141                 if (f->alog->len) {
142                         if (n > f->alog->len)
143                                 n = f->alog->len;
144                         d = 0;
145                         rptr = f->alog->rptr;
146                         f->alog->rptr += n;
147                         if (f->alog->rptr >= f->alog->end) {
148                                 d = f->alog->rptr - f->alog->end;
149                                 f->alog->rptr = f->alog->buf + d;
150                         }
151                         f->alog->len -= n;
152                         spin_unlock(&f->alog->lock);
153
154                         i = n - d;
155                         p = a;
156                         memmove(p, rptr, i);
157                         memmove(p + i, f->alog->buf, d);
158                         break;
159                 } else
160                         spin_unlock(&f->alog->lock);
161
162                 rendez_sleep(&f->alog->r, netlogready, f);
163         }
164
165         qunlock(&f->alog->qlock);
166         poperror();
167
168         return n;
169 }
170
171 void netlogctl(struct Fs *f, char *s, int n)
172 {
173         ERRSTACK(1);
174         int i, set = 0;
175         Netlogflag *fp;
176         struct cmdbuf *cb;
177         struct cmdtab *ct;
178
179         cb = parsecmd(s, n);
180         if (waserror()) {
181                 kfree(cb);
182                 nexterror();
183         }
184
185         if (cb->nf < 2)
186                 error(EINVAL, NULL);
187
188         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
189
190         switch (ct->index) {
191                 case CMset:
192                         set = 1;
193                         break;
194
195                 case CMclear:
196                         set = 0;
197                         break;
198
199                 case CMonly:
200                         parseip(f->alog->iponly, cb->f[1]);
201                         if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
202                                 f->alog->iponlyset = 0;
203                         else
204                                 f->alog->iponlyset = 1;
205                         kfree(cb);
206                         poperror();
207                         return;
208
209                 default:
210                         cmderror(cb, "unknown ip control message");
211         }
212
213         for (i = 1; i < cb->nf; i++) {
214                 for (fp = flags; fp->name; fp++)
215                         if (strcmp(fp->name, cb->f[i]) == 0)
216                                 break;
217                 if (fp->name == NULL)
218                         continue;
219                 if (set)
220                         f->alog->logmask |= fp->mask;
221                 else
222                         f->alog->logmask &= ~fp->mask;
223         }
224
225         kfree(cb);
226         poperror();
227 }
228
229 void netlog(struct Fs *f, int mask, char *fmt, ...)
230 {
231         char buf[128], *t, *fp;
232         int i, n;
233         va_list arg;
234
235         if (!(f->alog->logmask & mask))
236                 return;
237
238         if (f->alog->opens == 0)
239                 return;
240
241         va_start(arg, fmt);
242         n = vsnprintf(buf, sizeof(buf), fmt, arg);
243         va_end(arg);
244
245         spin_lock(&f->alog->lock);
246         i = f->alog->len + n - Nlog;
247         if (i > 0) {
248                 f->alog->len -= i;
249                 f->alog->rptr += i;
250                 if (f->alog->rptr >= f->alog->end)
251                         f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
252         }
253         t = f->alog->rptr + f->alog->len;
254         fp = buf;
255         f->alog->len += n;
256         while (n-- > 0) {
257                 if (t >= f->alog->end)
258                         t = f->alog->buf + (t - f->alog->end);
259                 *t++ = *fp++;
260         }
261         spin_unlock(&f->alog->lock);
262
263         rendez_wakeup(&f->alog->r);
264 }