1 /* tuntest.c -- Tunnel-based testing of the network code.
3 * From: Rick van Rein <rick@openfortress.nl>
16 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #include <sys/select.h>
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>
30 #include <linux/if_tun.h>
31 #include <linux/if_ether.h>
36 #include <0cpm/netfun.h>
37 #include <0cpm/netdb.h>
39 #include <0cpm/timer.h>
47 timing_t timeout = TIMER_NULL;
53 * TEST OUTPUT FUNCTIONS
56 uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
57 printf ("Received: ARP Reply\n");
61 uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
62 printf ("Received: RTP\n");
66 uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
67 printf ("Received: RTCP\n");
71 uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
72 printf ("Received: SIP\n");
76 uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
77 //TODO// printf ("Received: mDNS error response\n");
81 uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
82 //TODO// printf ("Received: mDNS dynamic response\n");
86 uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
87 //TODO// printf ("Received: mDNS standard response\n");
91 uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
92 //TODO// printf ("Received: mDNS error query\n");
96 uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
97 //TODO// printf ("Received: mDNS ok query\n");
103 /* A collection of initialisation steps.
107 for (i=0; i<IP6BINDING_COUNT; i++) {
108 ip6binding [i].flags = I6B_EXPIRED;
114 * Environment simulation functions
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");
123 timing_t bottom_time (void) {
126 if (gettimeofday (&now, NULL) != 0) {
127 fprintf (stderr, "Failed to get clock time: %s\n", strerror (errno));
130 retval = now.tv_sec * 1000 + (now.tv_usec / 1000);
134 timing_t bottom_timer_set (timing_t nextirq) {
135 timing_t retval = timeout;
140 void bottom_critical_region_begin (void) {
141 // No real action, as this is already software
144 void bottom_critical_region_end (void) {
145 // No real action, as this is already software
148 void bottom_sleep_prepare (void) {
152 void bottom_sleep_commit (sleep_depth_t depth) {
158 FD_SET (tunsox, &seln);
159 struct timeval seltimeout;
161 if (timeout != TIMER_NULL) {
162 gettimeofday (&seltimeout, NULL);
163 tm = seltimeout.tv_sec * 1000 + seltimeout.tv_usec / 1000;
165 timeout = TIMER_NULL;
166 top_timer_expiration (tm);
171 seltimeout.tv_sec = tm / 1000 ;
172 seltimeout.tv_usec = (tm % 1000) * 1000;
174 int sel = select (tunsox+1, &seln, NULL, NULL, &seltimeout);
176 top_network_can_recv ();
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);
185 fprintf (stderr, "select() returned an error: %s\n", strerror (errno));
190 bool bottom_network_send (uint8_t *buf, uint16_t buflen) {
191 struct tun_pi *tunpi = (struct tun_pi *) &buf [-sizeof (struct tun_pi)];
193 tunpi->proto = ((struct ethhdr *) buf)->h_proto;
194 size_t wsz = write (tunsox, buf - sizeof (struct tun_pi), buflen + sizeof (struct tun_pi));
196 if (errno == EAGAIN) {
199 fprintf (stderr, "Ignoring error after write to tunnel: %s\n", strerror (errno));
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);
209 if (errno == EAGAIN) {
212 fprintf (stderr, "Ignoring error after read from tunnel: %s\n", strerror (errno));
215 } else if (rsz > sizeof (struct tun_pi)) {
216 *buflen = rsz - sizeof (struct tun_pi);
225 * TEST SETUP FUNCTIONS
228 typedef void *retfn (uint8_t *pout, intptr_t *mem);
230 int process_packets (int secs) {
232 time_t maxtm = secs + time (NULL);
236 FD_SET (tunsox, &seln);
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)) {
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);
248 bzero (mem, sizeof (mem));
249 retfn *rf = (retfn *) netinput (rbuf.data, pktlen, mem);
252 for (i=0; i<28; i++) {
253 printf (" M[%d]=0x%08x%s", i, mem [i],
254 ((i+1)%4 == 0)? "\n": "");
258 uint8_t *start = wbuf.data;
259 uint8_t *stop = (*rf) (start, mem);
261 mem [MEM_ALL_DONE] = (intptr_t) stop;
262 netcore_send_buffer (mem, wbuf.data);
271 int setup_tunnel (void) {
276 tunsox = open ("/dev/net/tun", O_RDWR | O_NONBLOCK);
281 // Set the tunnel name to "test0cpm"
283 bzero (&ifreq, sizeof (ifreq));
284 strncpy (ifreq.ifr_name, "test0cpm", IFNAMSIZ);
285 ifreq.ifr_flags = IFF_TAP;
287 if (ioctl (tunsox, TUNSETIFF, &ifreq) == -1) {
291 // Set to promiscuous mode (meaningless for a tunnel)
294 if (ioctl(tunsox, SIOCGIFFLAGS, &ifreq) == -1) {
297 ifreq.ifr_flags |= IFF_PROMISC | IFF_UP;
299 if (ioctl(tunsox, SIOCSIFFLAGS, &ifreq) == -1) {
304 // Cleanup and report success or failure
317 int main (int argc, char *argv []) {
319 int tunsox = setup_tunnel ();
321 fprintf (stderr, "Failed to setup tunnel\n");
324 system ("/sbin/ifconfig test0cpm up");
325 system ("/sbin/ifconfig test0cpm");
328 fprintf (stderr, "top_main() returned -- which MUST NOT happen!\n");