Inserted tickless RTOS code. Network input code dysfunctional, and bound to be replaced.
[firmerware] / src / driver / util / linuxtuntest.c
1 /* tuntest.c -- Tunnel-based testing of the network code.
2  *
3  * From: Rick van Rein <rick@openfortress.nl>
4  */
5
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdarg.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <fcntl.h>
14 #include <errno.h>
15
16 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #include <sys/select.h>
20 #include <sys/time.h>
21 #include <sys/uio.h>
22
23 #include <netinet/ip.h>
24 #include <netinet/ip6.h>
25 #include <netinet/udp.h>
26 #include <netinet/ip_icmp.h>
27 #include <netinet/icmp6.h>
28
29 #include <linux/if.h>
30 #include <linux/if_tun.h>
31 #include <linux/if_ether.h>
32
33 #include <config.h>
34
35 #include <0cpm/cpu.h>
36 #include <0cpm/netfun.h>
37 #include <0cpm/netdb.h>
38
39 #include <0cpm/timer.h>
40 #include <0cpm/led.h>
41
42
43 int tunsox = -1;
44
45 packet_t rbuf, wbuf;
46
47 timing_t timeout = TIMER_NULL;
48
49 bool sleepy = false;
50
51
52 /*
53  * TEST OUTPUT FUNCTIONS
54  */
55
56 uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
57         printf ("Received: ARP Reply\n");
58         return NULL;
59 }
60
61 uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
62         printf ("Received: RTP\n");
63         return NULL;
64 }
65
66 uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
67         printf ("Received: RTCP\n");
68         return NULL;
69 }
70
71 uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
72         printf ("Received: SIP\n");
73         return NULL;
74 }
75
76 uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
77         //TODO// printf ("Received: mDNS error response\n");
78         return NULL;
79 }
80
81 uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
82         //TODO// printf ("Received: mDNS dynamic response\n");
83         return NULL;
84 }
85
86 uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
87         //TODO// printf ("Received: mDNS standard response\n");
88         return NULL;
89 }
90
91 uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
92         //TODO// printf ("Received: mDNS error query\n");
93         return NULL;
94 }
95
96 uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
97         //TODO// printf ("Received: mDNS ok query\n");
98         return NULL;
99 }
100
101
102
103 /* A collection of initialisation steps.
104  */
105 void init (void) {
106         int i;
107         for (i=0; i<IP6BINDING_COUNT; i++) {
108                 ip6binding [i].flags = I6B_EXPIRED;
109         }
110 }
111
112
113 /*
114  * Environment simulation functions
115  */
116
117 void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
118         char *colmap [] = { "off", "green", "red" };
119         printf ("LED #%d switches to colour #%d (%s)\n",
120                         ledidx, col, (col < 3)? colmap [col]: "out-of-range");
121 }
122
123 timing_t bottom_time (void) {
124         struct timeval now;
125         timing_t retval;
126         if (gettimeofday (&now, NULL) != 0) {
127                 fprintf (stderr, "Failed to get clock time: %s\n", strerror (errno));
128                 return 0;
129         }
130         retval = now.tv_sec * 1000 + (now.tv_usec / 1000);
131         return retval;
132 }
133
134 timing_t bottom_timer_set (timing_t nextirq) {
135         timing_t retval = timeout;
136         timeout = nextirq;
137         return timeout;
138 }
139
140 void bottom_critical_region_begin (void) {
141         // No real action, as this is already software
142 }
143
144 void bottom_critical_region_end (void) {
145         // No real action, as this is already software
146 }
147
148 void bottom_sleep_prepare (void) {
149         sleepy = true;
150 }
151
152 void bottom_sleep_commit (sleep_depth_t depth) {
153         if (!sleepy) {
154                 return;
155         }
156         fd_set seln;
157         FD_ZERO (&seln);
158         FD_SET (tunsox, &seln);
159         struct timeval seltimeout;
160         timing_t tm = 0;
161         if (timeout != TIMER_NULL) {
162                 gettimeofday (&seltimeout, NULL);
163                 tm = seltimeout.tv_sec * 1000 + seltimeout.tv_usec / 1000;
164                 if (timeout < tm) {
165                         timeout = TIMER_NULL;
166                         top_timer_expiration (tm);
167                         sleepy = false;
168                         return;
169                 }
170                 tm = timeout - tm;
171                 seltimeout.tv_sec  =  tm / 1000        ;
172                 seltimeout.tv_usec = (tm % 1000) * 1000;
173         }
174         int sel = select (tunsox+1, &seln, NULL, NULL, &seltimeout);
175         if (sel >= 1) {
176                 top_network_can_recv ();
177                 sleepy = false;
178         } else if (sel == 0) {
179                 gettimeofday (&seltimeout, NULL);
180                 timing_t exptm = (seltimeout.tv_sec * 1000) * (seltimeout.tv_usec / 1000);
181                 timeout = TIMER_NULL;
182                 top_timer_expiration (exptm);
183                 sleepy = false;
184         } else {
185                 fprintf (stderr, "select() returned an error: %s\n", strerror (errno));
186                 sleep (1);
187         }
188 }
189
190 bool bottom_network_send (uint8_t *buf, uint16_t buflen) {
191         struct tun_pi *tunpi = (struct tun_pi *) &buf [-sizeof (struct tun_pi)];
192         tunpi->flags = 0;
193         tunpi->proto = ((struct ethhdr *) buf)->h_proto;
194         size_t wsz = write (tunsox, buf - sizeof (struct tun_pi), buflen + sizeof (struct tun_pi));
195         if (wsz == -1) {
196                 if (errno == EAGAIN) {
197                         return false;
198                 } else {
199                         fprintf (stderr, "Ignoring error after write to tunnel: %s\n", strerror (errno));
200                 }
201         }
202         return true;
203 }
204
205 bool bottom_network_recv (uint8_t *buf, uint16_t *buflen) {
206         uint16_t bl = (*buflen) + sizeof (struct tun_pi);
207         size_t rsz = read (tunsox, buf - sizeof (struct tun_pi), bl);
208         if (rsz == -1) {
209                 if (errno == EAGAIN) {
210                         return false;
211                 } else {
212                         fprintf (stderr, "Ignoring error after read from tunnel: %s\n", strerror (errno));
213                 }
214                 *buflen = 0;
215         } else if (rsz > sizeof (struct tun_pi)) {
216                 *buflen = rsz - sizeof (struct tun_pi);
217         } else {
218                 *buflen = 0;
219         }
220         return true;
221 }
222
223
224 /*
225  * TEST SETUP FUNCTIONS
226  */
227
228 typedef void *retfn (uint8_t *pout, intptr_t *mem);
229
230 int process_packets (int secs) {
231         int ok = 1;
232         time_t maxtm = secs + time (NULL);
233         while (ok) {
234                 fd_set seln;
235                 FD_ZERO (&seln);
236                 FD_SET (tunsox, &seln);
237                 struct timeval tout;
238                 tout.tv_sec = maxtm - time (NULL);
239                 tout.tv_usec = 500000;
240                 if ((tout.tv_sec < 0) || (select (tunsox+1, &seln, NULL, NULL, &tout) <= 0)) {
241                         return 1;
242                 }
243                 size_t len = read (tunsox, &rbuf.data [-sizeof (struct tun_pi)], sizeof (struct tun_pi) + sizeof (rbuf.data));
244                 uint8_t *pkt = rbuf.data;
245                 uint32_t pktlen = len - sizeof (struct tun_pi);
246                 if (pktlen > 18) {
247                         intptr_t mem [28];
248                         bzero (mem, sizeof (mem));
249                         retfn *rf = (retfn *) netinput (rbuf.data, pktlen, mem);
250 #if 0
251                         int i;
252                         for (i=0; i<28; i++) {
253                                 printf ("  M[%d]=0x%08x%s", i, mem [i],
254                                                 ((i+1)%4 == 0)? "\n": "");
255                         }
256 #endif
257                         if (rf != NULL) {
258                                 uint8_t *start = wbuf.data;
259                                 uint8_t *stop = (*rf) (start, mem);
260                                 if (stop) {
261                                         mem [MEM_ALL_DONE] = (intptr_t) stop;
262                                         netcore_send_buffer (mem, wbuf.data);
263                                 }
264                         }
265                 }
266         }
267         return 0;
268 }
269
270
271 int setup_tunnel (void) {
272         tunsox = -1;
273         int ok = 1;
274         //
275         // Open the tunnel
276         tunsox = open ("/dev/net/tun", O_RDWR | O_NONBLOCK);
277         if (tunsox < 0) {
278                 ok = 0;
279         }
280         //
281         // Set the tunnel name to "test0cpm"
282         struct ifreq ifreq;
283         bzero (&ifreq, sizeof (ifreq));
284         strncpy (ifreq.ifr_name, "test0cpm", IFNAMSIZ);
285         ifreq.ifr_flags = IFF_TAP;
286         if (ok)
287         if (ioctl (tunsox, TUNSETIFF, &ifreq) == -1) {
288                 ok = 0;
289         }
290         //
291         // Set to promiscuous mode (meaningless for a tunnel)
292 #if 0
293         if (ok)
294         if (ioctl(tunsox, SIOCGIFFLAGS, &ifreq) == -1) {
295                 ok = 0;
296         }
297         ifreq.ifr_flags |= IFF_PROMISC | IFF_UP;
298         if (ok)
299         if (ioctl(tunsox, SIOCSIFFLAGS, &ifreq) == -1) {
300                 ok = 0;
301         }
302 #endif
303         //
304         // Cleanup and report success or failure
305         if (!ok) {
306                 if (tunsox >= 0) {
307                         close (tunsox);
308                         tunsox = -1;
309                 }
310                 return -1;
311         }
312         return tunsox;
313 }
314
315
316
317 int main (int argc, char *argv []) {
318         init ();
319         int tunsox = setup_tunnel ();
320         if (tunsox == -1) {
321                 fprintf (stderr, "Failed to setup tunnel\n");
322                 exit (1);
323         }
324         system ("/sbin/ifconfig test0cpm up");
325         system ("/sbin/ifconfig test0cpm");
326         sleep (10);
327         top_main ();
328         fprintf (stderr, "top_main() returned -- which MUST NOT happen!\n");
329         close (tunsox);
330         exit (1);
331 }
332