print-nfs.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715
  1. /*
  2. * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that: (1) source code distributions
  7. * retain the above copyright notice and this paragraph in its entirety, (2)
  8. * distributions including binary code include the above copyright notice and
  9. * this paragraph in its entirety in the documentation or other materials
  10. * provided with the distribution, and (3) all advertising materials mentioning
  11. * features or use of this software display the following acknowledgement:
  12. * ``This product includes software developed by the University of California,
  13. * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14. * the University nor the names of its contributors may be used to endorse
  15. * or promote products derived from this software without specific prior
  16. * written permission.
  17. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20. */
  21. /* \summary: Network File System (NFS) printer */
  22. #ifdef HAVE_CONFIG_H
  23. #include "config.h"
  24. #endif
  25. #include <netdissect-stdinc.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include "netdissect.h"
  29. #include "addrtoname.h"
  30. #include "extract.h"
  31. #include "nfs.h"
  32. #include "nfsfh.h"
  33. #include "ip.h"
  34. #include "ip6.h"
  35. #include "rpc_auth.h"
  36. #include "rpc_msg.h"
  37. static const char tstr[] = " [|nfs]";
  38. static void nfs_printfh(netdissect_options *, const uint32_t *, const u_int);
  39. static int xid_map_enter(netdissect_options *, const struct sunrpc_msg *, const u_char *);
  40. static int xid_map_find(const struct sunrpc_msg *, const u_char *,
  41. uint32_t *, uint32_t *);
  42. static void interp_reply(netdissect_options *, const struct sunrpc_msg *, uint32_t, uint32_t, int);
  43. static const uint32_t *parse_post_op_attr(netdissect_options *, const uint32_t *, int);
  44. /*
  45. * Mapping of old NFS Version 2 RPC numbers to generic numbers.
  46. */
  47. static uint32_t nfsv3_procid[NFS_NPROCS] = {
  48. NFSPROC_NULL,
  49. NFSPROC_GETATTR,
  50. NFSPROC_SETATTR,
  51. NFSPROC_NOOP,
  52. NFSPROC_LOOKUP,
  53. NFSPROC_READLINK,
  54. NFSPROC_READ,
  55. NFSPROC_NOOP,
  56. NFSPROC_WRITE,
  57. NFSPROC_CREATE,
  58. NFSPROC_REMOVE,
  59. NFSPROC_RENAME,
  60. NFSPROC_LINK,
  61. NFSPROC_SYMLINK,
  62. NFSPROC_MKDIR,
  63. NFSPROC_RMDIR,
  64. NFSPROC_READDIR,
  65. NFSPROC_FSSTAT,
  66. NFSPROC_NOOP,
  67. NFSPROC_NOOP,
  68. NFSPROC_NOOP,
  69. NFSPROC_NOOP,
  70. NFSPROC_NOOP,
  71. NFSPROC_NOOP,
  72. NFSPROC_NOOP,
  73. NFSPROC_NOOP
  74. };
  75. static const struct tok nfsproc_str[] = {
  76. { NFSPROC_NOOP, "nop" },
  77. { NFSPROC_NULL, "null" },
  78. { NFSPROC_GETATTR, "getattr" },
  79. { NFSPROC_SETATTR, "setattr" },
  80. { NFSPROC_LOOKUP, "lookup" },
  81. { NFSPROC_ACCESS, "access" },
  82. { NFSPROC_READLINK, "readlink" },
  83. { NFSPROC_READ, "read" },
  84. { NFSPROC_WRITE, "write" },
  85. { NFSPROC_CREATE, "create" },
  86. { NFSPROC_MKDIR, "mkdir" },
  87. { NFSPROC_SYMLINK, "symlink" },
  88. { NFSPROC_MKNOD, "mknod" },
  89. { NFSPROC_REMOVE, "remove" },
  90. { NFSPROC_RMDIR, "rmdir" },
  91. { NFSPROC_RENAME, "rename" },
  92. { NFSPROC_LINK, "link" },
  93. { NFSPROC_READDIR, "readdir" },
  94. { NFSPROC_READDIRPLUS, "readdirplus" },
  95. { NFSPROC_FSSTAT, "fsstat" },
  96. { NFSPROC_FSINFO, "fsinfo" },
  97. { NFSPROC_PATHCONF, "pathconf" },
  98. { NFSPROC_COMMIT, "commit" },
  99. { 0, NULL }
  100. };
  101. /*
  102. * NFS V2 and V3 status values.
  103. *
  104. * Some of these come from the RFCs for NFS V2 and V3, with the message
  105. * strings taken from the FreeBSD C library "errlst.c".
  106. *
  107. * Others are errors that are not in the RFC but that I suspect some
  108. * NFS servers could return; the values are FreeBSD errno values, as
  109. * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
  110. * was primarily BSD-derived.
  111. */
  112. static const struct tok status2str[] = {
  113. { 1, "Operation not permitted" }, /* EPERM */
  114. { 2, "No such file or directory" }, /* ENOENT */
  115. { 5, "Input/output error" }, /* EIO */
  116. { 6, "Device not configured" }, /* ENXIO */
  117. { 11, "Resource deadlock avoided" }, /* EDEADLK */
  118. { 12, "Cannot allocate memory" }, /* ENOMEM */
  119. { 13, "Permission denied" }, /* EACCES */
  120. { 17, "File exists" }, /* EEXIST */
  121. { 18, "Cross-device link" }, /* EXDEV */
  122. { 19, "Operation not supported by device" }, /* ENODEV */
  123. { 20, "Not a directory" }, /* ENOTDIR */
  124. { 21, "Is a directory" }, /* EISDIR */
  125. { 22, "Invalid argument" }, /* EINVAL */
  126. { 26, "Text file busy" }, /* ETXTBSY */
  127. { 27, "File too large" }, /* EFBIG */
  128. { 28, "No space left on device" }, /* ENOSPC */
  129. { 30, "Read-only file system" }, /* EROFS */
  130. { 31, "Too many links" }, /* EMLINK */
  131. { 45, "Operation not supported" }, /* EOPNOTSUPP */
  132. { 62, "Too many levels of symbolic links" }, /* ELOOP */
  133. { 63, "File name too long" }, /* ENAMETOOLONG */
  134. { 66, "Directory not empty" }, /* ENOTEMPTY */
  135. { 69, "Disc quota exceeded" }, /* EDQUOT */
  136. { 70, "Stale NFS file handle" }, /* ESTALE */
  137. { 71, "Too many levels of remote in path" }, /* EREMOTE */
  138. { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
  139. { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */
  140. { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
  141. { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
  142. { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */
  143. { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
  144. { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
  145. { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
  146. { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
  147. { 0, NULL }
  148. };
  149. static const struct tok nfsv3_writemodes[] = {
  150. { 0, "unstable" },
  151. { 1, "datasync" },
  152. { 2, "filesync" },
  153. { 0, NULL }
  154. };
  155. static const struct tok type2str[] = {
  156. { NFNON, "NON" },
  157. { NFREG, "REG" },
  158. { NFDIR, "DIR" },
  159. { NFBLK, "BLK" },
  160. { NFCHR, "CHR" },
  161. { NFLNK, "LNK" },
  162. { NFFIFO, "FIFO" },
  163. { 0, NULL }
  164. };
  165. static const struct tok sunrpc_auth_str[] = {
  166. { SUNRPC_AUTH_OK, "OK" },
  167. { SUNRPC_AUTH_BADCRED, "Bogus Credentials (seal broken)" },
  168. { SUNRPC_AUTH_REJECTEDCRED, "Rejected Credentials (client should begin new session)" },
  169. { SUNRPC_AUTH_BADVERF, "Bogus Verifier (seal broken)" },
  170. { SUNRPC_AUTH_REJECTEDVERF, "Verifier expired or was replayed" },
  171. { SUNRPC_AUTH_TOOWEAK, "Credentials are too weak" },
  172. { SUNRPC_AUTH_INVALIDRESP, "Bogus response verifier" },
  173. { SUNRPC_AUTH_FAILED, "Unknown failure" },
  174. { 0, NULL }
  175. };
  176. static const struct tok sunrpc_str[] = {
  177. { SUNRPC_PROG_UNAVAIL, "PROG_UNAVAIL" },
  178. { SUNRPC_PROG_MISMATCH, "PROG_MISMATCH" },
  179. { SUNRPC_PROC_UNAVAIL, "PROC_UNAVAIL" },
  180. { SUNRPC_GARBAGE_ARGS, "GARBAGE_ARGS" },
  181. { SUNRPC_SYSTEM_ERR, "SYSTEM_ERR" },
  182. { 0, NULL }
  183. };
  184. static void
  185. print_nfsaddr(netdissect_options *ndo,
  186. const u_char *bp, const char *s, const char *d)
  187. {
  188. const struct ip *ip;
  189. const struct ip6_hdr *ip6;
  190. char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
  191. srcaddr[0] = dstaddr[0] = '\0';
  192. switch (IP_V((const struct ip *)bp)) {
  193. case 4:
  194. ip = (const struct ip *)bp;
  195. strlcpy(srcaddr, ipaddr_string(ndo, &ip->ip_src), sizeof(srcaddr));
  196. strlcpy(dstaddr, ipaddr_string(ndo, &ip->ip_dst), sizeof(dstaddr));
  197. break;
  198. case 6:
  199. ip6 = (const struct ip6_hdr *)bp;
  200. strlcpy(srcaddr, ip6addr_string(ndo, &ip6->ip6_src),
  201. sizeof(srcaddr));
  202. strlcpy(dstaddr, ip6addr_string(ndo, &ip6->ip6_dst),
  203. sizeof(dstaddr));
  204. break;
  205. default:
  206. strlcpy(srcaddr, "?", sizeof(srcaddr));
  207. strlcpy(dstaddr, "?", sizeof(dstaddr));
  208. break;
  209. }
  210. ND_PRINT((ndo, "%s.%s > %s.%s: ", srcaddr, s, dstaddr, d));
  211. }
  212. static const uint32_t *
  213. parse_sattr3(netdissect_options *ndo,
  214. const uint32_t *dp, struct nfsv3_sattr *sa3)
  215. {
  216. ND_TCHECK(dp[0]);
  217. sa3->sa_modeset = EXTRACT_32BITS(dp);
  218. dp++;
  219. if (sa3->sa_modeset) {
  220. ND_TCHECK(dp[0]);
  221. sa3->sa_mode = EXTRACT_32BITS(dp);
  222. dp++;
  223. }
  224. ND_TCHECK(dp[0]);
  225. sa3->sa_uidset = EXTRACT_32BITS(dp);
  226. dp++;
  227. if (sa3->sa_uidset) {
  228. ND_TCHECK(dp[0]);
  229. sa3->sa_uid = EXTRACT_32BITS(dp);
  230. dp++;
  231. }
  232. ND_TCHECK(dp[0]);
  233. sa3->sa_gidset = EXTRACT_32BITS(dp);
  234. dp++;
  235. if (sa3->sa_gidset) {
  236. ND_TCHECK(dp[0]);
  237. sa3->sa_gid = EXTRACT_32BITS(dp);
  238. dp++;
  239. }
  240. ND_TCHECK(dp[0]);
  241. sa3->sa_sizeset = EXTRACT_32BITS(dp);
  242. dp++;
  243. if (sa3->sa_sizeset) {
  244. ND_TCHECK(dp[0]);
  245. sa3->sa_size = EXTRACT_32BITS(dp);
  246. dp++;
  247. }
  248. ND_TCHECK(dp[0]);
  249. sa3->sa_atimetype = EXTRACT_32BITS(dp);
  250. dp++;
  251. if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
  252. ND_TCHECK(dp[1]);
  253. sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
  254. dp++;
  255. sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
  256. dp++;
  257. }
  258. ND_TCHECK(dp[0]);
  259. sa3->sa_mtimetype = EXTRACT_32BITS(dp);
  260. dp++;
  261. if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
  262. ND_TCHECK(dp[1]);
  263. sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
  264. dp++;
  265. sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
  266. dp++;
  267. }
  268. return dp;
  269. trunc:
  270. return NULL;
  271. }
  272. static int nfserr; /* true if we error rather than trunc */
  273. static void
  274. print_sattr3(netdissect_options *ndo,
  275. const struct nfsv3_sattr *sa3, int verbose)
  276. {
  277. if (sa3->sa_modeset)
  278. ND_PRINT((ndo, " mode %o", sa3->sa_mode));
  279. if (sa3->sa_uidset)
  280. ND_PRINT((ndo, " uid %u", sa3->sa_uid));
  281. if (sa3->sa_gidset)
  282. ND_PRINT((ndo, " gid %u", sa3->sa_gid));
  283. if (verbose > 1) {
  284. if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
  285. ND_PRINT((ndo, " atime %u.%06u", sa3->sa_atime.nfsv3_sec,
  286. sa3->sa_atime.nfsv3_nsec));
  287. if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
  288. ND_PRINT((ndo, " mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
  289. sa3->sa_mtime.nfsv3_nsec));
  290. }
  291. }
  292. void
  293. nfsreply_print(netdissect_options *ndo,
  294. register const u_char *bp, u_int length,
  295. register const u_char *bp2)
  296. {
  297. register const struct sunrpc_msg *rp;
  298. char srcid[20], dstid[20]; /*fits 32bit*/
  299. nfserr = 0; /* assume no error */
  300. rp = (const struct sunrpc_msg *)bp;
  301. ND_TCHECK(rp->rm_xid);
  302. if (!ndo->ndo_nflag) {
  303. strlcpy(srcid, "nfs", sizeof(srcid));
  304. snprintf(dstid, sizeof(dstid), "%u",
  305. EXTRACT_32BITS(&rp->rm_xid));
  306. } else {
  307. snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
  308. snprintf(dstid, sizeof(dstid), "%u",
  309. EXTRACT_32BITS(&rp->rm_xid));
  310. }
  311. print_nfsaddr(ndo, bp2, srcid, dstid);
  312. nfsreply_print_noaddr(ndo, bp, length, bp2);
  313. return;
  314. trunc:
  315. if (!nfserr)
  316. ND_PRINT((ndo, "%s", tstr));
  317. }
  318. void
  319. nfsreply_print_noaddr(netdissect_options *ndo,
  320. register const u_char *bp, u_int length,
  321. register const u_char *bp2)
  322. {
  323. register const struct sunrpc_msg *rp;
  324. uint32_t proc, vers, reply_stat;
  325. enum sunrpc_reject_stat rstat;
  326. uint32_t rlow;
  327. uint32_t rhigh;
  328. enum sunrpc_auth_stat rwhy;
  329. nfserr = 0; /* assume no error */
  330. rp = (const struct sunrpc_msg *)bp;
  331. ND_TCHECK(rp->rm_reply.rp_stat);
  332. reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
  333. switch (reply_stat) {
  334. case SUNRPC_MSG_ACCEPTED:
  335. ND_PRINT((ndo, "reply ok %u", length));
  336. if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
  337. interp_reply(ndo, rp, proc, vers, length);
  338. break;
  339. case SUNRPC_MSG_DENIED:
  340. ND_PRINT((ndo, "reply ERR %u: ", length));
  341. ND_TCHECK(rp->rm_reply.rp_reject.rj_stat);
  342. rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
  343. switch (rstat) {
  344. case SUNRPC_RPC_MISMATCH:
  345. ND_TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
  346. rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
  347. rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
  348. ND_PRINT((ndo, "RPC Version mismatch (%u-%u)", rlow, rhigh));
  349. break;
  350. case SUNRPC_AUTH_ERROR:
  351. ND_TCHECK(rp->rm_reply.rp_reject.rj_why);
  352. rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
  353. ND_PRINT((ndo, "Auth %s", tok2str(sunrpc_auth_str, "Invalid failure code %u", rwhy)));
  354. break;
  355. default:
  356. ND_PRINT((ndo, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat));
  357. break;
  358. }
  359. break;
  360. default:
  361. ND_PRINT((ndo, "reply Unknown rpc response code=%u %u", reply_stat, length));
  362. break;
  363. }
  364. return;
  365. trunc:
  366. if (!nfserr)
  367. ND_PRINT((ndo, "%s", tstr));
  368. }
  369. /*
  370. * Return a pointer to the first file handle in the packet.
  371. * If the packet was truncated, return 0.
  372. */
  373. static const uint32_t *
  374. parsereq(netdissect_options *ndo,
  375. register const struct sunrpc_msg *rp, register u_int length)
  376. {
  377. register const uint32_t *dp;
  378. register u_int len;
  379. /*
  380. * find the start of the req data (if we captured it)
  381. */
  382. dp = (const uint32_t *)&rp->rm_call.cb_cred;
  383. ND_TCHECK(dp[1]);
  384. len = EXTRACT_32BITS(&dp[1]);
  385. if (len < length) {
  386. dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
  387. ND_TCHECK(dp[1]);
  388. len = EXTRACT_32BITS(&dp[1]);
  389. if (len < length) {
  390. dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
  391. ND_TCHECK2(dp[0], 0);
  392. return (dp);
  393. }
  394. }
  395. trunc:
  396. return (NULL);
  397. }
  398. /*
  399. * Print out an NFS file handle and return a pointer to following word.
  400. * If packet was truncated, return 0.
  401. */
  402. static const uint32_t *
  403. parsefh(netdissect_options *ndo,
  404. register const uint32_t *dp, int v3)
  405. {
  406. u_int len;
  407. if (v3) {
  408. ND_TCHECK(dp[0]);
  409. len = EXTRACT_32BITS(dp) / 4;
  410. dp++;
  411. } else
  412. len = NFSX_V2FH / 4;
  413. if (ND_TTEST2(*dp, len * sizeof(*dp))) {
  414. nfs_printfh(ndo, dp, len);
  415. return (dp + len);
  416. }
  417. trunc:
  418. return (NULL);
  419. }
  420. /*
  421. * Print out a file name and return pointer to 32-bit word past it.
  422. * If packet was truncated, return 0.
  423. */
  424. static const uint32_t *
  425. parsefn(netdissect_options *ndo,
  426. register const uint32_t *dp)
  427. {
  428. register uint32_t len;
  429. register const u_char *cp;
  430. /* Bail if we don't have the string length */
  431. ND_TCHECK(*dp);
  432. /* Fetch string length; convert to host order */
  433. len = *dp++;
  434. NTOHL(len);
  435. ND_TCHECK2(*dp, ((len + 3) & ~3));
  436. cp = (const u_char *)dp;
  437. /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
  438. dp += ((len + 3) & ~3) / sizeof(*dp);
  439. ND_PRINT((ndo, "\""));
  440. if (fn_printn(ndo, cp, len, ndo->ndo_snapend)) {
  441. ND_PRINT((ndo, "\""));
  442. goto trunc;
  443. }
  444. ND_PRINT((ndo, "\""));
  445. return (dp);
  446. trunc:
  447. return NULL;
  448. }
  449. /*
  450. * Print out file handle and file name.
  451. * Return pointer to 32-bit word past file name.
  452. * If packet was truncated (or there was some other error), return 0.
  453. */
  454. static const uint32_t *
  455. parsefhn(netdissect_options *ndo,
  456. register const uint32_t *dp, int v3)
  457. {
  458. dp = parsefh(ndo, dp, v3);
  459. if (dp == NULL)
  460. return (NULL);
  461. ND_PRINT((ndo, " "));
  462. return (parsefn(ndo, dp));
  463. }
  464. void
  465. nfsreq_print_noaddr(netdissect_options *ndo,
  466. register const u_char *bp, u_int length,
  467. register const u_char *bp2)
  468. {
  469. register const struct sunrpc_msg *rp;
  470. register const uint32_t *dp;
  471. nfs_type type;
  472. int v3;
  473. uint32_t proc;
  474. uint32_t access_flags;
  475. struct nfsv3_sattr sa3;
  476. ND_PRINT((ndo, "%d", length));
  477. nfserr = 0; /* assume no error */
  478. rp = (const struct sunrpc_msg *)bp;
  479. if (!xid_map_enter(ndo, rp, bp2)) /* record proc number for later on */
  480. goto trunc;
  481. v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
  482. proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
  483. if (!v3 && proc < NFS_NPROCS)
  484. proc = nfsv3_procid[proc];
  485. ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
  486. switch (proc) {
  487. case NFSPROC_GETATTR:
  488. case NFSPROC_SETATTR:
  489. case NFSPROC_READLINK:
  490. case NFSPROC_FSSTAT:
  491. case NFSPROC_FSINFO:
  492. case NFSPROC_PATHCONF:
  493. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  494. parsefh(ndo, dp, v3) != NULL)
  495. return;
  496. break;
  497. case NFSPROC_LOOKUP:
  498. case NFSPROC_CREATE:
  499. case NFSPROC_MKDIR:
  500. case NFSPROC_REMOVE:
  501. case NFSPROC_RMDIR:
  502. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  503. parsefhn(ndo, dp, v3) != NULL)
  504. return;
  505. break;
  506. case NFSPROC_ACCESS:
  507. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  508. (dp = parsefh(ndo, dp, v3)) != NULL) {
  509. ND_TCHECK(dp[0]);
  510. access_flags = EXTRACT_32BITS(&dp[0]);
  511. if (access_flags & ~NFSV3ACCESS_FULL) {
  512. /* NFSV3ACCESS definitions aren't up to date */
  513. ND_PRINT((ndo, " %04x", access_flags));
  514. } else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) {
  515. ND_PRINT((ndo, " NFS_ACCESS_FULL"));
  516. } else {
  517. char separator = ' ';
  518. if (access_flags & NFSV3ACCESS_READ) {
  519. ND_PRINT((ndo, " NFS_ACCESS_READ"));
  520. separator = '|';
  521. }
  522. if (access_flags & NFSV3ACCESS_LOOKUP) {
  523. ND_PRINT((ndo, "%cNFS_ACCESS_LOOKUP", separator));
  524. separator = '|';
  525. }
  526. if (access_flags & NFSV3ACCESS_MODIFY) {
  527. ND_PRINT((ndo, "%cNFS_ACCESS_MODIFY", separator));
  528. separator = '|';
  529. }
  530. if (access_flags & NFSV3ACCESS_EXTEND) {
  531. ND_PRINT((ndo, "%cNFS_ACCESS_EXTEND", separator));
  532. separator = '|';
  533. }
  534. if (access_flags & NFSV3ACCESS_DELETE) {
  535. ND_PRINT((ndo, "%cNFS_ACCESS_DELETE", separator));
  536. separator = '|';
  537. }
  538. if (access_flags & NFSV3ACCESS_EXECUTE)
  539. ND_PRINT((ndo, "%cNFS_ACCESS_EXECUTE", separator));
  540. }
  541. return;
  542. }
  543. break;
  544. case NFSPROC_READ:
  545. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  546. (dp = parsefh(ndo, dp, v3)) != NULL) {
  547. if (v3) {
  548. ND_TCHECK(dp[2]);
  549. ND_PRINT((ndo, " %u bytes @ %" PRIu64,
  550. EXTRACT_32BITS(&dp[2]),
  551. EXTRACT_64BITS(&dp[0])));
  552. } else {
  553. ND_TCHECK(dp[1]);
  554. ND_PRINT((ndo, " %u bytes @ %u",
  555. EXTRACT_32BITS(&dp[1]),
  556. EXTRACT_32BITS(&dp[0])));
  557. }
  558. return;
  559. }
  560. break;
  561. case NFSPROC_WRITE:
  562. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  563. (dp = parsefh(ndo, dp, v3)) != NULL) {
  564. if (v3) {
  565. ND_TCHECK(dp[4]);
  566. ND_PRINT((ndo, " %u (%u) bytes @ %" PRIu64,
  567. EXTRACT_32BITS(&dp[4]),
  568. EXTRACT_32BITS(&dp[2]),
  569. EXTRACT_64BITS(&dp[0])));
  570. if (ndo->ndo_vflag) {
  571. ND_PRINT((ndo, " <%s>",
  572. tok2str(nfsv3_writemodes,
  573. NULL, EXTRACT_32BITS(&dp[3]))));
  574. }
  575. } else {
  576. ND_TCHECK(dp[3]);
  577. ND_PRINT((ndo, " %u (%u) bytes @ %u (%u)",
  578. EXTRACT_32BITS(&dp[3]),
  579. EXTRACT_32BITS(&dp[2]),
  580. EXTRACT_32BITS(&dp[1]),
  581. EXTRACT_32BITS(&dp[0])));
  582. }
  583. return;
  584. }
  585. break;
  586. case NFSPROC_SYMLINK:
  587. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  588. (dp = parsefhn(ndo, dp, v3)) != NULL) {
  589. ND_PRINT((ndo, " ->"));
  590. if (v3 && (dp = parse_sattr3(ndo, dp, &sa3)) == NULL)
  591. break;
  592. if (parsefn(ndo, dp) == NULL)
  593. break;
  594. if (v3 && ndo->ndo_vflag)
  595. print_sattr3(ndo, &sa3, ndo->ndo_vflag);
  596. return;
  597. }
  598. break;
  599. case NFSPROC_MKNOD:
  600. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  601. (dp = parsefhn(ndo, dp, v3)) != NULL) {
  602. ND_TCHECK(*dp);
  603. type = (nfs_type)EXTRACT_32BITS(dp);
  604. dp++;
  605. if ((dp = parse_sattr3(ndo, dp, &sa3)) == NULL)
  606. break;
  607. ND_PRINT((ndo, " %s", tok2str(type2str, "unk-ft %d", type)));
  608. if (ndo->ndo_vflag && (type == NFCHR || type == NFBLK)) {
  609. ND_TCHECK(dp[1]);
  610. ND_PRINT((ndo, " %u/%u",
  611. EXTRACT_32BITS(&dp[0]),
  612. EXTRACT_32BITS(&dp[1])));
  613. dp += 2;
  614. }
  615. if (ndo->ndo_vflag)
  616. print_sattr3(ndo, &sa3, ndo->ndo_vflag);
  617. return;
  618. }
  619. break;
  620. case NFSPROC_RENAME:
  621. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  622. (dp = parsefhn(ndo, dp, v3)) != NULL) {
  623. ND_PRINT((ndo, " ->"));
  624. if (parsefhn(ndo, dp, v3) != NULL)
  625. return;
  626. }
  627. break;
  628. case NFSPROC_LINK:
  629. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  630. (dp = parsefh(ndo, dp, v3)) != NULL) {
  631. ND_PRINT((ndo, " ->"));
  632. if (parsefhn(ndo, dp, v3) != NULL)
  633. return;
  634. }
  635. break;
  636. case NFSPROC_READDIR:
  637. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  638. (dp = parsefh(ndo, dp, v3)) != NULL) {
  639. if (v3) {
  640. ND_TCHECK(dp[4]);
  641. /*
  642. * We shouldn't really try to interpret the
  643. * offset cookie here.
  644. */
  645. ND_PRINT((ndo, " %u bytes @ %" PRId64,
  646. EXTRACT_32BITS(&dp[4]),
  647. EXTRACT_64BITS(&dp[0])));
  648. if (ndo->ndo_vflag)
  649. ND_PRINT((ndo, " verf %08x%08x", dp[2], dp[3]));
  650. } else {
  651. ND_TCHECK(dp[1]);
  652. /*
  653. * Print the offset as signed, since -1 is
  654. * common, but offsets > 2^31 aren't.
  655. */
  656. ND_PRINT((ndo, " %u bytes @ %d",
  657. EXTRACT_32BITS(&dp[1]),
  658. EXTRACT_32BITS(&dp[0])));
  659. }
  660. return;
  661. }
  662. break;
  663. case NFSPROC_READDIRPLUS:
  664. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  665. (dp = parsefh(ndo, dp, v3)) != NULL) {
  666. ND_TCHECK(dp[4]);
  667. /*
  668. * We don't try to interpret the offset
  669. * cookie here.
  670. */
  671. ND_PRINT((ndo, " %u bytes @ %" PRId64,
  672. EXTRACT_32BITS(&dp[4]),
  673. EXTRACT_64BITS(&dp[0])));
  674. if (ndo->ndo_vflag) {
  675. ND_TCHECK(dp[5]);
  676. ND_PRINT((ndo, " max %u verf %08x%08x",
  677. EXTRACT_32BITS(&dp[5]), dp[2], dp[3]));
  678. }
  679. return;
  680. }
  681. break;
  682. case NFSPROC_COMMIT:
  683. if ((dp = parsereq(ndo, rp, length)) != NULL &&
  684. (dp = parsefh(ndo, dp, v3)) != NULL) {
  685. ND_TCHECK(dp[2]);
  686. ND_PRINT((ndo, " %u bytes @ %" PRIu64,
  687. EXTRACT_32BITS(&dp[2]),
  688. EXTRACT_64BITS(&dp[0])));
  689. return;
  690. }
  691. break;
  692. default:
  693. return;
  694. }
  695. trunc:
  696. if (!nfserr)
  697. ND_PRINT((ndo, "%s", tstr));
  698. }
  699. /*
  700. * Print out an NFS file handle.
  701. * We assume packet was not truncated before the end of the
  702. * file handle pointed to by dp.
  703. *
  704. * Note: new version (using portable file-handle parser) doesn't produce
  705. * generation number. It probably could be made to do that, with some
  706. * additional hacking on the parser code.
  707. */
  708. static void
  709. nfs_printfh(netdissect_options *ndo,
  710. register const uint32_t *dp, const u_int len)
  711. {
  712. my_fsid fsid;
  713. uint32_t ino;
  714. const char *sfsname = NULL;
  715. char *spacep;
  716. if (ndo->ndo_uflag) {
  717. u_int i;
  718. char const *sep = "";
  719. ND_PRINT((ndo, " fh["));
  720. for (i=0; i<len; i++) {
  721. ND_PRINT((ndo, "%s%x", sep, dp[i]));
  722. sep = ":";
  723. }
  724. ND_PRINT((ndo, "]"));
  725. return;
  726. }
  727. Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
  728. if (sfsname) {
  729. /* file system ID is ASCII, not numeric, for this server OS */
  730. char temp[NFSX_V3FHMAX+1];
  731. u_int stringlen;
  732. /* Make sure string is null-terminated */
  733. stringlen = len;
  734. if (stringlen > NFSX_V3FHMAX)
  735. stringlen = NFSX_V3FHMAX;
  736. strncpy(temp, sfsname, stringlen);
  737. temp[stringlen] = '\0';
  738. /* Remove trailing spaces */
  739. spacep = strchr(temp, ' ');
  740. if (spacep)
  741. *spacep = '\0';
  742. ND_PRINT((ndo, " fh %s/", temp));
  743. } else {
  744. ND_PRINT((ndo, " fh %d,%d/",
  745. fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor));
  746. }
  747. if(fsid.Fsid_dev.Minor == 257)
  748. /* Print the undecoded handle */
  749. ND_PRINT((ndo, "%s", fsid.Opaque_Handle));
  750. else
  751. ND_PRINT((ndo, "%ld", (long) ino));
  752. }
  753. /*
  754. * Maintain a small cache of recent client.XID.server/proc pairs, to allow
  755. * us to match up replies with requests and thus to know how to parse
  756. * the reply.
  757. */
  758. struct xid_map_entry {
  759. uint32_t xid; /* transaction ID (net order) */
  760. int ipver; /* IP version (4 or 6) */
  761. struct in6_addr client; /* client IP address (net order) */
  762. struct in6_addr server; /* server IP address (net order) */
  763. uint32_t proc; /* call proc number (host order) */
  764. uint32_t vers; /* program version (host order) */
  765. };
  766. /*
  767. * Map entries are kept in an array that we manage as a ring;
  768. * new entries are always added at the tail of the ring. Initially,
  769. * all the entries are zero and hence don't match anything.
  770. */
  771. #define XIDMAPSIZE 64
  772. static struct xid_map_entry xid_map[XIDMAPSIZE];
  773. static int xid_map_next = 0;
  774. static int xid_map_hint = 0;
  775. static int
  776. xid_map_enter(netdissect_options *ndo,
  777. const struct sunrpc_msg *rp, const u_char *bp)
  778. {
  779. const struct ip *ip = NULL;
  780. const struct ip6_hdr *ip6 = NULL;
  781. struct xid_map_entry *xmep;
  782. if (!ND_TTEST(rp->rm_call.cb_proc))
  783. return (0);
  784. switch (IP_V((const struct ip *)bp)) {
  785. case 4:
  786. ip = (const struct ip *)bp;
  787. break;
  788. case 6:
  789. ip6 = (const struct ip6_hdr *)bp;
  790. break;
  791. default:
  792. return (1);
  793. }
  794. xmep = &xid_map[xid_map_next];
  795. if (++xid_map_next >= XIDMAPSIZE)
  796. xid_map_next = 0;
  797. UNALIGNED_MEMCPY(&xmep->xid, &rp->rm_xid, sizeof(xmep->xid));
  798. if (ip) {
  799. xmep->ipver = 4;
  800. UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
  801. UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
  802. }
  803. else if (ip6) {
  804. xmep->ipver = 6;
  805. UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
  806. UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
  807. }
  808. xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
  809. xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
  810. return (1);
  811. }
  812. /*
  813. * Returns 0 and puts NFSPROC_xxx in proc return and
  814. * version in vers return, or returns -1 on failure
  815. */
  816. static int
  817. xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, uint32_t *proc,
  818. uint32_t *vers)
  819. {
  820. int i;
  821. struct xid_map_entry *xmep;
  822. uint32_t xid;
  823. const struct ip *ip = (const struct ip *)bp;
  824. const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
  825. int cmp;
  826. UNALIGNED_MEMCPY(&xid, &rp->rm_xid, sizeof(xmep->xid));
  827. /* Start searching from where we last left off */
  828. i = xid_map_hint;
  829. do {
  830. xmep = &xid_map[i];
  831. cmp = 1;
  832. if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
  833. goto nextitem;
  834. switch (xmep->ipver) {
  835. case 4:
  836. if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server,
  837. sizeof(ip->ip_src)) != 0 ||
  838. UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client,
  839. sizeof(ip->ip_dst)) != 0) {
  840. cmp = 0;
  841. }
  842. break;
  843. case 6:
  844. if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server,
  845. sizeof(ip6->ip6_src)) != 0 ||
  846. UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client,
  847. sizeof(ip6->ip6_dst)) != 0) {
  848. cmp = 0;
  849. }
  850. break;
  851. default:
  852. cmp = 0;
  853. break;
  854. }
  855. if (cmp) {
  856. /* match */
  857. xid_map_hint = i;
  858. *proc = xmep->proc;
  859. *vers = xmep->vers;
  860. return 0;
  861. }
  862. nextitem:
  863. if (++i >= XIDMAPSIZE)
  864. i = 0;
  865. } while (i != xid_map_hint);
  866. /* search failed */
  867. return (-1);
  868. }
  869. /*
  870. * Routines for parsing reply packets
  871. */
  872. /*
  873. * Return a pointer to the beginning of the actual results.
  874. * If the packet was truncated, return 0.
  875. */
  876. static const uint32_t *
  877. parserep(netdissect_options *ndo,
  878. register const struct sunrpc_msg *rp, register u_int length)
  879. {
  880. register const uint32_t *dp;
  881. u_int len;
  882. enum sunrpc_accept_stat astat;
  883. /*
  884. * Portability note:
  885. * Here we find the address of the ar_verf credentials.
  886. * Originally, this calculation was
  887. * dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf
  888. * On the wire, the rp_acpt field starts immediately after
  889. * the (32 bit) rp_stat field. However, rp_acpt (which is a
  890. * "struct accepted_reply") contains a "struct opaque_auth",
  891. * whose internal representation contains a pointer, so on a
  892. * 64-bit machine the compiler inserts 32 bits of padding
  893. * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
  894. * the internal representation to parse the on-the-wire
  895. * representation. Instead, we skip past the rp_stat field,
  896. * which is an "enum" and so occupies one 32-bit word.
  897. */
  898. dp = ((const uint32_t *)&rp->rm_reply) + 1;
  899. ND_TCHECK(dp[1]);
  900. len = EXTRACT_32BITS(&dp[1]);
  901. if (len >= length)
  902. return (NULL);
  903. /*
  904. * skip past the ar_verf credentials.
  905. */
  906. dp += (len + (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t);
  907. /*
  908. * now we can check the ar_stat field
  909. */
  910. ND_TCHECK(dp[0]);
  911. astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
  912. if (astat != SUNRPC_SUCCESS) {
  913. ND_PRINT((ndo, " %s", tok2str(sunrpc_str, "ar_stat %d", astat)));
  914. nfserr = 1; /* suppress trunc string */
  915. return (NULL);
  916. }
  917. /* successful return */
  918. ND_TCHECK2(*dp, sizeof(astat));
  919. return ((const uint32_t *) (sizeof(astat) + ((const char *)dp)));
  920. trunc:
  921. return (0);
  922. }
  923. static const uint32_t *
  924. parsestatus(netdissect_options *ndo,
  925. const uint32_t *dp, int *er)
  926. {
  927. int errnum;
  928. ND_TCHECK(dp[0]);
  929. errnum = EXTRACT_32BITS(&dp[0]);
  930. if (er)
  931. *er = errnum;
  932. if (errnum != 0) {
  933. if (!ndo->ndo_qflag)
  934. ND_PRINT((ndo, " ERROR: %s",
  935. tok2str(status2str, "unk %d", errnum)));
  936. nfserr = 1;
  937. }
  938. return (dp + 1);
  939. trunc:
  940. return NULL;
  941. }
  942. static const uint32_t *
  943. parsefattr(netdissect_options *ndo,
  944. const uint32_t *dp, int verbose, int v3)
  945. {
  946. const struct nfs_fattr *fap;
  947. fap = (const struct nfs_fattr *)dp;
  948. ND_TCHECK(fap->fa_gid);
  949. if (verbose) {
  950. ND_PRINT((ndo, " %s %o ids %d/%d",
  951. tok2str(type2str, "unk-ft %d ",
  952. EXTRACT_32BITS(&fap->fa_type)),
  953. EXTRACT_32BITS(&fap->fa_mode),
  954. EXTRACT_32BITS(&fap->fa_uid),
  955. EXTRACT_32BITS(&fap->fa_gid)));
  956. if (v3) {
  957. ND_TCHECK(fap->fa3_size);
  958. ND_PRINT((ndo, " sz %" PRIu64,
  959. EXTRACT_64BITS((const uint32_t *)&fap->fa3_size)));
  960. } else {
  961. ND_TCHECK(fap->fa2_size);
  962. ND_PRINT((ndo, " sz %d", EXTRACT_32BITS(&fap->fa2_size)));
  963. }
  964. }
  965. /* print lots more stuff */
  966. if (verbose > 1) {
  967. if (v3) {
  968. ND_TCHECK(fap->fa3_ctime);
  969. ND_PRINT((ndo, " nlink %d rdev %d/%d",
  970. EXTRACT_32BITS(&fap->fa_nlink),
  971. EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
  972. EXTRACT_32BITS(&fap->fa3_rdev.specdata2)));
  973. ND_PRINT((ndo, " fsid %" PRIx64,
  974. EXTRACT_64BITS((const uint32_t *)&fap->fa3_fsid)));
  975. ND_PRINT((ndo, " fileid %" PRIx64,
  976. EXTRACT_64BITS((const uint32_t *)&fap->fa3_fileid)));
  977. ND_PRINT((ndo, " a/m/ctime %u.%06u",
  978. EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
  979. EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec)));
  980. ND_PRINT((ndo, " %u.%06u",
  981. EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
  982. EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec)));
  983. ND_PRINT((ndo, " %u.%06u",
  984. EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
  985. EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec)));
  986. } else {
  987. ND_TCHECK(fap->fa2_ctime);
  988. ND_PRINT((ndo, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime",
  989. EXTRACT_32BITS(&fap->fa_nlink),
  990. EXTRACT_32BITS(&fap->fa2_rdev),
  991. EXTRACT_32BITS(&fap->fa2_fsid),
  992. EXTRACT_32BITS(&fap->fa2_fileid)));
  993. ND_PRINT((ndo, " %u.%06u",
  994. EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
  995. EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec)));
  996. ND_PRINT((ndo, " %u.%06u",
  997. EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
  998. EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec)));
  999. ND_PRINT((ndo, " %u.%06u",
  1000. EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
  1001. EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec)));
  1002. }
  1003. }
  1004. return ((const uint32_t *)((const unsigned char *)dp +
  1005. (v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
  1006. trunc:
  1007. return (NULL);
  1008. }
  1009. static int
  1010. parseattrstat(netdissect_options *ndo,
  1011. const uint32_t *dp, int verbose, int v3)
  1012. {
  1013. int er;
  1014. dp = parsestatus(ndo, dp, &er);
  1015. if (dp == NULL)
  1016. return (0);
  1017. if (er)
  1018. return (1);
  1019. return (parsefattr(ndo, dp, verbose, v3) != NULL);
  1020. }
  1021. static int
  1022. parsediropres(netdissect_options *ndo,
  1023. const uint32_t *dp)
  1024. {
  1025. int er;
  1026. if (!(dp = parsestatus(ndo, dp, &er)))
  1027. return (0);
  1028. if (er)
  1029. return (1);
  1030. dp = parsefh(ndo, dp, 0);
  1031. if (dp == NULL)
  1032. return (0);
  1033. return (parsefattr(ndo, dp, ndo->ndo_vflag, 0) != NULL);
  1034. }
  1035. static int
  1036. parselinkres(netdissect_options *ndo,
  1037. const uint32_t *dp, int v3)
  1038. {
  1039. int er;
  1040. dp = parsestatus(ndo, dp, &er);
  1041. if (dp == NULL)
  1042. return(0);
  1043. if (er)
  1044. return(1);
  1045. if (v3 && !(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1046. return (0);
  1047. ND_PRINT((ndo, " "));
  1048. return (parsefn(ndo, dp) != NULL);
  1049. }
  1050. static int
  1051. parsestatfs(netdissect_options *ndo,
  1052. const uint32_t *dp, int v3)
  1053. {
  1054. const struct nfs_statfs *sfsp;
  1055. int er;
  1056. dp = parsestatus(ndo, dp, &er);
  1057. if (dp == NULL)
  1058. return (0);
  1059. if (!v3 && er)
  1060. return (1);
  1061. if (ndo->ndo_qflag)
  1062. return(1);
  1063. if (v3) {
  1064. if (ndo->ndo_vflag)
  1065. ND_PRINT((ndo, " POST:"));
  1066. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1067. return (0);
  1068. }
  1069. ND_TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
  1070. sfsp = (const struct nfs_statfs *)dp;
  1071. if (v3) {
  1072. ND_PRINT((ndo, " tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
  1073. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tbytes),
  1074. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_fbytes),
  1075. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_abytes)));
  1076. if (ndo->ndo_vflag) {
  1077. ND_PRINT((ndo, " tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
  1078. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_tfiles),
  1079. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_ffiles),
  1080. EXTRACT_64BITS((const uint32_t *)&sfsp->sf_afiles),
  1081. EXTRACT_32BITS(&sfsp->sf_invarsec)));
  1082. }
  1083. } else {
  1084. ND_PRINT((ndo, " tsize %d bsize %d blocks %d bfree %d bavail %d",
  1085. EXTRACT_32BITS(&sfsp->sf_tsize),
  1086. EXTRACT_32BITS(&sfsp->sf_bsize),
  1087. EXTRACT_32BITS(&sfsp->sf_blocks),
  1088. EXTRACT_32BITS(&sfsp->sf_bfree),
  1089. EXTRACT_32BITS(&sfsp->sf_bavail)));
  1090. }
  1091. return (1);
  1092. trunc:
  1093. return (0);
  1094. }
  1095. static int
  1096. parserddires(netdissect_options *ndo,
  1097. const uint32_t *dp)
  1098. {
  1099. int er;
  1100. dp = parsestatus(ndo, dp, &er);
  1101. if (dp == NULL)
  1102. return (0);
  1103. if (er)
  1104. return (1);
  1105. if (ndo->ndo_qflag)
  1106. return (1);
  1107. ND_TCHECK(dp[2]);
  1108. ND_PRINT((ndo, " offset 0x%x size %d ",
  1109. EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1])));
  1110. if (dp[2] != 0)
  1111. ND_PRINT((ndo, " eof"));
  1112. return (1);
  1113. trunc:
  1114. return (0);
  1115. }
  1116. static const uint32_t *
  1117. parse_wcc_attr(netdissect_options *ndo,
  1118. const uint32_t *dp)
  1119. {
  1120. /* Our caller has already checked this */
  1121. ND_PRINT((ndo, " sz %" PRIu64, EXTRACT_64BITS(&dp[0])));
  1122. ND_PRINT((ndo, " mtime %u.%06u ctime %u.%06u",
  1123. EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
  1124. EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5])));
  1125. return (dp + 6);
  1126. }
  1127. /*
  1128. * Pre operation attributes. Print only if vflag > 1.
  1129. */
  1130. static const uint32_t *
  1131. parse_pre_op_attr(netdissect_options *ndo,
  1132. const uint32_t *dp, int verbose)
  1133. {
  1134. ND_TCHECK(dp[0]);
  1135. if (!EXTRACT_32BITS(&dp[0]))
  1136. return (dp + 1);
  1137. dp++;
  1138. ND_TCHECK2(*dp, 24);
  1139. if (verbose > 1) {
  1140. return parse_wcc_attr(ndo, dp);
  1141. } else {
  1142. /* If not verbose enough, just skip over wcc_attr */
  1143. return (dp + 6);
  1144. }
  1145. trunc:
  1146. return (NULL);
  1147. }
  1148. /*
  1149. * Post operation attributes are printed if vflag >= 1
  1150. */
  1151. static const uint32_t *
  1152. parse_post_op_attr(netdissect_options *ndo,
  1153. const uint32_t *dp, int verbose)
  1154. {
  1155. ND_TCHECK(dp[0]);
  1156. if (!EXTRACT_32BITS(&dp[0]))
  1157. return (dp + 1);
  1158. dp++;
  1159. if (verbose) {
  1160. return parsefattr(ndo, dp, verbose, 1);
  1161. } else
  1162. return (dp + (NFSX_V3FATTR / sizeof (uint32_t)));
  1163. trunc:
  1164. return (NULL);
  1165. }
  1166. static const uint32_t *
  1167. parse_wcc_data(netdissect_options *ndo,
  1168. const uint32_t *dp, int verbose)
  1169. {
  1170. if (verbose > 1)
  1171. ND_PRINT((ndo, " PRE:"));
  1172. if (!(dp = parse_pre_op_attr(ndo, dp, verbose)))
  1173. return (0);
  1174. if (verbose)
  1175. ND_PRINT((ndo, " POST:"));
  1176. return parse_post_op_attr(ndo, dp, verbose);
  1177. }
  1178. static const uint32_t *
  1179. parsecreateopres(netdissect_options *ndo,
  1180. const uint32_t *dp, int verbose)
  1181. {
  1182. int er;
  1183. if (!(dp = parsestatus(ndo, dp, &er)))
  1184. return (0);
  1185. if (er)
  1186. dp = parse_wcc_data(ndo, dp, verbose);
  1187. else {
  1188. ND_TCHECK(dp[0]);
  1189. if (!EXTRACT_32BITS(&dp[0]))
  1190. return (dp + 1);
  1191. dp++;
  1192. if (!(dp = parsefh(ndo, dp, 1)))
  1193. return (0);
  1194. if (verbose) {
  1195. if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
  1196. return (0);
  1197. if (ndo->ndo_vflag > 1) {
  1198. ND_PRINT((ndo, " dir attr:"));
  1199. dp = parse_wcc_data(ndo, dp, verbose);
  1200. }
  1201. }
  1202. }
  1203. return (dp);
  1204. trunc:
  1205. return (NULL);
  1206. }
  1207. static int
  1208. parsewccres(netdissect_options *ndo,
  1209. const uint32_t *dp, int verbose)
  1210. {
  1211. int er;
  1212. if (!(dp = parsestatus(ndo, dp, &er)))
  1213. return (0);
  1214. return parse_wcc_data(ndo, dp, verbose) != NULL;
  1215. }
  1216. static const uint32_t *
  1217. parsev3rddirres(netdissect_options *ndo,
  1218. const uint32_t *dp, int verbose)
  1219. {
  1220. int er;
  1221. if (!(dp = parsestatus(ndo, dp, &er)))
  1222. return (0);
  1223. if (ndo->ndo_vflag)
  1224. ND_PRINT((ndo, " POST:"));
  1225. if (!(dp = parse_post_op_attr(ndo, dp, verbose)))
  1226. return (0);
  1227. if (er)
  1228. return dp;
  1229. if (ndo->ndo_vflag) {
  1230. ND_TCHECK(dp[1]);
  1231. ND_PRINT((ndo, " verf %08x%08x", dp[0], dp[1]));
  1232. dp += 2;
  1233. }
  1234. return dp;
  1235. trunc:
  1236. return (NULL);
  1237. }
  1238. static int
  1239. parsefsinfo(netdissect_options *ndo,
  1240. const uint32_t *dp)
  1241. {
  1242. const struct nfsv3_fsinfo *sfp;
  1243. int er;
  1244. if (!(dp = parsestatus(ndo, dp, &er)))
  1245. return (0);
  1246. if (ndo->ndo_vflag)
  1247. ND_PRINT((ndo, " POST:"));
  1248. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1249. return (0);
  1250. if (er)
  1251. return (1);
  1252. sfp = (const struct nfsv3_fsinfo *)dp;
  1253. ND_TCHECK(*sfp);
  1254. ND_PRINT((ndo, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
  1255. EXTRACT_32BITS(&sfp->fs_rtmax),
  1256. EXTRACT_32BITS(&sfp->fs_rtpref),
  1257. EXTRACT_32BITS(&sfp->fs_wtmax),
  1258. EXTRACT_32BITS(&sfp->fs_wtpref),
  1259. EXTRACT_32BITS(&sfp->fs_dtpref)));
  1260. if (ndo->ndo_vflag) {
  1261. ND_PRINT((ndo, " rtmult %u wtmult %u maxfsz %" PRIu64,
  1262. EXTRACT_32BITS(&sfp->fs_rtmult),
  1263. EXTRACT_32BITS(&sfp->fs_wtmult),
  1264. EXTRACT_64BITS((const uint32_t *)&sfp->fs_maxfilesize)));
  1265. ND_PRINT((ndo, " delta %u.%06u ",
  1266. EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
  1267. EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec)));
  1268. }
  1269. return (1);
  1270. trunc:
  1271. return (0);
  1272. }
  1273. static int
  1274. parsepathconf(netdissect_options *ndo,
  1275. const uint32_t *dp)
  1276. {
  1277. int er;
  1278. const struct nfsv3_pathconf *spp;
  1279. if (!(dp = parsestatus(ndo, dp, &er)))
  1280. return (0);
  1281. if (ndo->ndo_vflag)
  1282. ND_PRINT((ndo, " POST:"));
  1283. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1284. return (0);
  1285. if (er)
  1286. return (1);
  1287. spp = (const struct nfsv3_pathconf *)dp;
  1288. ND_TCHECK(*spp);
  1289. ND_PRINT((ndo, " linkmax %u namemax %u %s %s %s %s",
  1290. EXTRACT_32BITS(&spp->pc_linkmax),
  1291. EXTRACT_32BITS(&spp->pc_namemax),
  1292. EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
  1293. EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
  1294. EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
  1295. EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : ""));
  1296. return (1);
  1297. trunc:
  1298. return (0);
  1299. }
  1300. static void
  1301. interp_reply(netdissect_options *ndo,
  1302. const struct sunrpc_msg *rp, uint32_t proc, uint32_t vers, int length)
  1303. {
  1304. register const uint32_t *dp;
  1305. register int v3;
  1306. int er;
  1307. v3 = (vers == NFS_VER3);
  1308. if (!v3 && proc < NFS_NPROCS)
  1309. proc = nfsv3_procid[proc];
  1310. ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc)));
  1311. switch (proc) {
  1312. case NFSPROC_GETATTR:
  1313. dp = parserep(ndo, rp, length);
  1314. if (dp != NULL && parseattrstat(ndo, dp, !ndo->ndo_qflag, v3) != 0)
  1315. return;
  1316. break;
  1317. case NFSPROC_SETATTR:
  1318. if (!(dp = parserep(ndo, rp, length)))
  1319. return;
  1320. if (v3) {
  1321. if (parsewccres(ndo, dp, ndo->ndo_vflag))
  1322. return;
  1323. } else {
  1324. if (parseattrstat(ndo, dp, !ndo->ndo_qflag, 0) != 0)
  1325. return;
  1326. }
  1327. break;
  1328. case NFSPROC_LOOKUP:
  1329. if (!(dp = parserep(ndo, rp, length)))
  1330. break;
  1331. if (v3) {
  1332. if (!(dp = parsestatus(ndo, dp, &er)))
  1333. break;
  1334. if (er) {
  1335. if (ndo->ndo_vflag > 1) {
  1336. ND_PRINT((ndo, " post dattr:"));
  1337. dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
  1338. }
  1339. } else {
  1340. if (!(dp = parsefh(ndo, dp, v3)))
  1341. break;
  1342. if ((dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)) &&
  1343. ndo->ndo_vflag > 1) {
  1344. ND_PRINT((ndo, " post dattr:"));
  1345. dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag);
  1346. }
  1347. }
  1348. if (dp)
  1349. return;
  1350. } else {
  1351. if (parsediropres(ndo, dp) != 0)
  1352. return;
  1353. }
  1354. break;
  1355. case NFSPROC_ACCESS:
  1356. if (!(dp = parserep(ndo, rp, length)))
  1357. break;
  1358. if (!(dp = parsestatus(ndo, dp, &er)))
  1359. break;
  1360. if (ndo->ndo_vflag)
  1361. ND_PRINT((ndo, " attr:"));
  1362. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1363. break;
  1364. if (!er) {
  1365. ND_TCHECK(dp[0]);
  1366. ND_PRINT((ndo, " c %04x", EXTRACT_32BITS(&dp[0])));
  1367. }
  1368. return;
  1369. case NFSPROC_READLINK:
  1370. dp = parserep(ndo, rp, length);
  1371. if (dp != NULL && parselinkres(ndo, dp, v3) != 0)
  1372. return;
  1373. break;
  1374. case NFSPROC_READ:
  1375. if (!(dp = parserep(ndo, rp, length)))
  1376. break;
  1377. if (v3) {
  1378. if (!(dp = parsestatus(ndo, dp, &er)))
  1379. break;
  1380. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1381. break;
  1382. if (er)
  1383. return;
  1384. if (ndo->ndo_vflag) {
  1385. ND_TCHECK(dp[1]);
  1386. ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
  1387. if (EXTRACT_32BITS(&dp[1]))
  1388. ND_PRINT((ndo, " EOF"));
  1389. }
  1390. return;
  1391. } else {
  1392. if (parseattrstat(ndo, dp, ndo->ndo_vflag, 0) != 0)
  1393. return;
  1394. }
  1395. break;
  1396. case NFSPROC_WRITE:
  1397. if (!(dp = parserep(ndo, rp, length)))
  1398. break;
  1399. if (v3) {
  1400. if (!(dp = parsestatus(ndo, dp, &er)))
  1401. break;
  1402. if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
  1403. break;
  1404. if (er)
  1405. return;
  1406. if (ndo->ndo_vflag) {
  1407. ND_TCHECK(dp[0]);
  1408. ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0])));
  1409. if (ndo->ndo_vflag > 1) {
  1410. ND_TCHECK(dp[1]);
  1411. ND_PRINT((ndo, " <%s>",
  1412. tok2str(nfsv3_writemodes,
  1413. NULL, EXTRACT_32BITS(&dp[1]))));
  1414. }
  1415. return;
  1416. }
  1417. } else {
  1418. if (parseattrstat(ndo, dp, ndo->ndo_vflag, v3) != 0)
  1419. return;
  1420. }
  1421. break;
  1422. case NFSPROC_CREATE:
  1423. case NFSPROC_MKDIR:
  1424. if (!(dp = parserep(ndo, rp, length)))
  1425. break;
  1426. if (v3) {
  1427. if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
  1428. return;
  1429. } else {
  1430. if (parsediropres(ndo, dp) != 0)
  1431. return;
  1432. }
  1433. break;
  1434. case NFSPROC_SYMLINK:
  1435. if (!(dp = parserep(ndo, rp, length)))
  1436. break;
  1437. if (v3) {
  1438. if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
  1439. return;
  1440. } else {
  1441. if (parsestatus(ndo, dp, &er) != NULL)
  1442. return;
  1443. }
  1444. break;
  1445. case NFSPROC_MKNOD:
  1446. if (!(dp = parserep(ndo, rp, length)))
  1447. break;
  1448. if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != NULL)
  1449. return;
  1450. break;
  1451. case NFSPROC_REMOVE:
  1452. case NFSPROC_RMDIR:
  1453. if (!(dp = parserep(ndo, rp, length)))
  1454. break;
  1455. if (v3) {
  1456. if (parsewccres(ndo, dp, ndo->ndo_vflag))
  1457. return;
  1458. } else {
  1459. if (parsestatus(ndo, dp, &er) != NULL)
  1460. return;
  1461. }
  1462. break;
  1463. case NFSPROC_RENAME:
  1464. if (!(dp = parserep(ndo, rp, length)))
  1465. break;
  1466. if (v3) {
  1467. if (!(dp = parsestatus(ndo, dp, &er)))
  1468. break;
  1469. if (ndo->ndo_vflag) {
  1470. ND_PRINT((ndo, " from:"));
  1471. if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
  1472. break;
  1473. ND_PRINT((ndo, " to:"));
  1474. if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
  1475. break;
  1476. }
  1477. return;
  1478. } else {
  1479. if (parsestatus(ndo, dp, &er) != NULL)
  1480. return;
  1481. }
  1482. break;
  1483. case NFSPROC_LINK:
  1484. if (!(dp = parserep(ndo, rp, length)))
  1485. break;
  1486. if (v3) {
  1487. if (!(dp = parsestatus(ndo, dp, &er)))
  1488. break;
  1489. if (ndo->ndo_vflag) {
  1490. ND_PRINT((ndo, " file POST:"));
  1491. if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)))
  1492. break;
  1493. ND_PRINT((ndo, " dir:"));
  1494. if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag)))
  1495. break;
  1496. return;
  1497. }
  1498. } else {
  1499. if (parsestatus(ndo, dp, &er) != NULL)
  1500. return;
  1501. }
  1502. break;
  1503. case NFSPROC_READDIR:
  1504. if (!(dp = parserep(ndo, rp, length)))
  1505. break;
  1506. if (v3) {
  1507. if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
  1508. return;
  1509. } else {
  1510. if (parserddires(ndo, dp) != 0)
  1511. return;
  1512. }
  1513. break;
  1514. case NFSPROC_READDIRPLUS:
  1515. if (!(dp = parserep(ndo, rp, length)))
  1516. break;
  1517. if (parsev3rddirres(ndo, dp, ndo->ndo_vflag))
  1518. return;
  1519. break;
  1520. case NFSPROC_FSSTAT:
  1521. dp = parserep(ndo, rp, length);
  1522. if (dp != NULL && parsestatfs(ndo, dp, v3) != 0)
  1523. return;
  1524. break;
  1525. case NFSPROC_FSINFO:
  1526. dp = parserep(ndo, rp, length);
  1527. if (dp != NULL && parsefsinfo(ndo, dp) != 0)
  1528. return;
  1529. break;
  1530. case NFSPROC_PATHCONF:
  1531. dp = parserep(ndo, rp, length);
  1532. if (dp != NULL && parsepathconf(ndo, dp) != 0)
  1533. return;
  1534. break;
  1535. case NFSPROC_COMMIT:
  1536. dp = parserep(ndo, rp, length);
  1537. if (dp != NULL && parsewccres(ndo, dp, ndo->ndo_vflag) != 0)
  1538. return;
  1539. break;
  1540. default:
  1541. return;
  1542. }
  1543. trunc:
  1544. if (!nfserr)
  1545. ND_PRINT((ndo, "%s", tstr));
  1546. }