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
))
53 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, procnet_tab
,
57 if (entry
->type
== virt_file
&& !get_adapters_addresses (NULL
, AF_INET6
))
59 fileid
= entry
- procnet_tab
;
65 fhandler_procnet::fhandler_procnet ():
71 fhandler_procnet::fstat (struct stat
*buf
)
73 fhandler_base::fstat (buf
);
74 buf
->st_mode
&= ~_IFMT
& NO_W
;
75 int file_type
= exists ();
83 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
88 buf
->st_mode
|= S_IFREG
| S_IRUSR
| S_IRGRP
| S_IROTH
;
94 fhandler_procnet::readdir (DIR *dir
, dirent
*de
)
97 if (dir
->__d_position
>= PROCNET_LINK_COUNT
)
99 if (procnet_tab
[dir
->__d_position
].type
== virt_file
100 && !get_adapters_addresses (NULL
, AF_INET6
))
102 strcpy (de
->d_name
, procnet_tab
[dir
->__d_position
].name
);
103 de
->d_type
= virt_ftype_to_dtype (procnet_tab
[dir
->__d_position
].type
);
105 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
108 syscall_printf ("%d = readdir(%p, %p) (%s)", res
, dir
, de
, de
->d_name
);
113 fhandler_procnet::open (int flags
, mode_t mode
)
115 int res
= fhandler_virtual::open (flags
, mode
);
122 path
= get_name () + proc_len
+ 1;
123 while (*path
!= 0 && !isdirsep (*path
))
128 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
134 else if (flags
& O_WRONLY
)
148 entry
= virt_tab_search (path
+ 1, true, procnet_tab
, PROCNET_LINK_COUNT
);
151 set_errno ((flags
& O_CREAT
) ? EROFS
: ENOENT
);
155 if (flags
& O_WRONLY
)
162 fileid
= entry
- procnet_tab
;
163 if (!fill_filebuf ())
169 if (flags
& O_APPEND
)
176 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
179 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res
, flags
, mode
);
184 fhandler_procnet::fill_filebuf ()
186 if (procnet_tab
[fileid
].format_func
)
188 filesize
= procnet_tab
[fileid
].format_func (NULL
, filebuf
);
194 /* Return the same scope values as Linux. */
196 get_scope (struct in6_addr
*addr
)
198 if (IN6_IS_ADDR_LOOPBACK (addr
))
200 if (IN6_IS_ADDR_LINKLOCAL (addr
))
202 if (IN6_IS_ADDR_SITELOCAL (addr
))
204 if (IN6_IS_ADDR_V4COMPAT (addr
))
209 /* Convert DAD state into Linux compatible values. */
210 static unsigned int dad_to_flags
[] =
212 0x02, /* Invalid -> NODAD */
213 0x40, /* Tentative -> TENTATIVE */
214 0xc0, /* Duplicate -> PERMANENT | TENTATIVE */
215 0x20, /* Deprecated -> DEPRECATED */
216 0x80 /* Preferred -> PERMANENT */
220 format_procnet_ifinet6 (void *, char *&filebuf
)
222 PIP_ADAPTER_ADDRESSES pa0
= NULL
, pap
;
223 PIP_ADAPTER_UNICAST_ADDRESS pua
;
227 if (!get_adapters_addresses (&pa0
, AF_INET6
))
230 for (pap
= pa0
; pap
; pap
= pap
->Next
)
231 for (pua
= pap
->FirstUnicastAddress
; pua
; pua
= pua
->Next
)
235 filebuf
= (char *) crealloc (filebuf
, alloclen
);
238 for (pap
= pa0
; pap
; pap
= pap
->Next
)
239 for (pua
= pap
->FirstUnicastAddress
; pua
; pua
= pua
->Next
)
241 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)
242 pua
->Address
.lpSockaddr
;
243 for (int i
= 0; i
< 8; ++i
)
244 /* __small_sprintf generates upper-case hex. */
245 filesize
+= sprintf (filebuf
+ filesize
, "%04x",
246 ntohs (sin6
->sin6_addr
.s6_addr16
[i
]));
247 filebuf
[filesize
++] = ' ';
248 filesize
+= sprintf (filebuf
+ filesize
,
249 "%02lx %02x %02x %02x %s\n",
250 (long) pap
->Ipv6IfIndex
,
251 pua
->OnLinkPrefixLength
,
252 get_scope (&((struct sockaddr_in6
*)
253 pua
->Address
.lpSockaddr
)->sin6_addr
),
254 dad_to_flags
[pua
->DadState
],