1 /* fhandler_procnet.cc: fhandler for /proc/net virtual filesystem
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 #define __INSIDE_CYGWIN_NET__
10 #define USE_SYS_TYPES_FD_SET
12 /* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
13 because a redefinition for LP64 systems is missing. This leads to a wrong
14 definition and size of sockaddr_in6 when building with winsock headers. */
16 #define u_long __ms_u_long
17 #include <w32api/ws2tcpip.h>
18 #include <w32api/iphlpapi.h>
19 #include <asm/byteorder.h>
24 #include "fhandler_virtual.h"
27 bool get_adapters_addresses (PIP_ADAPTER_ADDRESSES
*pa0
, ULONG family
);
29 static off_t
format_procnet_ifinet6 (void *, char *&);
31 static const virt_tab_t procnet_tab
[] =
33 { _VN ("."), FH_PROCNET
, virt_directory
, NULL
},
34 { _VN (".."), FH_PROCNET
, virt_directory
, NULL
},
35 { _VN ("if_inet6"), FH_PROCNET
, virt_file
, format_procnet_ifinet6
},
36 { NULL
, 0, FH_NADA
, virt_none
, NULL
}
39 static const int PROCNET_LINK_COUNT
=
40 (sizeof (procnet_tab
) / sizeof (virt_tab_t
)) - 1;
43 fhandler_procnet::exists ()
45 const char *path
= get_name ();
46 debug_printf ("exists (%s)", path
);
48 while (*path
!= 0 && !isdirsep (*path
))
56 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, procnet_tab
,
60 if (entry
->type
== virt_file
&& !get_adapters_addresses (NULL
, AF_INET6
))
62 fileid () = entry
- procnet_tab
;
69 fhandler_procnet::fhandler_procnet ():
75 fhandler_procnet::fstat (struct stat
*buf
)
77 fhandler_base::fstat (buf
);
78 buf
->st_mode
&= ~_IFMT
& NO_W
;
79 int file_type
= exists ();
87 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
92 buf
->st_mode
|= S_IFREG
| S_IRUSR
| S_IRGRP
| S_IROTH
;
98 fhandler_procnet::readdir (DIR *dir
, dirent
*de
)
101 if (dir
->__d_position
>= PROCNET_LINK_COUNT
)
103 if (procnet_tab
[dir
->__d_position
].type
== virt_file
104 && !get_adapters_addresses (NULL
, AF_INET6
))
106 strcpy (de
->d_name
, procnet_tab
[dir
->__d_position
].name
);
107 de
->d_type
= virt_ftype_to_dtype (procnet_tab
[dir
->__d_position
].type
);
109 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
112 syscall_printf ("%d = readdir(%p, %p) (%s)", res
, dir
, de
, de
->d_name
);
117 fhandler_procnet::open (int flags
, mode_t mode
)
119 int res
= fhandler_virtual::open (flags
, mode
);
126 path
= get_name () + proc_len
+ 1;
127 while (*path
!= 0 && !isdirsep (*path
))
132 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
138 else if (flags
& O_WRONLY
)
152 entry
= virt_tab_search (path
+ 1, true, procnet_tab
, PROCNET_LINK_COUNT
);
155 set_errno ((flags
& O_CREAT
) ? EROFS
: ENOENT
);
159 if (flags
& O_WRONLY
)
166 fileid () = entry
- procnet_tab
;
167 if (!fill_filebuf ())
173 if (flags
& O_APPEND
)
180 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
183 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res
, flags
, mode
);
188 fhandler_procnet::fill_filebuf ()
190 if (procnet_tab
[fileid ()].format_func
)
192 filesize
= procnet_tab
[fileid ()].format_func (NULL
, filebuf
);
198 /* Return the same scope values as Linux. */
200 get_scope (struct in6_addr
*addr
)
202 if (IN6_IS_ADDR_LOOPBACK (addr
))
204 if (IN6_IS_ADDR_LINKLOCAL (addr
))
206 if (IN6_IS_ADDR_SITELOCAL (addr
))
208 if (IN6_IS_ADDR_V4COMPAT (addr
))
213 /* Convert DAD state into Linux compatible values. */
214 static unsigned int dad_to_flags
[] =
216 0x02, /* Invalid -> NODAD */
217 0x40, /* Tentative -> TENTATIVE */
218 0xc0, /* Duplicate -> PERMANENT | TENTATIVE */
219 0x20, /* Deprecated -> DEPRECATED */
220 0x80 /* Preferred -> PERMANENT */
224 format_procnet_ifinet6 (void *, char *&filebuf
)
226 PIP_ADAPTER_ADDRESSES pa0
= NULL
, pap
;
227 PIP_ADAPTER_UNICAST_ADDRESS pua
;
231 if (!get_adapters_addresses (&pa0
, AF_INET6
))
234 for (pap
= pa0
; pap
; pap
= pap
->Next
)
235 for (pua
= pap
->FirstUnicastAddress
; pua
; pua
= pua
->Next
)
239 filebuf
= (char *) crealloc (filebuf
, alloclen
);
242 for (pap
= pa0
; pap
; pap
= pap
->Next
)
243 for (pua
= pap
->FirstUnicastAddress
; pua
; pua
= pua
->Next
)
245 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)
246 pua
->Address
.lpSockaddr
;
247 for (int i
= 0; i
< 8; ++i
)
248 /* __small_sprintf generates upper-case hex. */
249 filesize
+= sprintf (filebuf
+ filesize
, "%04x",
250 ntohs (sin6
->sin6_addr
.s6_addr16
[i
]));
251 filebuf
[filesize
++] = ' ';
252 filesize
+= sprintf (filebuf
+ filesize
,
253 "%02lx %02x %02x %02x %s\n",
254 (long) pap
->Ipv6IfIndex
,
255 pua
->OnLinkPrefixLength
,
256 get_scope (&((struct sockaddr_in6
*)
257 pua
->Address
.lpSockaddr
)->sin6_addr
),
258 dad_to_flags
[pua
->DadState
],