Add the Inferno license to files we got from Inferno
[akaros.git] / kern / src / net / netlog.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42
43 enum {
44         Nlog = 4 * 1024,
45 };
46
47 /*
48  *  action log
49  */
50 struct Netlog {
51         spinlock_t lock;
52         int opens;
53         char *buf;
54         char *end;
55         char *rptr;
56         int len;
57
58         int logmask;                            /* mask of things to debug */
59         uint8_t iponly[IPaddrlen];      /* ip address to print debugging for */
60         int iponlyset;
61
62         qlock_t qlock;
63         struct rendez r;
64 };
65
66 typedef struct Netlogflag {
67         char *name;
68         int mask;
69 } Netlogflag;
70
71 static Netlogflag flags[] = {
72         {"ppp", Logppp,},
73         {"ip", Logip,},
74         {"fs", Logfs,},
75         {"tcp", Logtcp,},
76         {"il", Logil,},
77         {"icmp", Logicmp,},
78         {"udp", Logudp,},
79         {"compress", Logcompress,},
80         {"ilmsg", Logil | Logilmsg,},
81         {"gre", Loggre,},
82         {"tcpwin", Logtcp | Logtcpwin,},
83         {"tcprxmt", Logtcp | Logtcprxmt,},
84         {"udpmsg", Logudp | Logudpmsg,},
85         {"ipmsg", Logip | Logipmsg,},
86         {"esp", Logesp,},
87         {NULL, 0,},
88 };
89
90 enum {
91         CMset,
92         CMclear,
93         CMonly,
94 };
95
96 static
97 struct cmdtab routecmd[] = {
98         {CMset, "set", 0},
99         {CMclear, "clear", 0},
100         {CMonly, "only", 0},
101 };
102
103 void netloginit(struct Fs *f)
104 {
105         f->alog = kzmalloc(sizeof(struct Netlog), 0);
106         spinlock_init(&f->alog->lock);
107         qlock_init(&f->alog->qlock);
108         rendez_init(&f->alog->r);
109 }
110
111 void netlogopen(struct Fs *f)
112 {
113         ERRSTACK(1);
114         spin_lock(&f->alog->lock);
115         if (waserror()) {
116                 spin_unlock(&f->alog->lock);
117                 nexterror();
118         }
119         if (f->alog->opens == 0) {
120                 if (f->alog->buf == NULL)
121                         f->alog->buf = kzmalloc(Nlog, 0);
122                 f->alog->rptr = f->alog->buf;
123                 f->alog->end = f->alog->buf + Nlog;
124         }
125         f->alog->opens++;
126         spin_unlock(&f->alog->lock);
127         poperror();
128 }
129
130 void netlogclose(struct Fs *f)
131 {
132         ERRSTACK(1);
133         spin_lock(&f->alog->lock);
134         if (waserror()) {
135                 spin_unlock(&f->alog->lock);
136                 nexterror();
137         }
138         f->alog->opens--;
139         if (f->alog->opens == 0) {
140                 kfree(f->alog->buf);
141                 f->alog->buf = NULL;
142         }
143         spin_unlock(&f->alog->lock);
144         poperror();
145 }
146
147 static int netlogready(void *a)
148 {
149         struct Fs *f = a;
150
151         return f->alog->len;
152 }
153
154 long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
155 {
156         ERRSTACK(1);
157         int i, d;
158         char *p, *rptr;
159
160         qlock(&f->alog->qlock);
161         if (waserror()) {
162                 qunlock(&f->alog->qlock);
163                 nexterror();
164         }
165
166         for (;;) {
167                 spin_lock(&f->alog->lock);
168                 if (f->alog->len) {
169                         if (n > f->alog->len)
170                                 n = f->alog->len;
171                         d = 0;
172                         rptr = f->alog->rptr;
173                         f->alog->rptr += n;
174                         if (f->alog->rptr >= f->alog->end) {
175                                 d = f->alog->rptr - f->alog->end;
176                                 f->alog->rptr = f->alog->buf + d;
177                         }
178                         f->alog->len -= n;
179                         spin_unlock(&f->alog->lock);
180
181                         i = n - d;
182                         p = a;
183                         memmove(p, rptr, i);
184                         memmove(p + i, f->alog->buf, d);
185                         break;
186                 } else
187                         spin_unlock(&f->alog->lock);
188
189                 rendez_sleep(&f->alog->r, netlogready, f);
190         }
191
192         qunlock(&f->alog->qlock);
193         poperror();
194
195         return n;
196 }
197
198 void netlogctl(struct Fs *f, char *s, int n)
199 {
200         ERRSTACK(1);
201         int i, set = 0;
202         Netlogflag *fp;
203         struct cmdbuf *cb;
204         struct cmdtab *ct;
205
206         cb = parsecmd(s, n);
207         if (waserror()) {
208                 kfree(cb);
209                 nexterror();
210         }
211
212         if (cb->nf < 2)
213                 error(EINVAL, NULL);
214
215         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
216
217         switch (ct->index) {
218                 case CMset:
219                         set = 1;
220                         break;
221
222                 case CMclear:
223                         set = 0;
224                         break;
225
226                 case CMonly:
227                         parseip(f->alog->iponly, cb->f[1]);
228                         if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
229                                 f->alog->iponlyset = 0;
230                         else
231                                 f->alog->iponlyset = 1;
232                         kfree(cb);
233                         poperror();
234                         return;
235
236                 default:
237                         cmderror(cb, "unknown ip control message");
238         }
239
240         for (i = 1; i < cb->nf; i++) {
241                 for (fp = flags; fp->name; fp++)
242                         if (strcmp(fp->name, cb->f[i]) == 0)
243                                 break;
244                 if (fp->name == NULL)
245                         continue;
246                 if (set)
247                         f->alog->logmask |= fp->mask;
248                 else
249                         f->alog->logmask &= ~fp->mask;
250         }
251
252         kfree(cb);
253         poperror();
254 }
255
256 void netlog(struct Fs *f, int mask, char *fmt, ...)
257 {
258         char buf[128], *t, *fp;
259         int i, n;
260         va_list arg;
261
262         if (!(f->alog->logmask & mask))
263                 return;
264
265         if (f->alog->opens == 0)
266                 return;
267
268         va_start(arg, fmt);
269         n = vsnprintf(buf, sizeof(buf), fmt, arg);
270         va_end(arg);
271
272         spin_lock(&f->alog->lock);
273         i = f->alog->len + n - Nlog;
274         if (i > 0) {
275                 f->alog->len -= i;
276                 f->alog->rptr += i;
277                 if (f->alog->rptr >= f->alog->end)
278                         f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
279         }
280         t = f->alog->rptr + f->alog->len;
281         fp = buf;
282         f->alog->len += n;
283         while (n-- > 0) {
284                 if (t >= f->alog->end)
285                         t = f->alog->buf + (t - f->alog->end);
286                 *t++ = *fp++;
287         }
288         spin_unlock(&f->alog->lock);
289
290         rendez_wakeup(&f->alog->r);
291 }