1 /*
2  * Copyright (c) 2014 Chris Anderson
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include "minip-internal.h"
10 
11 #include <lk/console_cmd.h>
12 #include <kernel/thread.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <platform.h>
17 #include <kernel/timer.h>
18 #include <lk/err.h>
19 
str_ip_to_int(const char * s,size_t len)20 static uint32_t str_ip_to_int(const char *s, size_t len) {
21     uint8_t ip[4] = { 0, 0, 0, 0 };
22     uint8_t pos = 0, i = 0;
23 
24     while (pos < len) {
25         char c = s[pos];
26         if (c == '.') {
27             i++;
28         } else {
29             ip[i] *= 10;
30             ip[i] += c - '0';
31         }
32         pos++;
33     }
34 
35     return IPV4_PACK(ip);
36 }
37 
arp_usage(void)38 static void arp_usage(void) {
39     printf("arp list                        print arp table\n");
40     printf("arp query <ipv4 address>        query arp address\n");
41 }
42 
cmd_arp(int argc,const console_cmd_args * argv)43 static int cmd_arp(int argc, const console_cmd_args *argv) {
44     if (argc == 1) {
45         arp_usage();
46         return -1;
47     }
48 
49     const char *cmd = argv[1].str;
50     if (argc == 2 && strncmp(cmd, "list", sizeof("list")) == 0) {
51         arp_cache_dump();
52     } else if (argc == 3 && strncmp(cmd, "query", sizeof("query")) == 0) {
53         const char *addr_s = argv[2].str;
54         uint32_t addr = str_ip_to_int(addr_s, strlen(addr_s));
55 
56         arp_send_request(addr);
57     } else {
58         arp_usage();
59     }
60 
61     return 0;
62 }
63 
cmd_minip(int argc,const console_cmd_args * argv)64 static int cmd_minip(int argc, const console_cmd_args *argv) {
65     if (argc == 1) {
66 minip_usage:
67         printf("minip commands\n");
68         printf("mi [a]rp                        dump arp table\n");
69         printf("mi [s]tatus                     print ip status\n");
70         printf("mi [t]est [dest] [port] [cnt]   send <cnt> test packets to the dest:port\n");
71     } else {
72         switch (argv[1].str[0]) {
73 
74             case 'a':
75                 arp_cache_dump();
76                 break;
77 
78             case 's': {
79                 printf("hostname: %s\n", minip_get_hostname());
80                 printf("ip: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_ipaddr()));
81                 printf("netmask: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_netmask()));
82                 printf("broadcast: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_broadcast()));
83                 printf("gateway: %u.%u.%u.%u\n", IPV4_SPLIT(minip_get_gateway()));
84             }
85             break;
86             case 't': {
87                 uint32_t count = 1;
88                 uint32_t host = 0x0100000A; // 10.0.0.1
89                 uint32_t port = 1025;
90                 udp_socket_t *handle;
91 
92                 switch (argc) {
93                     case 5:
94                         count = argv[4].u;
95                     /* fallthrough */
96                     case 4:
97                         port = argv[3].u;
98                     /* fallthrough */
99                     case 3:
100                         host = str_ip_to_int(argv[2].str, strlen(argv[2].str));
101                         break;
102                 }
103 
104                 if (udp_open(host, port, port, &handle) != NO_ERROR) {
105                     printf("udp_open to %u.%u.%u.%u:%u failed\n", IPV4_SPLIT(host), port);
106                     return -1;
107                 }
108 
109 #define BUFSIZE 1470
110                 uint8_t *buf;
111 
112                 buf = malloc(BUFSIZE);
113                 if (!buf) {
114                     udp_close(handle);
115                     return -1;
116                 }
117 
118                 memset(buf, 0x00, BUFSIZE);
119                 printf("sending %u packet(s) to %u.%u.%u.%u:%u\n", count, IPV4_SPLIT(host), port);
120 
121                 lk_bigtime_t t = current_time_hires();
122                 uint32_t failures = 0;
123                 for (uint32_t i = 0; i < count; i++) {
124                     if (udp_send(buf, BUFSIZE, handle) != 0) {
125                         failures++;
126                     }
127                     buf[128]++;
128                 }
129                 t = current_time_hires() - t;
130                 if (t == 0)
131                     t++;
132                 printf("%d pkts failed\n", failures);
133                 uint64_t total_count = (uint64_t)count * BUFSIZE;
134                 printf("wrote %llu bytes in %u msecs (%llu bytes/sec)\n",
135                        total_count, (uint32_t)t, total_count * 1000000 / t);
136 
137                 free(buf);
138                 udp_close(handle);
139 #undef BUFSIZE
140             }
141             break;
142             default:
143                 goto minip_usage;
144         }
145     }
146 
147     return 0;
148 }
149 
150 STATIC_COMMAND_START
151 STATIC_COMMAND("arp", "arp commands", &cmd_arp)
152 STATIC_COMMAND("mi", "minip commands", &cmd_minip)
153 STATIC_COMMAND_END(minip);
154