64-bit VFS_LSEEK_OFF
[minix3.git] / servers / lwip / udp.c
blob21c4cf7a04e042a9318eb1accd937ccf62543b39
1 #include <stdlib.h>
3 #include <minix/sysutil.h>
5 #include <sys/ioc_net.h>
6 #include <net/gen/in.h>
7 #include <net/gen/udp.h>
8 #include <net/gen/udp_io.h>
9 #include <net/gen/udp_io_hdr.h>
11 #include <lwip/udp.h>
12 #include <lwip/ip_addr.h>
14 #include <minix/netsock.h>
15 #include "proto.h"
17 #define UDP_BUF_SIZE (4 << 10)
19 #define sock_alloc_buf(s) debug_malloc(s)
20 #define sock_free_buf(x) debug_free(x)
22 #if 0
23 #define debug_udp_print(str, ...) printf("LWIP %s:%d : " str "\n", \
24 __func__, __LINE__, ##__VA_ARGS__)
25 #else
26 #define debug_udp_print(...) debug_print(__VA_ARGS__)
27 #endif
29 struct udp_recv_data {
30 ip_addr_t ip;
31 u16_t port;
32 struct pbuf * pbuf;
35 #define udp_recv_alloc() debug_malloc(sizeof(struct udp_recv_data))
37 static void udp_recv_free(void * data)
39 if (((struct udp_recv_data *)data)->pbuf)
40 pbuf_free(((struct udp_recv_data *)data)->pbuf);
41 debug_free(data);
44 static int udp_op_open(struct socket * sock)
46 struct udp_pcb * pcb;
48 debug_udp_print("socket num %ld", get_sock_num(sock));
50 if (!(pcb = udp_new()))
51 return ENOMEM;
53 sock->buf = NULL;
54 sock->buf_size = 0;
56 sock->pcb = pcb;
58 return OK;
61 static int udp_op_close(struct socket * sock)
63 debug_udp_print("socket num %ld", get_sock_num(sock));
65 /* deque and free all enqueued data before closing */
66 sock_dequeue_data_all(sock, udp_recv_free);
68 if (sock->pcb)
69 udp_remove(sock->pcb);
70 assert(sock->buf == NULL);
72 /* mark it as unused */
73 sock->ops = NULL;
75 return OK;
78 static int udp_do_receive(struct socket * sock,
79 struct sock_req * req,
80 struct udp_pcb *pcb,
81 struct pbuf *pbuf,
82 ip_addr_t *addr,
83 u16_t port)
85 struct pbuf * p;
86 size_t rem_len = req->size;
87 unsigned int written = 0, hdr_sz = 0;
88 int err;
90 debug_udp_print("user buffer size : %u", rem_len);
92 /* FIXME make it both a single copy */
93 if (!(sock->usr_flags & NWUO_RWDATONLY)) {
94 udp_io_hdr_t hdr;
96 hdr.uih_src_addr = addr->addr;
97 hdr.uih_src_port = htons(port);
98 hdr.uih_dst_addr = pcb->local_ip.addr;
99 hdr.uih_dst_port = htons(pcb->local_port);
101 hdr.uih_data_len = 0;
102 hdr.uih_ip_opt_len = 0;
104 err = copy_to_user(req->endpt, &hdr, sizeof(hdr), req->grant,
107 if (err != OK)
108 return err;
110 rem_len -= (hdr_sz = sizeof(hdr));
113 for (p = pbuf; p && rem_len; p = p->next) {
114 size_t cp_len;
116 cp_len = (rem_len < p->len) ? rem_len : p->len;
117 err = copy_to_user(req->endpt, p->payload, cp_len, req->grant,
118 hdr_sz + written);
120 if (err != OK)
121 return err;
123 written += cp_len;
124 rem_len -= cp_len;
127 debug_udp_print("copied %d bytes", written + hdr_sz);
128 return written + hdr_sz;
131 static void udp_recv_callback(void *arg,
132 struct udp_pcb *pcb,
133 struct pbuf *pbuf,
134 ip_addr_t *addr,
135 u16_t port)
137 struct socket * sock = (struct socket *) arg;
138 struct udp_recv_data * data;
140 debug_udp_print("socket num : %ld addr : %x port : %d\n",
141 get_sock_num(sock), (unsigned int) addr->addr, port);
143 if (sock->flags & SOCK_FLG_OP_PENDING) {
144 /* we are resuming a suspended operation */
145 int ret;
147 ret = udp_do_receive(sock, &sock->req, pcb, pbuf, addr, port);
149 send_req_reply(&sock->req, ret);
150 sock->flags &= ~SOCK_FLG_OP_PENDING;
152 if (ret > 0) {
153 pbuf_free(pbuf);
154 return;
158 /* Do not enqueue more data than allowed */
159 if (sock->recv_data_size > UDP_BUF_SIZE) {
160 pbuf_free(pbuf);
161 return;
165 * nobody is waiting for the data or an error occured above, we enqueue
166 * the packet
168 if (!(data = udp_recv_alloc())) {
169 pbuf_free(pbuf);
170 return;
173 data->ip = *addr;
174 data->port = port;
175 data->pbuf = pbuf;
177 if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
178 udp_recv_free(data);
179 return;
183 * We don't need to notify when somebody is already waiting, reviving
184 * read operation will do the trick for us. But we must announce new
185 * data available here.
187 if (sock_select_read_set(sock))
188 sock_select_notify(sock);
191 static int udp_op_read(struct socket * sock, struct sock_req * req, int blk)
193 debug_udp_print("socket num %ld", get_sock_num(sock));
195 if (sock->recv_head) {
196 /* data available receive immeditely */
198 struct udp_recv_data * data;
199 int ret;
201 data = (struct udp_recv_data *) sock->recv_head->data;
203 ret = udp_do_receive(sock, req, (struct udp_pcb *) sock->pcb,
204 data->pbuf, &data->ip, data->port);
206 if (ret > 0) {
207 sock_dequeue_data(sock);
208 sock->recv_data_size -= data->pbuf->tot_len;
209 udp_recv_free(data);
211 return ret;
212 } else if (!blk)
213 return EAGAIN;
214 else {
215 /* store the message so we know how to reply */
216 sock->req = *req;
217 /* operation is being processes */
218 sock->flags |= SOCK_FLG_OP_PENDING;
220 debug_udp_print("no data to read, suspending\n");
221 return EDONTREPLY;
225 static int udp_op_send(struct socket * sock,
226 struct pbuf * pbuf,
227 size_t size)
229 int err;
231 debug_udp_print("pbuf len %d\n", pbuf->len);
233 if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK)
234 return size;
235 else {
236 debug_udp_print("udp_send failed %d", err);
237 return EIO;
241 static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, size_t size)
243 int err;
244 udp_io_hdr_t hdr;
246 hdr = *(udp_io_hdr_t *) pbuf->payload;
248 pbuf_header(pbuf, -(s16_t)sizeof(udp_io_hdr_t));
250 debug_udp_print("data len %d pbuf len %d\n",
251 hdr.uih_data_len, pbuf->len);
253 if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr,
254 ntohs(hdr.uih_dst_port))) == ERR_OK)
255 return size;
256 else {
257 debug_udp_print("udp_sendto failed %d", err);
258 return EIO;
262 static int udp_op_write(struct socket * sock, struct sock_req * req,
263 __unused int blk)
265 int ret;
266 struct pbuf * pbuf;
268 debug_udp_print("socket num %ld data size %u",
269 get_sock_num(sock), req->size);
271 pbuf = pbuf_alloc(PBUF_TRANSPORT, req->size, PBUF_POOL);
272 if (!pbuf)
273 return ENOMEM;
275 if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size,
276 req->grant, 0)) != OK) {
277 pbuf_free(pbuf);
278 return ret;
281 if (sock->usr_flags & NWUO_RWDATONLY)
282 ret = udp_op_send(sock, pbuf, req->size);
283 else
284 ret = udp_op_sendto(sock, pbuf, req->size);
286 if (pbuf_free(pbuf) == 0) {
287 panic("We cannot buffer udp packets yet!");
290 return ret;
293 static int udp_set_opt(struct socket * sock, endpoint_t endpt,
294 cp_grant_id_t grant)
296 int err;
297 nwio_udpopt_t udpopt;
298 struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
299 ip_addr_t loc_ip = ip_addr_any;
301 assert(pcb);
303 err = copy_from_user(endpt, &udpopt, sizeof(udpopt), grant, 0);
305 if (err != OK)
306 return err;
308 debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
309 debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
310 (unsigned int) udpopt.nwuo_remaddr);
311 debug_udp_print("udpopt.nwuo_remport = 0x%x",
312 ntohs(udpopt.nwuo_remport));
313 debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
314 (unsigned int) udpopt.nwuo_locaddr);
315 debug_udp_print("udpopt.nwuo_locport = 0x%x",
316 ntohs(udpopt.nwuo_locport));
318 sock->usr_flags = udpopt.nwuo_flags;
321 * We will only get data from userspace and the remote address
322 * and port are being set which means that from now on we must
323 * know where to send data. Thus we should interpret this as
324 * connect() call
326 if (sock->usr_flags & NWUO_RWDATONLY &&
327 sock->usr_flags & NWUO_RP_SET &&
328 sock->usr_flags & NWUO_RA_SET)
329 udp_connect(pcb, (ip_addr_t *) &udpopt.nwuo_remaddr,
330 ntohs(udpopt.nwuo_remport));
331 /* Setting local address means binding */
332 if (sock->usr_flags & NWUO_LP_SET)
333 udp_bind(pcb, &loc_ip, ntohs(udpopt.nwuo_locport));
334 /* We can only bind to random local port */
335 if (sock->usr_flags & NWUO_LP_SEL)
336 udp_bind(pcb, &loc_ip, 0);
338 /* register a receive hook */
339 udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock);
341 return OK;
344 static int udp_get_opt(struct socket * sock, endpoint_t endpt,
345 cp_grant_id_t grant)
347 nwio_udpopt_t udpopt;
348 struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
350 assert(pcb);
352 udpopt.nwuo_locaddr = pcb->local_ip.addr;
353 udpopt.nwuo_locport = htons(pcb->local_port);
354 udpopt.nwuo_remaddr = pcb->remote_ip.addr;
355 udpopt.nwuo_remport = htons(pcb->remote_port);
356 udpopt.nwuo_flags = sock->usr_flags;
358 debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
359 debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
360 (unsigned int) udpopt.nwuo_remaddr);
361 debug_udp_print("udpopt.nwuo_remport = 0x%x",
362 ntohs(udpopt.nwuo_remport));
363 debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
364 (unsigned int) udpopt.nwuo_locaddr);
365 debug_udp_print("udpopt.nwuo_locport = 0x%x",
366 ntohs(udpopt.nwuo_locport));
368 return copy_to_user(endpt, &udpopt, sizeof(udpopt), grant, 0);
371 static int udp_op_ioctl(struct socket * sock, struct sock_req * req,
372 __unused int blk)
374 int r;
376 debug_udp_print("socket num %ld req %c %ld %ld",
377 get_sock_num(sock),
378 (unsigned char) (req->req >> 8),
379 req->req & 0xff, _MINIX_IOCTL_SIZE(req->req));
381 switch (req->req) {
382 case NWIOSUDPOPT:
383 r = udp_set_opt(sock, req->endpt, req->grant);
384 break;
385 case NWIOGUDPOPT:
386 r = udp_get_opt(sock, req->endpt, req->grant);
387 break;
388 default:
389 r = ENOTTY;
392 return r;
395 struct sock_ops sock_udp_ops = {
396 .open = udp_op_open,
397 .close = udp_op_close,
398 .read = udp_op_read,
399 .write = udp_op_write,
400 .ioctl = udp_op_ioctl,
401 .select = generic_op_select,
402 .select_reply = generic_op_select_reply