net_procfs.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /****************************************************************************
  2. * net/procfs/net_procfs.c
  3. *
  4. * Copyright (C) 2015 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <sys/statfs.h>
  41. #include <sys/stat.h>
  42. #include <stdint.h>
  43. #include <stdbool.h>
  44. #include <string.h>
  45. #include <fcntl.h>
  46. #include <libgen.h>
  47. #include <assert.h>
  48. #include <errno.h>
  49. #include <debug.h>
  50. #include <nuttx/kmalloc.h>
  51. #include <nuttx/fs/fs.h>
  52. #include <nuttx/fs/procfs.h>
  53. #include <nuttx/fs/dirent.h>
  54. #include <nuttx/lib/regex.h>
  55. #include <nuttx/net/netdev.h>
  56. #include "netdev/netdev.h"
  57. #include "procfs/procfs.h"
  58. #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \
  59. !defined(CONFIG_FS_PROCFS_EXCLUDE_NET)
  60. /****************************************************************************
  61. * Pre-processor Definitions
  62. ****************************************************************************/
  63. /* Directory entry indices */
  64. #ifdef CONFIG_NET_STATISTICS
  65. # define STAT_INDEX 0
  66. # ifdef CONFIG_NET_MLD
  67. # define MLD_INDEX 1
  68. # define _ROUTE_INDEX 2
  69. # else
  70. # define _ROUTE_INDEX 1
  71. # endif
  72. #else
  73. # define _ROUTE_INDEX 0
  74. #endif
  75. #ifdef CONFIG_NET_ROUTE
  76. # define ROUTE_INDEX _ROUTE_INDEX
  77. # define DEV_INDEX (_ROUTE_INDEX + 1)
  78. #else
  79. # define DEV_INDEX _ROUTE_INDEX
  80. #endif
  81. /****************************************************************************
  82. * Private Function Prototypes
  83. ****************************************************************************/
  84. /* File system methods */
  85. static int netprocfs_open(FAR struct file *filep, FAR const char *relpath,
  86. int oflags, mode_t mode);
  87. static int netprocfs_close(FAR struct file *filep);
  88. static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer,
  89. size_t buflen);
  90. static int netprocfs_dup(FAR const struct file *oldp,
  91. FAR struct file *newp);
  92. static int netprocfs_opendir(FAR const char *relpath,
  93. FAR struct fs_dirent_s *dir);
  94. static int netprocfs_closedir(FAR struct fs_dirent_s *dir);
  95. static int netprocfs_readdir(FAR struct fs_dirent_s *dir);
  96. static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir);
  97. static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf);
  98. /****************************************************************************
  99. * Public Data
  100. ****************************************************************************/
  101. /* See include/nutts/fs/procfs.h
  102. * We use the old-fashioned kind of initializers so that this will compile
  103. * with any compiler.
  104. */
  105. const struct procfs_operations net_procfsoperations =
  106. {
  107. netprocfs_open, /* open */
  108. netprocfs_close, /* close */
  109. netprocfs_read, /* read */
  110. NULL, /* write */
  111. netprocfs_dup, /* dup */
  112. netprocfs_opendir, /* opendir */
  113. netprocfs_closedir, /* closedir */
  114. netprocfs_readdir, /* readdir */
  115. netprocfs_rewinddir, /* rewinddir */
  116. netprocfs_stat /* stat */
  117. };
  118. extern const struct procfs_operations net_procfs_routeoperations;
  119. /****************************************************************************
  120. * Private Functions
  121. ****************************************************************************/
  122. /****************************************************************************
  123. * Name: netprocfs_open
  124. ****************************************************************************/
  125. static int netprocfs_open(FAR struct file *filep, FAR const char *relpath,
  126. int oflags, mode_t mode)
  127. {
  128. FAR struct netprocfs_file_s *priv;
  129. FAR struct net_driver_s *dev;
  130. enum netprocfs_entry_e entry;
  131. finfo("Open '%s'\n", relpath);
  132. /* PROCFS is read-only. Any attempt to open with any kind of write
  133. * access is not permitted.
  134. *
  135. * REVISIT: Write-able proc files could be quite useful.
  136. */
  137. if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) &&
  138. (net_procfsoperations.write == NULL))
  139. {
  140. ferr("ERROR: Only O_RDONLY supported\n");
  141. return -EACCES;
  142. }
  143. #ifdef CONFIG_NET_STATISTICS
  144. /* "net/stat" is an acceptable value for the relpath only if network layer
  145. * statistics are enabled.
  146. */
  147. if (strcmp(relpath, "net/stat") == 0)
  148. {
  149. entry = NETPROCFS_SUBDIR_STAT;
  150. dev = NULL;
  151. }
  152. else
  153. #ifdef CONFIG_NET_MLD
  154. /* "net/mld" is an acceptable value for the relpath only if MLD is enabled. */
  155. if (strcmp(relpath, "net/mld") == 0)
  156. {
  157. entry = NETPROCFS_SUBDIR_MLD;
  158. dev = NULL;
  159. }
  160. else
  161. #endif
  162. #endif
  163. #ifdef CONFIG_NET_ROUTE
  164. /* "net/route" is an acceptable value for the relpath only if routing
  165. * table support is initialized.
  166. */
  167. if (match("net/route/**", relpath))
  168. {
  169. /* Use the /net/route directory */
  170. return net_procfs_routeoperations.open(filep, relpath, oflags, mode);
  171. }
  172. else
  173. #endif
  174. {
  175. FAR char *devname;
  176. FAR char *copy;
  177. /* Otherwise, we need to search the list of registered network devices
  178. * to determine if the name corresponds to a network device.
  179. */
  180. copy = strdup(relpath);
  181. if (copy == NULL)
  182. {
  183. ferr("ERROR: strdup failed\n");
  184. return -ENOMEM;
  185. }
  186. devname = basename(copy);
  187. dev = netdev_findbyname(devname);
  188. kmm_free(copy);
  189. if (dev == NULL)
  190. {
  191. ferr("ERROR: relpath is '%s'\n", relpath);
  192. return -ENOENT;
  193. }
  194. entry = NETPROCFS_SUBDIR_DEV;
  195. }
  196. /* Allocate the open file structure */
  197. priv = (FAR struct netprocfs_file_s *)
  198. kmm_zalloc(sizeof(struct netprocfs_file_s));
  199. if (!priv)
  200. {
  201. ferr("ERROR: Failed to allocate file attributes\n");
  202. return -ENOMEM;
  203. }
  204. /* Initialize the open-file structure */
  205. priv->dev = dev;
  206. priv->entry = entry;
  207. /* Save the open file structure as the open-specific state in
  208. * filep->f_priv.
  209. */
  210. filep->f_priv = (FAR void *)priv;
  211. return OK;
  212. }
  213. /****************************************************************************
  214. * Name: netprocfs_close
  215. ****************************************************************************/
  216. static int netprocfs_close(FAR struct file *filep)
  217. {
  218. FAR struct netprocfs_file_s *priv;
  219. /* Recover our private data from the struct file instance */
  220. priv = (FAR struct netprocfs_file_s *)filep->f_priv;
  221. DEBUGASSERT(priv);
  222. /* Release the file attributes structure */
  223. kmm_free(priv);
  224. filep->f_priv = NULL;
  225. return OK;
  226. }
  227. /****************************************************************************
  228. * Name: netprocfs_read
  229. ****************************************************************************/
  230. static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer,
  231. size_t buflen)
  232. {
  233. FAR struct netprocfs_file_s *priv;
  234. ssize_t nreturned;
  235. finfo("buffer=%p buflen=%lu\n", buffer, (unsigned long)buflen);
  236. /* Recover our private data from the struct file instance */
  237. priv = (FAR struct netprocfs_file_s *)filep->f_priv;
  238. DEBUGASSERT(priv);
  239. /* Read according to the sub-directory */
  240. switch (priv->entry)
  241. {
  242. case NETPROCFS_SUBDIR_DEV:
  243. /* Show device-specific statistics */
  244. nreturned = netprocfs_read_devstats(priv, buffer, buflen);
  245. break;
  246. #ifdef CONFIG_NET_STATISTICS
  247. case NETPROCFS_SUBDIR_STAT:
  248. /* Show the network layer statistics */
  249. nreturned = netprocfs_read_netstats(priv, buffer, buflen);
  250. break;
  251. #ifdef CONFIG_NET_MLD
  252. case NETPROCFS_SUBDIR_MLD:
  253. /* Show the MLD statistics */
  254. nreturned = netprocfs_read_mldstats(priv, buffer, buflen);
  255. break;
  256. #endif
  257. #endif
  258. #ifdef CONFIG_NET_ROUTE
  259. case NETPROCFS_SUBDIR_ROUTE:
  260. nerr("ERROR: Cannot read from directory net/route\n");
  261. #endif
  262. default:
  263. nerr("ERROR: Invalid entry for reading: %u\n", priv->entry);
  264. nreturned = -EINVAL;
  265. }
  266. /* Update the file offset */
  267. if (nreturned > 0)
  268. {
  269. filep->f_pos += nreturned;
  270. }
  271. return nreturned;
  272. }
  273. /****************************************************************************
  274. * Name: netprocfs_dup
  275. *
  276. * Description:
  277. * Duplicate open file data in the new file structure.
  278. *
  279. ****************************************************************************/
  280. static int netprocfs_dup(FAR const struct file *oldp, FAR struct file *newp)
  281. {
  282. FAR struct netprocfs_file_s *oldpriv;
  283. FAR struct netprocfs_file_s *newpriv;
  284. finfo("Dup %p->%p\n", oldp, newp);
  285. /* Recover our private data from the old struct file instance */
  286. oldpriv = (FAR struct netprocfs_file_s *)oldp->f_priv;
  287. DEBUGASSERT(oldpriv);
  288. /* Allocate a new container to hold the task and attribute selection */
  289. newpriv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s));
  290. if (!newpriv)
  291. {
  292. ferr("ERROR: Failed to allocate file attributes\n");
  293. return -ENOMEM;
  294. }
  295. /* The copy the file attribtes from the old attributes to the new */
  296. memcpy(newpriv, oldpriv, sizeof(struct netprocfs_file_s));
  297. /* Save the new attributes in the new file structure */
  298. newp->f_priv = (FAR void *)newpriv;
  299. return OK;
  300. }
  301. /****************************************************************************
  302. * Name: netprocfs_opendir
  303. *
  304. * Description:
  305. * Open a directory for read access
  306. *
  307. ****************************************************************************/
  308. static int netprocfs_opendir(FAR const char *relpath,
  309. FAR struct fs_dirent_s *dir)
  310. {
  311. FAR struct netprocfs_level1_s *level1;
  312. int ndevs;
  313. int ret;
  314. finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL");
  315. DEBUGASSERT(relpath && dir && !dir->u.procfs);
  316. /* "net" and "net/route" are the only values of relpath that are
  317. * directories.
  318. */
  319. #ifdef CONFIG_NET_ROUTE
  320. if (match("net/route", relpath) || match("net/route/**", relpath))
  321. {
  322. /* Use the /net/route directory */
  323. return net_procfs_routeoperations.opendir(relpath, dir);
  324. }
  325. #endif
  326. /* Assume that path refers to the 1st level subdirectory. Allocate the
  327. * level1 the dirent structure before checking.
  328. */
  329. level1 = (FAR struct netprocfs_level1_s *)
  330. kmm_zalloc(sizeof(struct netprocfs_level1_s));
  331. if (level1 == NULL)
  332. {
  333. ferr("ERROR: Failed to allocate the level1 directory structure\n");
  334. return -ENOMEM;
  335. }
  336. level1->base.level = 1;
  337. if (strcmp(relpath, "net") == 0)
  338. {
  339. /* Count the number of network devices */
  340. ndevs = netdev_count();
  341. /* Initialize base structure components */
  342. level1->base.nentries = ndevs;
  343. #ifdef CONFIG_NET_STATISTICS
  344. level1->base.nentries++;
  345. #ifdef CONFIG_NET_MLD
  346. level1->base.nentries++;
  347. #endif
  348. #endif
  349. #ifdef CONFIG_NET_ROUTE
  350. level1->base.nentries++;
  351. #endif
  352. }
  353. else
  354. {
  355. /* REVISIT: We really need to check if the relpath refers to a network
  356. * device. In that case, we need to return -ENOTDIR. Otherwise, we
  357. * should return -ENOENT.
  358. */
  359. ferr("ERROR: Bad relpath: %s\n", relpath);
  360. ret = -ENOTDIR;
  361. goto errout_with_alloc;
  362. }
  363. dir->u.procfs = (FAR void *)level1;
  364. return OK;
  365. errout_with_alloc:
  366. kmm_free(level1);
  367. return ret;
  368. }
  369. /****************************************************************************
  370. * Name: netprocfs_closedir
  371. *
  372. * Description: Close the directory listing
  373. *
  374. ****************************************************************************/
  375. static int netprocfs_closedir(FAR struct fs_dirent_s *dir)
  376. {
  377. FAR struct netprocfs_level1_s *priv;
  378. DEBUGASSERT(dir && dir->u.procfs);
  379. priv = dir->u.procfs;
  380. if (priv)
  381. {
  382. kmm_free(priv);
  383. }
  384. dir->u.procfs = NULL;
  385. return OK;
  386. }
  387. /****************************************************************************
  388. * Name: netprocfs_readdir
  389. *
  390. * Description: Read the next directory entry
  391. *
  392. ****************************************************************************/
  393. static int netprocfs_readdir(FAR struct fs_dirent_s *dir)
  394. {
  395. FAR struct netprocfs_level1_s *level1;
  396. FAR struct net_driver_s *dev;
  397. int index;
  398. int ret;
  399. DEBUGASSERT(dir && dir->u.procfs);
  400. level1 = dir->u.procfs;
  401. DEBUGASSERT(level1->base.level > 0);
  402. /* Are we searching this directory? Or is it just an intermediate on the
  403. * way to a sub-directory?
  404. */
  405. if (level1->base.level == 1)
  406. {
  407. /* This directory.. Have we reached the end of the directory? */
  408. index = level1->base.index;
  409. DEBUGASSERT(index <= level1->base.nentries);
  410. if (index >= level1->base.nentries)
  411. {
  412. /* We signal the end of the directory by returning the special
  413. * error -ENOENT.
  414. */
  415. finfo("Entry %d: End of directory\n", index);
  416. return -ENOENT;
  417. }
  418. #ifdef CONFIG_NET_STATISTICS
  419. if (index == STAT_INDEX)
  420. {
  421. /* Copy the network statistics directory entry */
  422. dir->fd_dir.d_type = DTYPE_FILE;
  423. strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1);
  424. }
  425. else
  426. #ifdef CONFIG_NET_MLD
  427. if (index == MLD_INDEX)
  428. {
  429. /* Copy the MLD directory entry */
  430. dir->fd_dir.d_type = DTYPE_FILE;
  431. strncpy(dir->fd_dir.d_name, "mld", NAME_MAX + 1);
  432. }
  433. else
  434. #endif
  435. #endif
  436. #ifdef CONFIG_NET_ROUTE
  437. if (index == ROUTE_INDEX)
  438. {
  439. /* Copy the network statistics directory entry */
  440. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  441. strncpy(dir->fd_dir.d_name, "route", NAME_MAX + 1);
  442. }
  443. else
  444. #endif
  445. {
  446. int ifindex;
  447. #ifdef CONFIG_NETDEV_IFINDEX
  448. /* For the first network device, ifindex will be zero. We have
  449. * to take some special action to get the correct starting
  450. * ifindex.
  451. */
  452. if (level1->ifindex == 0)
  453. {
  454. ifindex = netdev_nextindex(1);
  455. }
  456. else
  457. {
  458. ifindex = netdev_nextindex(level1->ifindex);
  459. }
  460. if (ifindex < 0)
  461. {
  462. /* There are no more... one must have been unregistered */
  463. return -ENOENT;
  464. }
  465. level1->ifindex = ifindex + 1;
  466. #else
  467. /* Get the raw index, accounting for 1 based indexing */
  468. ifindex = index - DEV_INDEX + 1;
  469. #endif
  470. /* Find the device corresponding to this device index */
  471. dev = netdev_findbyindex(ifindex);
  472. if (dev == NULL)
  473. {
  474. /* What happened? */
  475. return -ENOENT;
  476. }
  477. /* Copy the device statistics file entry */
  478. dir->fd_dir.d_type = DTYPE_FILE;
  479. strncpy(dir->fd_dir.d_name, dev->d_ifname, NAME_MAX + 1);
  480. }
  481. /* Set up the next directory entry offset. NOTE that we could use the
  482. * standard f_pos instead of our own private index.
  483. */
  484. level1->base.index = index + 1;
  485. ret = OK;
  486. }
  487. else
  488. {
  489. /* We are performing a directory search of one of the subdirectories
  490. * and we must let the handler perform the read.
  491. */
  492. DEBUGASSERT(level1->base.procfsentry != NULL &&
  493. level1->base.procfsentry->ops->readdir != NULL);
  494. ret = level1->base.procfsentry->ops->readdir(dir);
  495. }
  496. return ret;
  497. }
  498. /****************************************************************************
  499. * Name: netprocfs_rewindir
  500. *
  501. * Description: Reset directory read to the first entry
  502. *
  503. ****************************************************************************/
  504. static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir)
  505. {
  506. FAR struct netprocfs_level1_s *priv;
  507. DEBUGASSERT(dir && dir->u.procfs);
  508. priv = dir->u.procfs;
  509. priv->base.index = 0;
  510. return OK;
  511. }
  512. /****************************************************************************
  513. * Name: netprocfs_stat
  514. *
  515. * Description: Return information about a file or directory
  516. *
  517. ****************************************************************************/
  518. static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf)
  519. {
  520. /* Check for the directory "net" */
  521. if (strcmp(relpath, "net") == 0)
  522. {
  523. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  524. }
  525. else
  526. #ifdef CONFIG_NET_STATISTICS
  527. /* Check for network statistics "net/stat" */
  528. if (strcmp(relpath, "net/stat") == 0)
  529. {
  530. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  531. }
  532. else
  533. #ifdef CONFIG_NET_MLD
  534. /* Check for MLD statistics "net/mld" */
  535. if (strcmp(relpath, "net/mld") == 0)
  536. {
  537. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  538. }
  539. else
  540. #endif
  541. #endif
  542. #ifdef CONFIG_NET_ROUTE
  543. /* Check for network statistics "net/stat" */
  544. if (strcmp(relpath, "net/route") == 0)
  545. {
  546. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  547. }
  548. else
  549. #endif
  550. {
  551. FAR struct net_driver_s *dev;
  552. FAR char *devname;
  553. FAR char *copy;
  554. /* Otherwise, we need to search the list of registered network devices
  555. * to determine if the name corresponds to a network device.
  556. */
  557. copy = strdup(relpath);
  558. if (copy == NULL)
  559. {
  560. ferr("ERROR: strdup failed\n");
  561. return -ENOMEM;
  562. }
  563. devname = basename(copy);
  564. dev = netdev_findbyname(devname);
  565. kmm_free(copy);
  566. if (dev == NULL)
  567. {
  568. ferr("ERROR: relpath is '%s'\n", relpath);
  569. return -ENOENT;
  570. }
  571. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  572. }
  573. /* File/directory size, access block size */
  574. buf->st_size = 0;
  575. buf->st_blksize = 0;
  576. buf->st_blocks = 0;
  577. return OK;
  578. }
  579. /****************************************************************************
  580. * Public Functions
  581. ****************************************************************************/
  582. /****************************************************************************
  583. * Name: netprocfs_read_linegen
  584. *
  585. * Description:
  586. * Read and format procfs data using a line generation table.
  587. *
  588. * Input Parameters:
  589. * priv - A reference to the network procfs file structure
  590. * buffer - The user-provided buffer into which device status will be
  591. * returned.
  592. * buflen - The size in bytes of the user provided buffer.
  593. * gentab - Table of line generation functions
  594. * nelems - The number of elements in the table
  595. *
  596. * Returned Value:
  597. * Zero (OK) is returned on success; a negated errno value is returned
  598. * on failure.
  599. *
  600. ****************************************************************************/
  601. ssize_t netprocfs_read_linegen(FAR struct netprocfs_file_s *priv,
  602. FAR char *buffer, size_t buflen,
  603. FAR const linegen_t *gentab, int nelems)
  604. {
  605. size_t xfrsize;
  606. ssize_t nreturned;
  607. finfo("buffer=%p buflen=%lu\n", buffer, (unsigned long)buflen);
  608. /* Is there line data already buffered? */
  609. nreturned = 0;
  610. if (priv->linesize > 0)
  611. {
  612. /* Yes, how much can we transfer now? */
  613. xfrsize = priv->linesize;
  614. if (xfrsize > buflen)
  615. {
  616. xfrsize = buflen;
  617. }
  618. /* Transfer the data to the user buffer */
  619. memcpy(buffer, &priv->line[priv->offset], xfrsize);
  620. /* Update pointers, sizes, and offsets */
  621. buffer += xfrsize;
  622. buflen -= xfrsize;
  623. priv->linesize -= xfrsize;
  624. priv->offset += xfrsize;
  625. nreturned = xfrsize;
  626. }
  627. /* Loop until the user buffer is full or until all of the network
  628. * statistics have been transferred. At this point we know that
  629. * either:
  630. *
  631. * 1. The user buffer is full, and/or
  632. * 2. All of the current line data has been transferred.
  633. */
  634. while (buflen > 0 && priv->lineno < nelems)
  635. {
  636. int len;
  637. /* Read the next line into the working buffer */
  638. len = gentab[priv->lineno](priv);
  639. /* Update line-related information */
  640. priv->lineno++;
  641. priv->linesize = len;
  642. priv->offset = 0;
  643. /* Transfer data to the user buffer */
  644. xfrsize = priv->linesize;
  645. if (xfrsize > buflen)
  646. {
  647. xfrsize = buflen;
  648. }
  649. memcpy(buffer, &priv->line[priv->offset], xfrsize);
  650. /* Update pointers, sizes, and offsets */
  651. buffer += xfrsize;
  652. buflen -= xfrsize;
  653. priv->linesize -= xfrsize;
  654. priv->offset += xfrsize;
  655. nreturned += xfrsize;
  656. }
  657. return nreturned;
  658. }
  659. #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS &&
  660. * !CONFIG_FS_PROCFS_EXCLUDE_NET */