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