net: tcp: Handle reseqs of length 0
[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 <net/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         {"tcpreset", Logtcp | Logtcpreset,},
83         {"tcprxmt", Logtcp | Logtcprxmt,},
84         {"tcpall", Logtcp | Logtcpreset | Logtcprxmt | Logtcpverbose,},
85         {"udpmsg", Logudp | Logudpmsg,},
86         {"ipmsg", Logip | Logipmsg,},
87         {"esp", Logesp,},
88         {NULL, 0,},
89 };
90
91 enum {
92         CMset,
93         CMclear,
94         CMonly,
95 };
96
97 static
98 struct cmdtab routecmd[] = {
99         {CMset, "set", 0},
100         {CMclear, "clear", 0},
101         {CMonly, "only", 0},
102 };
103
104 void netloginit(struct Fs *f)
105 {
106         f->alog = kzmalloc(sizeof(struct Netlog), 0);
107         spinlock_init(&f->alog->lock);
108         qlock_init(&f->alog->qlock);
109         rendez_init(&f->alog->r);
110 }
111
112 void netlogopen(struct Fs *f)
113 {
114         ERRSTACK(1);
115         spin_lock(&f->alog->lock);
116         if (waserror()) {
117                 spin_unlock(&f->alog->lock);
118                 nexterror();
119         }
120         if (f->alog->opens == 0) {
121                 if (f->alog->buf == NULL)
122                         f->alog->buf = kzmalloc(Nlog, 0);
123                 f->alog->rptr = f->alog->buf;
124                 f->alog->end = f->alog->buf + Nlog;
125         }
126         f->alog->opens++;
127         spin_unlock(&f->alog->lock);
128         poperror();
129 }
130
131 void netlogclose(struct Fs *f)
132 {
133         ERRSTACK(1);
134         spin_lock(&f->alog->lock);
135         if (waserror()) {
136                 spin_unlock(&f->alog->lock);
137                 nexterror();
138         }
139         f->alog->opens--;
140         if (f->alog->opens == 0) {
141                 kfree(f->alog->buf);
142                 f->alog->buf = NULL;
143         }
144         spin_unlock(&f->alog->lock);
145         poperror();
146 }
147
148 static int netlogready(void *a)
149 {
150         struct Fs *f = a;
151
152         return f->alog->len;
153 }
154
155 long netlogread(struct Fs *f, void *a, uint32_t unused, long n)
156 {
157         ERRSTACK(1);
158         int i, d;
159         char *p, *rptr;
160
161         qlock(&f->alog->qlock);
162         if (waserror()) {
163                 qunlock(&f->alog->qlock);
164                 nexterror();
165         }
166
167         for (;;) {
168                 spin_lock(&f->alog->lock);
169                 if (f->alog->len) {
170                         if (n > f->alog->len)
171                                 n = f->alog->len;
172                         d = 0;
173                         rptr = f->alog->rptr;
174                         f->alog->rptr += n;
175                         if (f->alog->rptr >= f->alog->end) {
176                                 d = f->alog->rptr - f->alog->end;
177                                 f->alog->rptr = f->alog->buf + d;
178                         }
179                         f->alog->len -= n;
180                         spin_unlock(&f->alog->lock);
181
182                         i = n - d;
183                         p = a;
184                         memmove(p, rptr, i);
185                         memmove(p + i, f->alog->buf, d);
186                         break;
187                 } else
188                         spin_unlock(&f->alog->lock);
189
190                 rendez_sleep(&f->alog->r, netlogready, f);
191         }
192
193         qunlock(&f->alog->qlock);
194         poperror();
195
196         return n;
197 }
198
199 void netlogctl(struct Fs *f, char *s, int n)
200 {
201         ERRSTACK(1);
202         int i, set = 0;
203         Netlogflag *fp;
204         struct cmdbuf *cb;
205         struct cmdtab *ct;
206
207         cb = parsecmd(s, n);
208         if (waserror()) {
209                 kfree(cb);
210                 nexterror();
211         }
212
213         if (cb->nf < 2)
214                 error(EINVAL, ERROR_FIXME);
215
216         ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
217
218         switch (ct->index) {
219                 case CMset:
220                         set = 1;
221                         break;
222
223                 case CMclear:
224                         set = 0;
225                         break;
226
227                 case CMonly:
228                         parseip(f->alog->iponly, cb->f[1]);
229                         if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
230                                 f->alog->iponlyset = 0;
231                         else
232                                 f->alog->iponlyset = 1;
233                         kfree(cb);
234                         poperror();
235                         return;
236
237                 default:
238                         cmderror(cb, "unknown ip control message");
239         }
240
241         for (i = 1; i < cb->nf; i++) {
242                 for (fp = flags; fp->name; fp++)
243                         if (strcmp(fp->name, cb->f[i]) == 0)
244                                 break;
245                 if (fp->name == NULL)
246                         continue;
247                 if (set)
248                         f->alog->logmask |= fp->mask;
249                 else
250                         f->alog->logmask &= ~fp->mask;
251         }
252
253         kfree(cb);
254         poperror();
255 }
256
257 void netlog(struct Fs *f, int mask, char *fmt, ...)
258 {
259         char buf[256], *t, *fp;
260         int i, n;
261         va_list arg;
262         struct timespec ts_now;
263
264         if (!(f->alog->logmask & mask))
265                 return;
266
267         if (f->alog->opens == 0)
268                 return;
269
270         /* Same style as trace_printk */
271         if (likely(__proc_global_info.tsc_freq))
272                 ts_now = tsc2timespec(read_tsc());
273         n = snprintf(buf, sizeof(buf), "[%lu.%09lu]: ",
274                      ts_now.tv_sec, ts_now.tv_nsec);
275
276         va_start(arg, fmt);
277         n += vsnprintf(buf + n, sizeof(buf) - n, fmt, arg);
278         va_end(arg);
279
280         spin_lock(&f->alog->lock);
281         i = f->alog->len + n - Nlog;
282         if (i > 0) {
283                 f->alog->len -= i;
284                 f->alog->rptr += i;
285                 if (f->alog->rptr >= f->alog->end)
286                         f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
287         }
288         t = f->alog->rptr + f->alog->len;
289         fp = buf;
290         f->alog->len += n;
291         while (n-- > 0) {
292                 if (t >= f->alog->end)
293                         t = f->alog->buf + (t - f->alog->end);
294                 *t++ = *fp++;
295         }
296         spin_unlock(&f->alog->lock);
297
298         rendez_wakeup(&f->alog->r);
299 }