tcpdump.c 23 KB

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