tcpdump.c 21 KB

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