1 /* LWIP service - util.c - shared utility functions */
5 #define US 1000000 /* number of microseconds per second */
8 * Convert the given timeval structure to a number of clock ticks, checking
9 * whether the given structure is valid and whether the resulting number of
10 * ticks can be expressed as a (relative) clock ticks value. Upon success,
11 * return OK, with the number of clock ticks stored in 'ticksp'. Upon failure,
12 * return a negative error code that may be returned to userland directly. In
13 * that case, the contents of 'ticksp' are left unchanged.
15 * TODO: move this function into libsys and remove other redundant copies.
18 util_timeval_to_ticks(const struct timeval
* tv
, clock_t * ticksp
)
22 if (tv
->tv_sec
< 0 || tv
->tv_usec
< 0 || tv
->tv_usec
>= US
)
25 if (tv
->tv_sec
>= TMRDIFF_MAX
/ sys_hz())
28 ticks
= tv
->tv_sec
* sys_hz() + (tv
->tv_usec
* sys_hz() + US
- 1) / US
;
29 assert(ticks
<= TMRDIFF_MAX
);
36 * Convert the given number of clock ticks to a timeval structure. This
37 * function never fails.
40 util_ticks_to_timeval(clock_t ticks
, struct timeval
* tv
)
43 memset(tv
, 0, sizeof(*tv
));
44 tv
->tv_sec
= ticks
/ sys_hz();
45 tv
->tv_usec
= (ticks
% sys_hz()) * US
/ sys_hz();
49 * Copy data between a user process and a chain of buffers. If the 'copy_in'
50 * flag is set, the data will be copied in from the user process to the given
51 * chain of buffers; otherwise, the data will be copied out from the given
52 * buffer chain to the user process. The 'data' parameter is a sockdriver-
53 * supplied structure identifying the remote source or destination of the data.
54 * The 'len' parameter contains the number of bytes to copy, and 'off' contains
55 * the offset into the remote source or destination. 'pbuf' is a pointer to
56 * the buffer chain, and 'skip' is the number of bytes to skip in the first
57 * buffer on the chain. Return OK on success, or a negative error code if the
58 * copy operation failed. This function is packet queue friendly.
61 util_copy_data(const struct sockdriver_data
* data
, size_t len
, size_t off
,
62 const struct pbuf
* pbuf
, size_t skip
, int copy_in
)
64 iovec_t iov
[SOCKDRIVER_IOV_MAX
];
72 for (i
= 0; len
> 0 && i
< __arraycount(iov
); i
++) {
75 chunk
= (size_t)pbuf
->len
- skip
;
79 iov
[i
].iov_addr
= (vir_bytes
)pbuf
->payload
+ skip
;
80 iov
[i
].iov_size
= chunk
;
90 r
= sockdriver_vcopyin(data
, off
, iov
, i
);
92 r
= sockdriver_vcopyout(data
, off
, iov
, i
);
103 * Copy from a vector of (local) buffers to a single (local) buffer. Return
104 * the total number of copied bytes on success, or E2BIG if not all of the
105 * results could be stored in the given bfufer.
108 util_coalesce(char * ptr
, size_t max
, const iovec_t
* iov
, unsigned int iovcnt
)
112 for (off
= 0; iovcnt
> 0; iov
++, iovcnt
--) {
113 if ((size
= iov
->iov_size
) > max
)
116 memcpy(&ptr
[off
], (void *)iov
->iov_addr
, size
);
126 * Return TRUE if the given endpoint has superuser privileges, FALSE otherwise.
129 util_is_root(endpoint_t endpt
)
132 return (getnuid(endpt
) == ROOT_EUID
);
136 * Convert a lwIP-provided error code (of type err_t) to a negative MINIX 3
140 util_convert_err(err_t err
)
144 case ERR_OK
: return OK
;
145 case ERR_MEM
: return ENOMEM
;
146 case ERR_BUF
: return ENOBUFS
;
147 case ERR_TIMEOUT
: return ETIMEDOUT
;
148 case ERR_RTE
: return EHOSTUNREACH
;
149 case ERR_VAL
: return EINVAL
;
150 case ERR_USE
: return EADDRINUSE
;
151 case ERR_ALREADY
: return EALREADY
;
152 case ERR_ISCONN
: return EISCONN
;
153 case ERR_CONN
: return ENOTCONN
;
154 case ERR_IF
: return ENETDOWN
;
155 case ERR_ABRT
: return ECONNABORTED
;
156 case ERR_RST
: return ECONNRESET
;
157 case ERR_INPROGRESS
: return EINPROGRESS
; /* should not be thrown */
158 case ERR_WOULDBLOCK
: return EWOULDBLOCK
; /* should not be thrown */
159 case ERR_ARG
: return EINVAL
;
160 case ERR_CLSD
: /* should be caught as separate case */
161 default: /* should have a case here */
162 printf("LWIP: unexpected error from lwIP: %d", err
);
168 * Obtain the list of protocol control blocks for a particular domain and
169 * protocol. The call may be used for requesting either IPv4 or IPv6 PCBs,
170 * based on the path used to get here. It is used for TCP, UDP, and RAW PCBs.
173 util_pcblist(struct rmib_call
* call
, struct rmib_oldp
* oldp
,
174 const void *(*enum_proc
)(const void *),
175 void (*get_info_proc
)(struct kinfo_pcb
*, const void *))
181 int r
, size
, max
, domain
, protocol
;
183 if (call
->call_namelen
!= 4)
186 /* The first two added name fields are not used. */
188 size
= call
->call_name
[2];
189 if (size
< 0 || (size_t)size
> sizeof(ki
))
193 max
= call
->call_name
[3];
195 domain
= call
->call_oname
[1];
196 protocol
= call
->call_oname
[2];
200 for (pcb
= enum_proc(NULL
); pcb
!= NULL
; pcb
= enum_proc(pcb
)) {
201 /* Filter on IPv4/IPv6. */
202 memcpy(&local_ip
, &((const struct ip_pcb
*)pcb
)->local_ip
,
206 * lwIP does not support IPv6 sockets with IPv4-mapped IPv6
207 * addresses, and requires that those be represented as IPv4
208 * sockets instead. We perform the appropriate conversions to
209 * make that work in general, but here we only have the lwIP
210 * PCB to go on, and that PCB may not even have an associated
211 * sock data structure. As a result, we have to report IPv6
212 * sockets with IPv4-mapped IPv6 addresses as IPv4 sockets
213 * here. There is little room for improvement until lwIP
214 * allows us to store a "this is really an IPv6 socket" flag in
215 * its PCBs. As documented in the ipsock module, a partial
216 * solution would for example cause TCP sockets to "jump" from
217 * the IPv6 listing to the IPv4 listing when entering TIME_WAIT
218 * state. The jumping already occurs now for sockets that are
219 * getting bound, but that is not as problematic.
221 if ((domain
== AF_INET
) != IP_IS_V4(&local_ip
))
224 if (rmib_inrange(oldp
, off
)) {
225 memset(&ki
, 0, sizeof(ki
));
227 ki
.ki_pcbaddr
= (uint64_t)(uintptr_t)pcb
;
228 ki
.ki_ppcbaddr
= (uint64_t)(uintptr_t)pcb
;
229 ki
.ki_family
= domain
;
230 ki
.ki_protocol
= protocol
;
232 get_info_proc(&ki
, pcb
);
234 if ((r
= rmib_copyout(oldp
, off
, &ki
, size
)) < OK
)
239 if (max
> 0 && --max
== 0)
244 * Margin to limit the possible effects of the inherent race condition
245 * between receiving just the data size and receiving the actual data.
248 off
+= PCB_SLOP
* size
;