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                 uint32_t ipaddr = minip_get_ipaddr();
80 
81                 printf("hostname: %s\n", minip_get_hostname());
82                 printf("ip: %u.%u.%u.%u\n", IPV4_SPLIT(ipaddr));
83             }
84             break;
85             case 't': {
86                 uint32_t count = 1;
87                 uint32_t host = 0x0100000A; // 10.0.0.1
88                 uint32_t port = 1025;
89                 udp_socket_t *handle;
90 
91                 switch (argc) {
92                     case 5:
93                         count = argv[4].u;
94                     /* fallthrough */
95                     case 4:
96                         port = argv[3].u;
97                     /* fallthrough */
98                     case 3:
99                         host = str_ip_to_int(argv[2].str, strlen(argv[2].str));
100                         break;
101                 }
102 
103                 if (udp_open(host, port, port, &handle) != NO_ERROR) {
104                     printf("udp_open to %u.%u.%u.%u:%u failed\n", IPV4_SPLIT(host), port);
105                     return -1;
106                 }
107 
108 #define BUFSIZE 1470
109                 uint8_t *buf;
110 
111                 buf = malloc(BUFSIZE);
112                 if (!buf) {
113                     udp_close(handle);
114                     return -1;
115                 }
116 
117                 memset(buf, 0x00, BUFSIZE);
118                 printf("sending %u packet(s) to %u.%u.%u.%u:%u\n", count, IPV4_SPLIT(host), port);
119 
120                 lk_time_t t = current_time();
121                 uint32_t failures = 0;
122                 for (uint32_t i = 0; i < count; i++) {
123                     if (udp_send(buf, BUFSIZE, handle) != 0) {
124                         failures++;
125                     }
126                     buf[128]++;
127                 }
128                 t = current_time() - t;
129                 printf("%d pkts failed\n", failures);
130                 uint64_t total_count = (uint64_t)count * BUFSIZE;
131                 printf("wrote %llu bytes in %u msecs (%llu bytes/sec)\n",
132                        total_count, (uint32_t)t, total_count * 1000 / t);
133 
134                 free(buf);
135                 udp_close(handle);
136 #undef BUFSIZE
137             }
138             break;
139             default:
140                 goto minip_usage;
141         }
142     }
143 
144     return 0;
145 }
146 
147 STATIC_COMMAND_START
148 STATIC_COMMAND("arp", "arp commands", &cmd_arp)
149 STATIC_COMMAND("mi", "minip commands", &cmd_minip)
150 STATIC_COMMAND_END(minip);
151