net_procfs.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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 *)
  290. kmm_zalloc(sizeof(struct netprocfs_file_s));
  291. if (!newpriv)
  292. {
  293. ferr("ERROR: Failed to allocate file attributes\n");
  294. return -ENOMEM;
  295. }
  296. /* The copy the file attribtes from the old attributes to the new */
  297. memcpy(newpriv, oldpriv, sizeof(struct netprocfs_file_s));
  298. /* Save the new attributes in the new file structure */
  299. newp->f_priv = (FAR void *)newpriv;
  300. return OK;
  301. }
  302. /****************************************************************************
  303. * Name: netprocfs_opendir
  304. *
  305. * Description:
  306. * Open a directory for read access
  307. *
  308. ****************************************************************************/
  309. static int netprocfs_opendir(FAR const char *relpath,
  310. FAR struct fs_dirent_s *dir)
  311. {
  312. FAR struct netprocfs_level1_s *level1;
  313. int ndevs;
  314. int ret;
  315. finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL");
  316. DEBUGASSERT(relpath && dir && !dir->u.procfs);
  317. /* "net" and "net/route" are the only values of relpath that are
  318. * directories.
  319. */
  320. #ifdef CONFIG_NET_ROUTE
  321. if (match("net/route", relpath) || match("net/route/**", relpath))
  322. {
  323. /* Use the /net/route directory */
  324. return net_procfs_routeoperations.opendir(relpath, dir);
  325. }
  326. #endif
  327. /* Assume that path refers to the 1st level subdirectory. Allocate the
  328. * level1 the dirent structure before checking.
  329. */
  330. level1 = (FAR struct netprocfs_level1_s *)
  331. kmm_zalloc(sizeof(struct netprocfs_level1_s));
  332. if (level1 == NULL)
  333. {
  334. ferr("ERROR: Failed to allocate the level1 directory structure\n");
  335. return -ENOMEM;
  336. }
  337. level1->base.level = 1;
  338. if (strcmp(relpath, "net") == 0)
  339. {
  340. /* Count the number of network devices */
  341. ndevs = netdev_count();
  342. /* Initialize base structure components */
  343. level1->base.nentries = ndevs;
  344. #ifdef CONFIG_NET_STATISTICS
  345. level1->base.nentries++;
  346. #ifdef CONFIG_NET_MLD
  347. level1->base.nentries++;
  348. #endif
  349. #endif
  350. #ifdef CONFIG_NET_ROUTE
  351. level1->base.nentries++;
  352. #endif
  353. }
  354. else
  355. {
  356. /* REVISIT: We really need to check if the relpath refers to a network
  357. * device. In that case, we need to return -ENOTDIR. Otherwise, we
  358. * should return -ENOENT.
  359. */
  360. ferr("ERROR: Bad relpath: %s\n", relpath);
  361. ret = -ENOTDIR;
  362. goto errout_with_alloc;
  363. }
  364. dir->u.procfs = (FAR void *)level1;
  365. return OK;
  366. errout_with_alloc:
  367. kmm_free(level1);
  368. return ret;
  369. }
  370. /****************************************************************************
  371. * Name: netprocfs_closedir
  372. *
  373. * Description: Close the directory listing
  374. *
  375. ****************************************************************************/
  376. static int netprocfs_closedir(FAR struct fs_dirent_s *dir)
  377. {
  378. FAR struct netprocfs_level1_s *priv;
  379. DEBUGASSERT(dir && dir->u.procfs);
  380. priv = dir->u.procfs;
  381. if (priv)
  382. {
  383. kmm_free(priv);
  384. }
  385. dir->u.procfs = NULL;
  386. return OK;
  387. }
  388. /****************************************************************************
  389. * Name: netprocfs_readdir
  390. *
  391. * Description: Read the next directory entry
  392. *
  393. ****************************************************************************/
  394. static int netprocfs_readdir(FAR struct fs_dirent_s *dir)
  395. {
  396. FAR struct netprocfs_level1_s *level1;
  397. FAR struct net_driver_s *dev;
  398. int index;
  399. int ret;
  400. DEBUGASSERT(dir && dir->u.procfs);
  401. level1 = dir->u.procfs;
  402. DEBUGASSERT(level1->base.level > 0);
  403. /* Are we searching this directory? Or is it just an intermediate on the
  404. * way to a sub-directory?
  405. */
  406. if (level1->base.level == 1)
  407. {
  408. /* This directory.. Have we reached the end of the directory? */
  409. index = level1->base.index;
  410. DEBUGASSERT(index <= level1->base.nentries);
  411. if (index >= level1->base.nentries)
  412. {
  413. /* We signal the end of the directory by returning the special
  414. * error -ENOENT.
  415. */
  416. finfo("Entry %d: End of directory\n", index);
  417. return -ENOENT;
  418. }
  419. #ifdef CONFIG_NET_STATISTICS
  420. if (index == STAT_INDEX)
  421. {
  422. /* Copy the network statistics directory entry */
  423. dir->fd_dir.d_type = DTYPE_FILE;
  424. strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1);
  425. }
  426. else
  427. #ifdef CONFIG_NET_MLD
  428. if (index == MLD_INDEX)
  429. {
  430. /* Copy the MLD directory entry */
  431. dir->fd_dir.d_type = DTYPE_FILE;
  432. strncpy(dir->fd_dir.d_name, "mld", NAME_MAX + 1);
  433. }
  434. else
  435. #endif
  436. #endif
  437. #ifdef CONFIG_NET_ROUTE
  438. if (index == ROUTE_INDEX)
  439. {
  440. /* Copy the network statistics directory entry */
  441. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  442. strncpy(dir->fd_dir.d_name, "route", NAME_MAX + 1);
  443. }
  444. else
  445. #endif
  446. {
  447. int ifindex;
  448. #ifdef CONFIG_NETDEV_IFINDEX
  449. /* For the first network device, ifindex will be zero. We have
  450. * to take some special action to get the correct starting
  451. * ifindex.
  452. */
  453. if (level1->ifindex == 0)
  454. {
  455. ifindex = netdev_nextindex(1);
  456. }
  457. else
  458. {
  459. ifindex = netdev_nextindex(level1->ifindex);
  460. }
  461. if (ifindex < 0)
  462. {
  463. /* There are no more... one must have been unregistered */
  464. return -ENOENT;
  465. }
  466. level1->ifindex = ifindex + 1;
  467. #else
  468. /* Get the raw index, accounting for 1 based indexing */
  469. ifindex = index - DEV_INDEX + 1;
  470. #endif
  471. /* Find the device corresponding to this device index */
  472. dev = netdev_findbyindex(ifindex);
  473. if (dev == NULL)
  474. {
  475. /* What happened? */
  476. return -ENOENT;
  477. }
  478. /* Copy the device statistics file entry */
  479. dir->fd_dir.d_type = DTYPE_FILE;
  480. strncpy(dir->fd_dir.d_name, dev->d_ifname, NAME_MAX + 1);
  481. }
  482. /* Set up the next directory entry offset. NOTE that we could use the
  483. * standard f_pos instead of our own private index.
  484. */
  485. level1->base.index = index + 1;
  486. ret = OK;
  487. }
  488. else
  489. {
  490. /* We are performing a directory search of one of the subdirectories
  491. * and we must let the handler perform the read.
  492. */
  493. DEBUGASSERT(level1->base.procfsentry != NULL &&
  494. level1->base.procfsentry->ops->readdir != NULL);
  495. ret = level1->base.procfsentry->ops->readdir(dir);
  496. }
  497. return ret;
  498. }
  499. /****************************************************************************
  500. * Name: netprocfs_rewindir
  501. *
  502. * Description: Reset directory read to the first entry
  503. *
  504. ****************************************************************************/
  505. static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir)
  506. {
  507. FAR struct netprocfs_level1_s *priv;
  508. DEBUGASSERT(dir && dir->u.procfs);
  509. priv = dir->u.procfs;
  510. priv->base.index = 0;
  511. return OK;
  512. }
  513. /****************************************************************************
  514. * Name: netprocfs_stat
  515. *
  516. * Description: Return information about a file or directory
  517. *
  518. ****************************************************************************/
  519. static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf)
  520. {
  521. /* Check for the directory "net" */
  522. if (strcmp(relpath, "net") == 0)
  523. {
  524. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  525. }
  526. else
  527. #ifdef CONFIG_NET_STATISTICS
  528. /* Check for network statistics "net/stat" */
  529. if (strcmp(relpath, "net/stat") == 0)
  530. {
  531. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  532. }
  533. else
  534. #ifdef CONFIG_NET_MLD
  535. /* Check for MLD statistics "net/mld" */
  536. if (strcmp(relpath, "net/mld") == 0)
  537. {
  538. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  539. }
  540. else
  541. #endif
  542. #endif
  543. #ifdef CONFIG_NET_ROUTE
  544. /* Check for network statistics "net/stat" */
  545. if (strcmp(relpath, "net/route") == 0)
  546. {
  547. buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
  548. }
  549. else
  550. #endif
  551. {
  552. FAR struct net_driver_s *dev;
  553. FAR char *devname;
  554. FAR char *copy;
  555. /* Otherwise, we need to search the list of registered network devices
  556. * to determine if the name corresponds to a network device.
  557. */
  558. copy = strdup(relpath);
  559. if (copy == NULL)
  560. {
  561. ferr("ERROR: strdup failed\n");
  562. return -ENOMEM;
  563. }
  564. devname = basename(copy);
  565. dev = netdev_findbyname(devname);
  566. kmm_free(copy);
  567. if (dev == NULL)
  568. {
  569. ferr("ERROR: relpath is '%s'\n", relpath);
  570. return -ENOENT;
  571. }
  572. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  573. }
  574. /* File/directory size, access block size */
  575. buf->st_size = 0;
  576. buf->st_blksize = 0;
  577. buf->st_blocks = 0;
  578. return OK;
  579. }
  580. /****************************************************************************
  581. * Public Functions
  582. ****************************************************************************/
  583. /****************************************************************************
  584. * Name: netprocfs_read_linegen
  585. *
  586. * Description:
  587. * Read and format procfs data using a line generation table.
  588. *
  589. * Input Parameters:
  590. * priv - A reference to the network procfs file structure
  591. * buffer - The user-provided buffer into which device status will be
  592. * returned.
  593. * buflen - The size in bytes of the user provided buffer.
  594. * gentab - Table of line generation functions
  595. * nelems - The number of elements in the table
  596. *
  597. * Returned Value:
  598. * Zero (OK) is returned on success; a negated errno value is returned
  599. * on failure.
  600. *
  601. ****************************************************************************/
  602. ssize_t netprocfs_read_linegen(FAR struct netprocfs_file_s *priv,
  603. FAR char *buffer, size_t buflen,
  604. FAR const linegen_t *gentab, int nelems)
  605. {
  606. size_t xfrsize;
  607. ssize_t nreturned;
  608. finfo("buffer=%p buflen=%lu\n", buffer, (unsigned long)buflen);
  609. /* Is there line data already buffered? */
  610. nreturned = 0;
  611. if (priv->linesize > 0)
  612. {
  613. /* Yes, how much can we transfer now? */
  614. xfrsize = priv->linesize;
  615. if (xfrsize > buflen)
  616. {
  617. xfrsize = buflen;
  618. }
  619. /* Transfer the data to the user buffer */
  620. memcpy(buffer, &priv->line[priv->offset], xfrsize);
  621. /* Update pointers, sizes, and offsets */
  622. buffer += xfrsize;
  623. buflen -= xfrsize;
  624. priv->linesize -= xfrsize;
  625. priv->offset += xfrsize;
  626. nreturned = xfrsize;
  627. }
  628. /* Loop until the user buffer is full or until all of the network
  629. * statistics have been transferred. At this point we know that
  630. * either:
  631. *
  632. * 1. The user buffer is full, and/or
  633. * 2. All of the current line data has been transferred.
  634. */
  635. while (buflen > 0 && priv->lineno < nelems)
  636. {
  637. int len;
  638. /* Read the next line into the working buffer */
  639. len = gentab[priv->lineno](priv);
  640. /* Update line-related information */
  641. priv->lineno++;
  642. priv->linesize = len;
  643. priv->offset = 0;
  644. /* Transfer data to the user buffer */
  645. xfrsize = priv->linesize;
  646. if (xfrsize > buflen)
  647. {
  648. xfrsize = buflen;
  649. }
  650. memcpy(buffer, &priv->line[priv->offset], xfrsize);
  651. /* Update pointers, sizes, and offsets */
  652. buffer += xfrsize;
  653. buflen -= xfrsize;
  654. priv->linesize -= xfrsize;
  655. priv->offset += xfrsize;
  656. nreturned += xfrsize;
  657. }
  658. return nreturned;
  659. }
  660. #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS &&
  661. * !CONFIG_FS_PROCFS_EXCLUDE_NET */