1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-05-17 ChenYong First version
9 */
10
11 #include <rtthread.h>
12
13 #ifdef SAL_USING_POSIX
14 #include <poll.h>
15 #endif
16
17 #include <lwip/sockets.h>
18 #include <lwip/netdb.h>
19 #include <lwip/api.h>
20 #include <lwip/init.h>
21 #include <lwip/netif.h>
22
23 #include <sal_low_lvl.h>
24 #include <af_inet.h>
25
26 #include <netdev.h>
27
28 #if (LWIP_VERSION < 0x2000000) && NETDEV_IPV6
29 #error "The lwIP version is not support IPV6, please disable netdev IPV6 configuration "
30 #elif (LWIP_VERSION > 0x2000000) && (NETDEV_IPV6 != LWIP_IPV6)
31 #error "IPV6 configuration error, Please check and synchronize netdev and lwip IPV6 configuration."
32 #endif
33
34 #if LWIP_VERSION < 0x2000000
35 #define SELWAIT_T int
36 #else
37 #ifndef SELWAIT_T
38 #define SELWAIT_T u8_t
39 #endif
40 #endif
41
42 #ifdef SAL_USING_LWIP
43
44 #ifdef SAL_USING_POSIX
45
46 #if LWIP_VERSION >= 0x20100ff
47 #include <lwip/priv/sockets_priv.h>
48 #else /* LWIP_VERSION < 0x20100ff */
49 /*
50 * Re-define lwip socket
51 *
52 * NOTE: please make sure the definitions same in lwip::net_socket.c
53 */
54 struct lwip_sock {
55 /** sockets currently are built on netconns, each socket has one netconn */
56 struct netconn *conn;
57 /** data that was left from the previous read */
58 void *lastdata;
59 /** offset in the data that was left from the previous read */
60 u16_t lastoffset;
61 /** number of times data was received, set by event_callback(),
62 tested by the receive and select functions */
63 s16_t rcvevent;
64 /** number of times data was ACKed (free send buffer), set by event_callback(),
65 tested by select */
66 u16_t sendevent;
67 /** error happened for this socket, set by event_callback(), tested by select */
68 u16_t errevent;
69 /** last error that occurred on this socket */
70 #if LWIP_VERSION < 0x2000000
71 int err;
72 #else
73 u8_t err;
74 #endif
75 /** counter of how many threads are waiting for this socket using select */
76 SELWAIT_T select_waiting;
77
78 rt_wqueue_t wait_head;
79 };
80 #endif /* LWIP_VERSION >= 0x20100ff */
81
82 static RT_DEFINE_SPINLOCK(_spinlock);
83
84 extern struct lwip_sock *lwip_tryget_socket(int s);
85
event_callback(struct netconn * conn,enum netconn_evt evt,u16_t len)86 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
87 {
88 int s;
89 struct lwip_sock *sock;
90 uint32_t event = 0;
91 SYS_ARCH_DECL_PROTECT(lev);
92
93 LWIP_UNUSED_ARG(len);
94
95 /* Get socket */
96 if (conn)
97 {
98 s = conn->socket;
99 if (s < 0)
100 {
101 /* Data comes in right away after an accept, even though
102 * the server task might not have created a new socket yet.
103 * Just count down (or up) if that's the case and we
104 * will use the data later. Note that only receive events
105 * can happen before the new socket is set up. */
106 SYS_ARCH_PROTECT(lev);
107 if (conn->socket < 0)
108 {
109 if (evt == NETCONN_EVT_RCVPLUS)
110 {
111 conn->socket--;
112 }
113 SYS_ARCH_UNPROTECT(lev);
114 return;
115 }
116 s = conn->socket;
117 SYS_ARCH_UNPROTECT(lev);
118 }
119
120 sock = lwip_tryget_socket(s);
121 if (!sock)
122 {
123 return;
124 }
125 }
126 else
127 {
128 return;
129 }
130
131 SYS_ARCH_PROTECT(lev);
132 /* Set event as required */
133 switch (evt)
134 {
135 case NETCONN_EVT_RCVPLUS:
136 sock->rcvevent++;
137 break;
138 case NETCONN_EVT_RCVMINUS:
139 sock->rcvevent--;
140 break;
141 case NETCONN_EVT_SENDPLUS:
142 sock->sendevent = 1;
143 break;
144 case NETCONN_EVT_SENDMINUS:
145 sock->sendevent = 0;
146 break;
147 case NETCONN_EVT_ERROR:
148 sock->errevent = 1;
149 break;
150 default:
151 LWIP_ASSERT("unknown event", 0);
152 break;
153 }
154
155 #if LWIP_VERSION >= 0x20100ff
156 if ((void*)(sock->lastdata.pbuf) || (sock->rcvevent > 0))
157 #else
158 if ((void*)(sock->lastdata) || (sock->rcvevent > 0))
159 #endif
160 event |= POLLIN;
161 if (sock->sendevent)
162 event |= POLLOUT;
163 if (sock->errevent)
164 event |= POLLERR;
165
166 SYS_ARCH_UNPROTECT(lev);
167
168 if (event)
169 {
170 rt_wqueue_wakeup(&sock->wait_head, (void*)(size_t)event);
171 }
172 }
173 #endif /* SAL_USING_POSIX */
174
inet_socket(int domain,int type,int protocol)175 static int inet_socket(int domain, int type, int protocol)
176 {
177 #ifdef SAL_USING_POSIX
178 int socket;
179
180 socket = lwip_socket(domain, type, protocol);
181 if (socket >= 0)
182 {
183 struct lwip_sock *lwsock;
184
185 lwsock = lwip_tryget_socket(socket);
186 lwsock->conn->callback = event_callback;
187
188 rt_wqueue_init(&lwsock->wait_head);
189 }
190
191 return socket;
192 #else
193 return lwip_socket(domain, type, protocol);
194 #endif /* SAL_USING_POSIX */
195 }
196
inet_accept(int socket,struct sockaddr * addr,socklen_t * addrlen)197 static int inet_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
198 {
199 #ifdef SAL_USING_POSIX
200 int new_socket;
201
202 new_socket = lwip_accept(socket, addr, addrlen);
203 if (new_socket >= 0)
204 {
205 struct lwip_sock *lwsock;
206
207 lwsock = lwip_tryget_socket(new_socket);
208
209 rt_wqueue_init(&lwsock->wait_head);
210 }
211
212 return new_socket;
213 #else
214 return lwip_accept(socket, addr, addrlen);
215 #endif /* SAL_USING_POSIX */
216 }
217
inet_getsockname(int socket,struct sockaddr * name,socklen_t * namelen)218 static int inet_getsockname(int socket, struct sockaddr *name, socklen_t *namelen)
219 {
220 #if LWIP_VERSION_MAJOR < 2U
221 rt_kprintf("ERROR: Your lwIP version is not supported. Please using lwIP 2.0.0+.\n");
222 RT_ASSERT(LWIP_VERSION_MAJOR >= 2U);
223 #endif
224
225 return lwip_getsockname(socket, name, namelen);
226 }
227
inet_ioctlsocket(int socket,long cmd,void * arg)228 int inet_ioctlsocket(int socket, long cmd, void *arg)
229 {
230 int flags;
231
232 switch (cmd)
233 {
234 case F_GETFL:
235 case F_SETFL:
236 flags = (int)(size_t)arg;
237 #ifdef O_LARGEFILE
238 flags &= ~O_LARGEFILE;
239 #endif
240 return lwip_fcntl(socket, cmd, flags);
241
242 default:
243 return lwip_ioctl(socket, cmd, arg);
244 }
245 }
246
247 #ifdef SAL_USING_POSIX
inet_poll(struct dfs_file * file,struct rt_pollreq * req)248 static int inet_poll(struct dfs_file *file, struct rt_pollreq *req)
249 {
250 int mask = 0;
251 struct lwip_sock *sock;
252 struct sal_socket *sal_sock;
253
254 sal_sock = sal_get_socket((int)(size_t)file->vnode->data);
255 if(!sal_sock)
256 {
257 return -1;
258 }
259
260 sock = lwip_tryget_socket((int)(size_t)sal_sock->user_data);
261 if (sock != NULL)
262 {
263 rt_base_t level;
264
265 rt_poll_add(&sock->wait_head, req);
266
267 level = rt_spin_lock_irqsave(&_spinlock);
268
269 #if LWIP_VERSION >= 0x20100ff
270 if ((void*)(sock->lastdata.pbuf) || sock->rcvevent)
271 #else
272 if ((void*)(sock->lastdata) || sock->rcvevent)
273 #endif
274 {
275 mask |= POLLIN;
276 }
277 if (sock->sendevent)
278 {
279 mask |= POLLOUT;
280 }
281 if (sock->errevent)
282 {
283 mask |= POLLERR;
284 /* clean error event */
285 sock->errevent = 0;
286 }
287 rt_spin_unlock_irqrestore(&_spinlock, level);
288 }
289
290 return mask;
291 }
292 #endif
293
294 static const struct sal_socket_ops lwip_socket_ops =
295 {
296 .socket = inet_socket,
297 .closesocket = lwip_close,
298 .bind = lwip_bind,
299 .listen = lwip_listen,
300 .connect = lwip_connect,
301 .accept = inet_accept,
302 .sendto = (int (*)(int, const void *, size_t, int, const struct sockaddr *, socklen_t))lwip_sendto,
303 #if LWIP_VERSION >= 0x20102ff
304 .sendmsg = (int (*)(int, const struct msghdr *, int))lwip_sendmsg,
305 .recvmsg = (int (*)(int, struct msghdr *, int))lwip_recvmsg,
306 #endif
307 .recvfrom = (int (*)(int, void *, size_t, int, struct sockaddr *, socklen_t *))lwip_recvfrom,
308 .getsockopt = lwip_getsockopt,
309 //TODO fix on 1.4.1
310 .setsockopt = lwip_setsockopt,
311 .shutdown = lwip_shutdown,
312 .getpeername = lwip_getpeername,
313 .getsockname = inet_getsockname,
314 .ioctlsocket = inet_ioctlsocket,
315 .socketpair = RT_NULL,
316 #ifdef SAL_USING_POSIX
317 .poll = inet_poll,
318 #endif
319 };
320
321 static const struct sal_netdb_ops lwip_netdb_ops =
322 {
323 .gethostbyname = lwip_gethostbyname,
324 .gethostbyname_r = lwip_gethostbyname_r,
325 .getaddrinfo = lwip_getaddrinfo,
326 .freeaddrinfo = lwip_freeaddrinfo,
327 };
328
329 static const struct sal_proto_family lwip_inet_family =
330 {
331 .family = AF_INET,
332 #if LWIP_VERSION > 0x2000000
333 .sec_family = AF_INET6,
334 #else
335 .sec_family = AF_INET,
336 #endif
337 .skt_ops = &lwip_socket_ops,
338 .netdb_ops = &lwip_netdb_ops,
339 };
340
341 /* Set lwIP network interface device protocol family information */
sal_lwip_netdev_set_pf_info(struct netdev * netdev)342 int sal_lwip_netdev_set_pf_info(struct netdev *netdev)
343 {
344 RT_ASSERT(netdev);
345
346 netdev->sal_user_data = (void *) &lwip_inet_family;
347 return 0;
348 }
349
350 #endif /* SAL_USING_LWIP */
351