tcpdump.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-07-13 never the first version
  9. */
  10. #include <rtthread.h>
  11. #ifdef PKG_NETUTILS_TCPDUMP
  12. #if RT_VER_NUM >= 0x40100
  13. #include <unistd.h>
  14. #include <fcntl.h>
  15. #else
  16. #include <dfs_posix.h>
  17. #endif /* RT_VER_NUM >= 0x40100 */
  18. #include "netif/ethernetif.h"
  19. #include "optparse.h"
  20. #ifdef PKG_NETUTILS_TCPDUMP_DBG
  21. #define DBG_ENABLE
  22. #define DBG_SECTION_NAME "TCPDUMP"
  23. #define DBG_LEVEL DBG_INFO
  24. #define DBG_COLOR
  25. #else
  26. #undef DBG_ENABLE
  27. #endif
  28. #include <rtdbg.h>
  29. #define TCPDUMP_PIPE_DEVICE ("urdbd") /* rdb pipe */
  30. #define TCPDUMP_DEFAULT_NANE ("sample.pcap")
  31. #define TCPDUMP_MAX_MSG (10)
  32. #define PCAP_FILE_HEADER_SIZE (24)
  33. #define PCAP_PKTHDR_SIZE (16)
  34. #define PCAP_FILE_ID (0xA1B2C3D4)
  35. #define PCAP_VERSION_MAJOR (0x200)
  36. #define PCAP_VERSION_MINOR (0x400)
  37. #define GREENWICH_MEAN_TIME (0)
  38. #define PRECISION_OF_TIME_STAMP (0)
  39. #define MAX_LENTH_OF_CAPTURE_PKG (0xFFFF)
  40. #define LINKTYPE_NULL (0)
  41. #define LINKTYPE_ETHERNET (1) /* also for 100Mb and up */
  42. #define LINKTYPE_EXP_ETHERNET (2) /* 3Mb experimental Ethernet */
  43. #define LINKTYPE_AX25 (3)
  44. #define LINKTYPE_PRONET (4)
  45. #define LINKTYPE_CHAOS (5)
  46. #define LINKTYPE_TOKEN_RING (6) /* DLT_IEEE802 is used for Token Ring */
  47. #define LINKTYPE_ARCNET (7)
  48. #define LINKTYPE_SLIP (8)
  49. #define LINKTYPE_PPP (9)
  50. #define LINKTYPE_FDDI (10)
  51. #define LINKTYPE_PPP_HDLC (50) /* PPP in HDLC-like framing */
  52. #define LINKTYPE_PPP_ETHER (51) /* NetBSD PPP-over-Ethernet */
  53. #define LINKTYPE_ATM_RFC1483 (100) /* LLC/SNAP-encapsulated ATM */
  54. #define LINKTYPE_RAW (101) /* raw IP */
  55. #define LINKTYPE_SLIP_BSDOS (102) /* BSD/OS SLIP BPF header */
  56. #define LINKTYPE_PPP_BSDOS (103) /* BSD/OS PPP BPF header */
  57. #define LINKTYPE_C_HDLC (104) /* Cisco HDLC */
  58. #define LINKTYPE_IEEE802_11 (105) /* IEEE 802.11 (wireless) */
  59. #define LINKTYPE_ATM_CLIP (106) /* Linux Classical IP over ATM */
  60. #define LINKTYPE_LOOP (108) /* OpenBSD loopback */
  61. #define LINKTYPE_LINUX_SLL (113) /* Linux cooked socket capture */
  62. #define LINKTYPE_LTALK (114) /* Apple LocalTalk hardware */
  63. #define LINKTYPE_ECONET (115) /* Acorn Econet */
  64. #define LINKTYPE_CISCO_IOS (118) /* For Cisco-internal use */
  65. #define LINKTYPE_PRISM_HEADER (119) /* 802.11+Prism II monitor mode */
  66. #define LINKTYPE_AIRONET_HEADER (120) /* FreeBSD Aironet driver stuff */
  67. #define MSH_CMD ("phi::m::w::") /* [-p] [-h] [-i] [-m] [-w] */
  68. #define STRCMP(a, R, b) (rt_strcmp((a), (b)) R 0)
  69. #define PACP_FILE_HEADER_CREATE(_head) \
  70. do { \
  71. (_head)->magic = PCAP_FILE_ID; \
  72. (_head)->version_major = PCAP_VERSION_MAJOR; \
  73. (_head)->version_minor = PCAP_VERSION_MINOR; \
  74. (_head)->thiszone = GREENWICH_MEAN_TIME; \
  75. (_head)->sigfigs = PRECISION_OF_TIME_STAMP; \
  76. (_head)->snaplen = MAX_LENTH_OF_CAPTURE_PKG; \
  77. (_head)->linktype = LINKTYPE_ETHERNET; \
  78. } while (0)
  79. #define PACP_ZERO_PKTHDR_CREATE(_head, _len) \
  80. do{ \
  81. (_head)->ts.tv_sec = 0; \
  82. (_head)->ts.tv_usec = 0; \
  83. (_head)->caplen = _len; \
  84. (_head)->len = _len; \
  85. } while (0)
  86. #define PACP_PKTHDR_CREATE(_head, _p) \
  87. do{ \
  88. (_head)->ts.tv_sec = _p->tick / 1000; \
  89. (_head)->ts.tv_usec = (_p->tick % 1000) * 1000; \
  90. (_head)->caplen = _p->tot_len; \
  91. (_head)->len = _p->tot_len; \
  92. } while (0)
  93. #if defined(RT_VERSION_CHECK)
  94. #if (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 2, 0))
  95. #define dbg_log(level, fmt, ...) \
  96. if ((level) <= DBG_LEVEL) \
  97. { \
  98. switch(level) \
  99. { \
  100. case DBG_ERROR: _DBG_LOG_HDR("E", 31); break; \
  101. case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \
  102. case DBG_INFO: _DBG_LOG_HDR("I", 32); break; \
  103. case DBG_LOG: _DBG_LOG_HDR("D", 0); break; \
  104. default: break; \
  105. } \
  106. rt_kprintf(fmt, ##__VA_ARGS__); \
  107. _DBG_COLOR(0); \
  108. }
  109. #endif
  110. #endif
  111. struct tcpdump_buf
  112. {
  113. rt_uint16_t tot_len;
  114. rt_tick_t tick;
  115. void *buf;
  116. };
  117. struct rt_pcap_file_header
  118. {
  119. rt_uint32_t magic;
  120. rt_uint16_t version_major;
  121. rt_uint16_t version_minor;
  122. rt_int32_t thiszone;
  123. rt_uint32_t sigfigs;
  124. rt_uint32_t snaplen;
  125. rt_uint32_t linktype;
  126. };
  127. struct rt_timeval
  128. {
  129. rt_uint32_t tv_sec;
  130. rt_uint32_t tv_usec;
  131. };
  132. struct rt_pcap_pkthdr
  133. {
  134. struct rt_timeval ts;
  135. rt_uint32_t caplen;
  136. rt_uint32_t len;
  137. };
  138. enum rt_tcpdump_return_param
  139. {
  140. STOP = -2,
  141. HELP = -3,
  142. };
  143. static struct rt_device *tcpdump_pipe;
  144. static struct rt_mailbox *tcpdump_mb;
  145. static struct netif *netif;
  146. static netif_linkoutput_fn link_output;
  147. static netif_input_fn input;
  148. static const char *name;
  149. static char *filename;
  150. static const char *eth;
  151. static char *ethname;
  152. static const char *mode;
  153. static int fd = -1;
  154. static void rt_tcpdump_filename_del(void);
  155. static void rt_tcpdump_ethname_del(void);
  156. static void rt_tcpdump_error_info_deal(void);
  157. static void rt_tcpdump_init_indicate(void);
  158. static rt_err_t rt_tcpdump_pcap_file_save(const void *buf, int len);
  159. static rt_err_t (*tcpdump_write)(const void *buf, int len);
  160. #ifdef PKG_NETUTILS_TCPDUMP_PRINT
  161. #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
  162. static void hex_dump(const rt_uint8_t *ptr, rt_size_t buflen)
  163. {
  164. unsigned char *buf = (unsigned char *)ptr;
  165. int i, j;
  166. RT_ASSERT(ptr != RT_NULL);
  167. for (i = 0; i < buflen; i += 16)
  168. {
  169. rt_kprintf("%08X: ", i);
  170. for (j = 0; j < 16; j++)
  171. if (i + j < buflen)
  172. rt_kprintf("%02X ", buf[i + j]);
  173. else
  174. rt_kprintf(" ");
  175. rt_kprintf(" ");
  176. for (j = 0; j < 16; j++)
  177. if (i + j < buflen)
  178. rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
  179. rt_kprintf("\n");
  180. }
  181. }
  182. #endif
  183. /* get tx data */
  184. static err_t _netif_linkoutput(struct netif *netif, struct pbuf *p)
  185. {
  186. // pbuf->payload + sizeof(struct tcpdump_buf)
  187. struct tcpdump_buf *tbuf = (struct tcpdump_buf *)rt_malloc(p->tot_len+sizeof(struct tcpdump_buf));
  188. RT_ASSERT(tbuf != RT_NULL);
  189. RT_ASSERT(netif != RT_NULL);
  190. tbuf->tick = rt_tick_get();
  191. tbuf->buf = ((rt_uint8_t *)tbuf) + sizeof(struct tcpdump_buf);
  192. tbuf->tot_len = p->tot_len;
  193. pbuf_copy_partial(p, tbuf->buf, p->tot_len, 0);
  194. if (p != RT_NULL)
  195. {
  196. if (rt_mb_send(tcpdump_mb, (rt_uint32_t)tbuf) != RT_EOK)
  197. {
  198. rt_free(tbuf);
  199. }
  200. }
  201. return link_output(netif, p);
  202. }
  203. /* get rx data */
  204. static err_t _netif_input(struct pbuf *p, struct netif *inp)
  205. {
  206. // pbuf->payload + sizeof(struct tcpdump_buf)
  207. struct tcpdump_buf *tbuf = (struct tcpdump_buf *)rt_malloc(p->tot_len+sizeof(struct tcpdump_buf));
  208. RT_ASSERT(tbuf != RT_NULL);
  209. RT_ASSERT(netif != RT_NULL);
  210. tbuf->tick = rt_tick_get();
  211. tbuf->buf = ((rt_uint8_t *)tbuf) + sizeof(struct tcpdump_buf);
  212. tbuf->tot_len = p->tot_len;
  213. pbuf_copy_partial(p, tbuf->buf, p->tot_len, 0);
  214. if (p != RT_NULL)
  215. {
  216. if (rt_mb_send(tcpdump_mb, (rt_uint32_t)tbuf) != RT_EOK)
  217. {
  218. rt_free(tbuf);
  219. }
  220. }
  221. return input(p, inp);
  222. }
  223. /* import pcap file into your PC through file-system */
  224. static rt_err_t rt_tcpdump_pcap_file_write(const void *buf, int len)
  225. {
  226. int length;
  227. if (filename == RT_NULL)
  228. {
  229. dbg_log(DBG_ERROR, "file name is null!\n");
  230. return -RT_ERROR;
  231. }
  232. // if ((len == 0) && (fd > 0))
  233. // {
  234. // dbg_log(DBG_ERROR, "ip mess error and close file! len = %d, fd = %d\n", len, fd);
  235. // close(fd);
  236. // fd = -1;
  237. // return -RT_ERROR;
  238. // }
  239. if (fd < 0)
  240. {
  241. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
  242. if (fd < 0)
  243. {
  244. dbg_log(DBG_ERROR, "open file failed!\n");
  245. return -RT_ERROR;
  246. }
  247. }
  248. length = write(fd, buf, len);
  249. if (length != len)
  250. {
  251. dbg_log(DBG_ERROR, "write data failed, length: %d\n", length);
  252. close(fd);
  253. return -RT_ERROR;
  254. }
  255. return RT_EOK;
  256. }
  257. /* Import pcap file into your PC through rdb tools */
  258. static rt_err_t rt_tcpdump_pcap_file_save(const void *buf, int len)
  259. {
  260. rt_device_write(tcpdump_pipe, 0, buf, len);
  261. return RT_EOK;
  262. }
  263. /* write ip mess and print */
  264. static void rt_tcpdump_ip_mess_write(struct tcpdump_buf *p)
  265. {
  266. struct tcpdump_buf *tbuf = p;
  267. RT_ASSERT(tbuf != RT_NULL);
  268. #ifdef PKG_NETUTILS_TCPDUMP_PRINT
  269. hex_dump(tbuf->buf, tbuf->tot_len);
  270. #endif
  271. /* write ip mess */
  272. if (tcpdump_write != RT_NULL)
  273. {
  274. // rt_kprintf("tbuf->tot_len = %d\n", tbuf->tot_len);
  275. tcpdump_write(tbuf->buf, tbuf->tot_len);
  276. }
  277. }
  278. /* write pcap file header */
  279. static rt_err_t rt_tcpdump_pcap_file_init(void)
  280. {
  281. struct rt_pcap_file_header file_header;
  282. int res = -1;
  283. if (tcpdump_pipe != RT_NULL)
  284. {
  285. if (rt_device_open(tcpdump_pipe, RT_DEVICE_OFLAG_WRONLY) != RT_EOK)
  286. {
  287. dbg_log(DBG_LOG, "not found pipe device!\n");
  288. return -RT_ERROR;
  289. }
  290. }
  291. /* in rdb mode does not need to write pcap file header */
  292. if ((tcpdump_write != RT_NULL) && (tcpdump_write == rt_tcpdump_pcap_file_write))
  293. {
  294. struct rt_pcap_pkthdr pkthdr;
  295. /* pcap header */
  296. PACP_FILE_HEADER_CREATE(&file_header);
  297. res = tcpdump_write(&file_header, sizeof(file_header));
  298. /* Positioning at time zero */
  299. char pacp_zero[] =
  300. {
  301. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
  302. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
  303. 0x08, 0x00,
  304. ' ', ' ', 'R', 'T', 'T', 'H', 'R', 'E', 'A', 'D', ' ', 'Z', 'E', 'R', 'O'
  305. };
  306. PACP_ZERO_PKTHDR_CREATE(&pkthdr, sizeof(pacp_zero));
  307. tcpdump_write(&pkthdr, sizeof(pkthdr));
  308. tcpdump_write(pacp_zero, sizeof(pacp_zero));
  309. }
  310. #ifdef PKG_NETUTILS_TCPDUMP_PRINT
  311. hex_dump((rt_uint8_t *)&file_header, PCAP_FILE_HEADER_SIZE);
  312. #endif
  313. if (res != RT_EOK)
  314. return -RT_ERROR;
  315. return RT_EOK;
  316. }
  317. static void rt_tcpdump_thread_entry(void *param)
  318. {
  319. // struct pbuf *pbuf = RT_NULL;
  320. struct tcpdump_buf *tbuf = RT_NULL;
  321. struct rt_pcap_pkthdr pkthdr;
  322. rt_uint32_t mbval;
  323. while (1)
  324. {
  325. if (rt_mb_recv(tcpdump_mb, (rt_ubase_t *)&mbval, RT_WAITING_FOREVER) == RT_EOK)
  326. {
  327. tbuf = (struct tcpdump_buf *)mbval;
  328. RT_ASSERT(tbuf != RT_NULL);
  329. /* write pkthdr */
  330. if ((tcpdump_write != RT_NULL) && (tcpdump_write == rt_tcpdump_pcap_file_write))
  331. {
  332. PACP_PKTHDR_CREATE(&pkthdr, tbuf);
  333. tcpdump_write(&pkthdr, sizeof(pkthdr));
  334. }
  335. #ifdef PKG_NETUTILS_TCPDUMP_PRINT
  336. hex_dump((rt_uint8_t *)&pkthdr, PCAP_PKTHDR_SIZE);
  337. #endif
  338. rt_tcpdump_ip_mess_write(tbuf);
  339. rt_free(tbuf);
  340. tbuf = RT_NULL;
  341. }
  342. /* tcpdump deinit, the mailbox does not receive the data, exits the thread*/
  343. else
  344. {
  345. dbg_log(DBG_INFO, "tcpdump stop and tcpdump thread exit!\n");
  346. close(fd);
  347. fd = -1;
  348. if (tcpdump_pipe != RT_NULL)
  349. rt_device_close((rt_device_t)tcpdump_pipe);
  350. tcpdump_write = RT_NULL;
  351. rt_tcpdump_filename_del();
  352. rt_tcpdump_ethname_del();
  353. return;
  354. }
  355. }
  356. }
  357. /* set file name */
  358. static void rt_tcpdump_filename_set(const char *name)
  359. {
  360. filename = rt_strdup(name);
  361. }
  362. /* delete file name */
  363. static void rt_tcpdump_filename_del(void)
  364. {
  365. name = RT_NULL;
  366. if (filename != RT_NULL)
  367. rt_free(filename);
  368. filename = RT_NULL;
  369. }
  370. /* set network interface name */
  371. static void rt_tcpdump_ethname_set(const char *eth)
  372. {
  373. ethname = rt_strdup(eth);
  374. }
  375. /* delete network interface name */
  376. static void rt_tcpdump_ethname_del(void)
  377. {
  378. eth = RT_NULL;
  379. if (ethname != RT_NULL)
  380. rt_free(ethname);
  381. }
  382. static int rt_tcpdump_init(void)
  383. {
  384. struct eth_device *device;
  385. rt_thread_t tid;
  386. rt_base_t level;
  387. if (netif != RT_NULL)
  388. {
  389. dbg_log(DBG_ERROR, "This command is running, please stop before you use the [tcpdump -p] command!\n");
  390. return -RT_ERROR;
  391. }
  392. /* print and set default state */
  393. rt_tcpdump_init_indicate();
  394. tcpdump_pipe = rt_device_find(TCPDUMP_PIPE_DEVICE);
  395. /* file-system mode does not judge pipe */
  396. if (tcpdump_write != rt_tcpdump_pcap_file_write)
  397. {
  398. if (tcpdump_pipe == RT_NULL)
  399. {
  400. dbg_log(DBG_ERROR, "pipe is error!\n");
  401. return -RT_ERROR;
  402. }
  403. }
  404. device = (struct eth_device *)rt_device_find(eth);
  405. if (device == RT_NULL)
  406. {
  407. dbg_log(DBG_ERROR, "network interface card [%s] device not find!\n", eth);
  408. dbg_log(DBG_ERROR, "tcpdump thread startup failed and enter the correct network interface please!\n");
  409. return -RT_ERROR;
  410. }
  411. if ((device->netif == RT_NULL) || (device->netif->linkoutput == RT_NULL))
  412. {
  413. dbg_log(DBG_ERROR, "this device not e0!\n");
  414. return -RT_ERROR;
  415. }
  416. tcpdump_mb = rt_mb_create("tdrmb", TCPDUMP_MAX_MSG, RT_IPC_FLAG_FIFO);
  417. if (tcpdump_mb == RT_NULL)
  418. {
  419. dbg_log(DBG_ERROR, "tcp dump mp create fail!\n");
  420. return -RT_ERROR;
  421. }
  422. tid = rt_thread_create("tcpdump", rt_tcpdump_thread_entry, RT_NULL, 2048, 12, 10);
  423. if (tid == RT_NULL)
  424. {
  425. rt_mb_delete(tcpdump_mb);
  426. tcpdump_mb = RT_NULL;
  427. dbg_log(DBG_ERROR, "tcpdump thread create fail!\n");
  428. return -RT_ERROR;
  429. }
  430. rt_tcpdump_filename_set(name);
  431. rt_tcpdump_ethname_set(eth);
  432. netif = device->netif;
  433. /* linkoutput and input init */
  434. level = rt_hw_interrupt_disable();
  435. link_output = netif->linkoutput;
  436. netif->linkoutput = _netif_linkoutput;
  437. input = netif->input;
  438. netif->input = _netif_input;
  439. rt_hw_interrupt_enable(level);
  440. /* linkoutput and input init */
  441. /* write pcap file header */
  442. rt_tcpdump_pcap_file_init();
  443. rt_thread_startup(tid);
  444. dbg_log(DBG_INFO, "tcpdump start!\n");
  445. return RT_EOK;
  446. }
  447. static void rt_tcpdump_deinit(void)
  448. {
  449. rt_base_t level;
  450. struct rt_mailbox *tcpdump_mb_tmp = RT_NULL;
  451. if (netif == RT_NULL)
  452. {
  453. dbg_log(DBG_ERROR, "capture packet stopped, no repeat input required!\n");
  454. return;
  455. }
  456. /* linkoutput and input deinit */
  457. level = rt_hw_interrupt_disable();
  458. tcpdump_mb_tmp = tcpdump_mb;
  459. tcpdump_mb = RT_NULL;
  460. netif->linkoutput = link_output;
  461. netif->input = input;
  462. netif = RT_NULL;
  463. rt_hw_interrupt_enable(level);
  464. /* linkoutput and input deinit */
  465. rt_thread_mdelay(10);
  466. rt_mb_delete(tcpdump_mb_tmp);
  467. tcpdump_mb_tmp = RT_NULL;
  468. }
  469. static void rt_tcpdump_help_info_print(void)
  470. {
  471. rt_kprintf("\n");
  472. rt_kprintf("|>------------------------- help -------------------------<|\n");
  473. rt_kprintf("| tcpdump [-p] [-h] [-i interface] [-m mode] [-w file] |\n");
  474. rt_kprintf("| |\n");
  475. rt_kprintf("| -h: help |\n");
  476. rt_kprintf("| -i: specify the network interface for listening |\n");
  477. rt_kprintf("| -m: choose what mode(file-system or rdb) to save the file|\n");
  478. rt_kprintf("| -w: write the captured packets into an xx.pcap file |\n");
  479. rt_kprintf("| -p: stop capturing packets |\n");
  480. rt_kprintf("| |\n");
  481. rt_kprintf("| e.g.: |\n");
  482. rt_kprintf("| specify network interface and select save mode \\ |\n");
  483. rt_kprintf("| and specify filename |\n");
  484. rt_kprintf("| tcpdump -ie0 -mfile -wtext.pcap |\n");
  485. rt_kprintf("| tcpdump -ie0 -mrdb -wtext.pcap |\n");
  486. rt_kprintf("| |\n");
  487. rt_kprintf("| -m: file-system mode |\n");
  488. rt_kprintf("| tcpdump -mfile |\n");
  489. rt_kprintf("| |\n");
  490. rt_kprintf("| -m: rdb mode |\n");
  491. rt_kprintf("| tcpdump -mrdb |\n");
  492. rt_kprintf("| |\n");
  493. rt_kprintf("| -w: file |\n");
  494. rt_kprintf("| tcpdump -wtext.pcap |\n");
  495. rt_kprintf("| |\n");
  496. rt_kprintf("| -p: stop |\n");
  497. rt_kprintf("| tcpdump -p |\n");
  498. rt_kprintf("| |\n");
  499. rt_kprintf("| -h: help |\n");
  500. rt_kprintf("| tcpdump -h |\n");
  501. rt_kprintf("| |\n");
  502. rt_kprintf("| write commands but no arguments are illegal!! |\n");
  503. rt_kprintf("| e.g.: tcpdump -i / -i -mfile / -i -mfile -wtext.pcap |\n");
  504. rt_kprintf("|>------------------------- help -------------------------<|\n");
  505. rt_kprintf("\n");
  506. }
  507. static void rt_tcpdump_error_info_deal(void)
  508. {
  509. dbg_log(DBG_ERROR, "tcpdump command is incorrect, please refer to the help information!\n");
  510. rt_tcpdump_help_info_print();
  511. }
  512. /* print and set default state */
  513. static void rt_tcpdump_init_indicate(void)
  514. {
  515. int name_flag = 0, eth_flag = 0, mode_flag = 0;
  516. if (eth == RT_NULL)
  517. {
  518. rt_kprintf("[TCPDUMP]default selection [e0] network interface\n");
  519. eth = "e0";
  520. eth_flag = 1;
  521. }
  522. if (tcpdump_write == RT_NULL)
  523. {
  524. rt_kprintf("[TCPDUMP]default selection [file-system] mode\n");
  525. tcpdump_write = rt_tcpdump_pcap_file_write;
  526. mode_flag = 1;
  527. }
  528. if (name == RT_NULL)
  529. {
  530. rt_kprintf("[TCPDUMP]default save in [sample.pcap]\n");
  531. name = TCPDUMP_DEFAULT_NANE;
  532. name_flag = 1;
  533. }
  534. if (eth_flag == 0)
  535. rt_kprintf("[TCPDUMP]select [%s] network interface\n", eth);
  536. if (mode_flag == 0)
  537. {
  538. if (STRCMP(mode, ==, "file"))
  539. rt_kprintf("[TCPDUMP]select [file-system] mode\n");
  540. if (STRCMP(mode, ==, "rdb"))
  541. rt_kprintf("[TCPDUMP]select [rdb] mode\n");
  542. }
  543. if (name_flag == 0)
  544. rt_kprintf("[TCPDUMP]save in [%s]\n", name);
  545. }
  546. /* msh command-line deal */
  547. static int rt_tcpdump_cmd_deal(struct optparse *options)
  548. {
  549. switch (options->optopt)
  550. {
  551. case 'p':
  552. rt_tcpdump_deinit();
  553. return STOP;
  554. case 'h':
  555. rt_tcpdump_help_info_print();
  556. return HELP;
  557. case 'i':
  558. /* it's illegal without parameters. */
  559. if (options->optarg == RT_NULL)
  560. return -RT_ERROR;
  561. eth = options->optarg;
  562. return RT_EOK;
  563. case 'm':
  564. if (options->optarg == RT_NULL)
  565. return -RT_ERROR;
  566. if (STRCMP(options->optarg, ==, "file"))
  567. {
  568. mode = options->optarg;
  569. tcpdump_write = rt_tcpdump_pcap_file_write;
  570. return RT_EOK;
  571. }
  572. if (STRCMP(options->optarg, ==, "rdb"))
  573. {
  574. mode = options->optarg;
  575. tcpdump_write = rt_tcpdump_pcap_file_save;
  576. return RT_EOK;
  577. }
  578. /* User input Error */
  579. return -RT_ERROR;
  580. case 'w':
  581. if (options->optarg == RT_NULL)
  582. return -RT_ERROR;
  583. name = options->optarg;
  584. break;
  585. default:
  586. return -RT_ERROR;
  587. }
  588. return RT_EOK;
  589. }
  590. /* msh command-line parsing */
  591. static int rt_tcpdump_cmd_parse(int argc, char *argv[], const char *cmd)
  592. {
  593. int ch, res, invalid_argv = 0;
  594. struct optparse options;
  595. optparse_init(&options, argc, argv);
  596. while ((ch = optparse(&options, cmd)) != -1)
  597. {
  598. ch = ch;
  599. invalid_argv = 1;
  600. switch (options.optopt)
  601. {
  602. case 'p':
  603. return rt_tcpdump_cmd_deal(&options);
  604. case 'h':
  605. return rt_tcpdump_cmd_deal(&options);
  606. case 'i':
  607. res = rt_tcpdump_cmd_deal(&options);
  608. break;
  609. case 'm':
  610. res = rt_tcpdump_cmd_deal(&options);
  611. break;
  612. case 'w':
  613. res = rt_tcpdump_cmd_deal(&options);
  614. break;
  615. default:
  616. rt_tcpdump_error_info_deal();
  617. return -RT_ERROR;
  618. }
  619. if (res == -RT_ERROR)
  620. {
  621. rt_tcpdump_error_info_deal();
  622. return res;
  623. }
  624. }
  625. /* judge invalid command */
  626. if (invalid_argv == 0)
  627. {
  628. rt_tcpdump_error_info_deal();
  629. return -RT_ERROR;
  630. }
  631. return RT_EOK;
  632. }
  633. static void rt_tcpdump_cmd_argv_deinit(void)
  634. {
  635. eth = RT_NULL;
  636. tcpdump_write = RT_NULL;
  637. name = RT_NULL;
  638. }
  639. static int tcpdump_test(int argc, char *argv[])
  640. {
  641. int res = 0;
  642. if (argc == 1)
  643. {
  644. rt_tcpdump_cmd_argv_deinit();
  645. rt_tcpdump_init();
  646. return RT_EOK;
  647. }
  648. rt_tcpdump_cmd_argv_deinit();
  649. res = rt_tcpdump_cmd_parse(argc, argv, MSH_CMD);
  650. if (res == STOP)
  651. return RT_EOK;
  652. if (res == HELP)
  653. return RT_EOK;
  654. if (res == -RT_ERROR)
  655. return -RT_ERROR;
  656. rt_tcpdump_init();
  657. return RT_EOK;
  658. }
  659. #ifdef RT_USING_FINSH
  660. #include <finsh.h>
  661. MSH_CMD_EXPORT_ALIAS(tcpdump_test, tcpdump, test optparse_short cmd.);
  662. #endif
  663. #endif /* PKG_NETUTILS_TCPDUMP */