tcpdump.c 22 KB

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