minor fixes for safecopy & safemap tests
[minix.git] / servers / lwip / udp.c
blob38ca29ce3883d96409cbcee003e54e8729609197
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, __unused message * m)
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 void udp_op_close(struct socket * sock, __unused message * m)
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 sock_reply_close(sock, OK);
78 static int udp_do_receive(struct socket * sock,
79 message * m,
80 struct udp_pcb *pcb,
81 struct pbuf *pbuf,
82 ip_addr_t *addr,
83 u16_t port)
85 struct pbuf * p;
86 unsigned rem_len = m->COUNT;
87 unsigned written = 0, hdr_sz = 0;
88 int err;
90 debug_udp_print("user buffer size : %d", 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(m->m_source,
105 &hdr, sizeof(hdr),
106 (cp_grant_id_t) m->IO_GRANT,
109 if (err != OK)
110 return err;
112 rem_len -= (hdr_sz = sizeof(hdr));
115 for (p = pbuf; p && rem_len; p = p->next) {
116 size_t cp_len;
118 cp_len = (rem_len < p->len) ? rem_len : p->len;
119 err = copy_to_user(m->m_source, p->payload, cp_len,
120 (cp_grant_id_t) m->IO_GRANT,
121 hdr_sz + written);
123 if (err != OK)
124 return err;
126 written += cp_len;
127 rem_len -= cp_len;
130 debug_udp_print("copied %d bytes", written + hdr_sz);
131 return written + hdr_sz;
134 static void udp_recv_callback(void *arg,
135 struct udp_pcb *pcb,
136 struct pbuf *pbuf,
137 ip_addr_t *addr,
138 u16_t port)
140 struct socket * sock = (struct socket *) arg;
141 struct udp_recv_data * data;
143 debug_udp_print("socket num : %ld addr : %x port : %d\n",
144 get_sock_num(sock), (unsigned int) addr->addr, port);
146 if (sock->flags & SOCK_FLG_OP_PENDING) {
147 /* we are resuming a suspended operation */
148 int ret;
150 ret = udp_do_receive(sock, &sock->mess, pcb, pbuf, addr, port);
152 if (ret > 0) {
153 pbuf_free(pbuf);
154 sock_reply(sock, ret);
155 sock->flags &= ~SOCK_FLG_OP_PENDING;
156 return;
157 } else {
158 sock_reply(sock, ret);
159 sock->flags &= ~SOCK_FLG_OP_PENDING;
163 /* Do not enqueue more data than allowed */
164 if (sock->recv_data_size > UDP_BUF_SIZE) {
165 pbuf_free(pbuf);
166 return;
170 * nobody is waiting for the data or an error occured above, we enqueue
171 * the packet
173 if (!(data = udp_recv_alloc())) {
174 pbuf_free(pbuf);
175 return;
178 data->ip = *addr;
179 data->port = port;
180 data->pbuf = pbuf;
182 if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
183 udp_recv_free(data);
184 return;
188 * We don't need to notify when somebody is already waiting, reviving
189 * read operation will do the trick for us. But we must announce new
190 * data available here.
192 if (sock_select_read_set(sock))
193 sock_select_notify(sock);
196 static void udp_op_read(struct socket * sock, message * m, int blk)
198 debug_udp_print("socket num %ld", get_sock_num(sock));
200 if (sock->recv_head) {
201 /* data available receive immeditely */
203 struct udp_recv_data * data;
204 int ret;
206 data = (struct udp_recv_data *) sock->recv_head->data;
208 ret = udp_do_receive(sock, m, (struct udp_pcb *) sock->pcb,
209 data->pbuf, &data->ip, data->port);
211 if (ret > 0) {
212 sock_dequeue_data(sock);
213 sock->recv_data_size -= data->pbuf->tot_len;
214 udp_recv_free(data);
216 sock_reply(sock, ret);
217 } else if (!blk)
218 sock_reply(sock, EAGAIN);
219 else {
220 /* store the message so we know how to reply */
221 sock->mess = *m;
222 /* operation is being processes */
223 sock->flags |= SOCK_FLG_OP_PENDING;
225 debug_udp_print("no data to read, suspending\n");
229 static int udp_op_send(struct socket * sock,
230 struct pbuf * pbuf,
231 message * m)
233 int err;
235 debug_udp_print("pbuf len %d\n", pbuf->len);
237 if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK)
238 return m->COUNT;
239 else {
240 debug_udp_print("udp_send failed %d", err);
241 return EIO;
245 static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, message * m)
247 int err;
248 udp_io_hdr_t hdr;
250 hdr = *(udp_io_hdr_t *) pbuf->payload;
252 pbuf_header(pbuf, -(s16_t)sizeof(udp_io_hdr_t));
254 debug_udp_print("data len %d pbuf len %d\n",
255 hdr.uih_data_len, pbuf->len);
257 if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr,
258 ntohs(hdr.uih_dst_port))) == ERR_OK)
259 return m->COUNT;
260 else {
261 debug_udp_print("udp_sendto failed %d", err);
262 return EIO;
266 static void udp_op_write(struct socket * sock, message * m, __unused int blk)
268 int ret;
269 struct pbuf * pbuf;
271 debug_udp_print("socket num %ld data size %d",
272 get_sock_num(sock), m->COUNT);
274 pbuf = pbuf_alloc(PBUF_TRANSPORT, m->COUNT, PBUF_POOL);
275 if (!pbuf) {
276 ret = ENOMEM;
277 goto write_err;
280 if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT,
281 (cp_grant_id_t) m->IO_GRANT, 0)) != OK) {
282 pbuf_free(pbuf);
283 goto write_err;
286 if (sock->usr_flags & NWUO_RWDATONLY)
287 ret = udp_op_send(sock, pbuf, m);
288 else
289 ret = udp_op_sendto(sock, pbuf, m);
291 if (pbuf_free(pbuf) == 0) {
292 panic("We cannot buffer udp packets yet!");
295 write_err:
296 sock_reply(sock, ret);
299 static void udp_set_opt(struct socket * sock, message * m)
301 int err;
302 nwio_udpopt_t udpopt;
303 struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
304 ip_addr_t loc_ip = ip_addr_any;
306 assert(pcb);
308 err = copy_from_user(m->m_source, &udpopt, sizeof(udpopt),
309 (cp_grant_id_t) m->IO_GRANT, 0);
311 if (err != OK)
312 sock_reply(sock, err);
314 debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
315 debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
316 (unsigned int) udpopt.nwuo_remaddr);
317 debug_udp_print("udpopt.nwuo_remport = 0x%x",
318 ntohs(udpopt.nwuo_remport));
319 debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
320 (unsigned int) udpopt.nwuo_locaddr);
321 debug_udp_print("udpopt.nwuo_locport = 0x%x",
322 ntohs(udpopt.nwuo_locport));
324 sock->usr_flags = udpopt.nwuo_flags;
327 * We will only get data from userspace and the remote address
328 * and port are being set which means that from now on we must
329 * know where to send data. Thus we should interpret this as
330 * connect() call
332 if (sock->usr_flags & NWUO_RWDATONLY &&
333 sock->usr_flags & NWUO_RP_SET &&
334 sock->usr_flags & NWUO_RA_SET)
335 udp_connect(pcb, (ip_addr_t *) &udpopt.nwuo_remaddr,
336 ntohs(udpopt.nwuo_remport));
337 /* Setting local address means binding */
338 if (sock->usr_flags & NWUO_LP_SET)
339 udp_bind(pcb, &loc_ip, ntohs(udpopt.nwuo_locport));
340 /* We can only bind to random local port */
341 if (sock->usr_flags & NWUO_LP_SEL)
342 udp_bind(pcb, &loc_ip, 0);
345 /* register a receive hook */
346 udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock);
348 sock_reply(sock, OK);
351 static void udp_get_opt(struct socket * sock, message * m)
353 int err;
354 nwio_udpopt_t udpopt;
355 struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
357 assert(pcb);
359 udpopt.nwuo_locaddr = pcb->local_ip.addr;
360 udpopt.nwuo_locport = htons(pcb->local_port);
361 udpopt.nwuo_remaddr = pcb->remote_ip.addr;
362 udpopt.nwuo_remport = htons(pcb->remote_port);
363 udpopt.nwuo_flags = sock->usr_flags;
365 debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
366 debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
367 (unsigned int) udpopt.nwuo_remaddr);
368 debug_udp_print("udpopt.nwuo_remport = 0x%x",
369 ntohs(udpopt.nwuo_remport));
370 debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
371 (unsigned int) udpopt.nwuo_locaddr);
372 debug_udp_print("udpopt.nwuo_locport = 0x%x",
373 ntohs(udpopt.nwuo_locport));
375 if ((unsigned) m->COUNT < sizeof(udpopt)) {
376 sock_reply(sock, EINVAL);
377 return;
380 err = copy_to_user(m->m_source, &udpopt, sizeof(udpopt),
381 (cp_grant_id_t) m->IO_GRANT, 0);
383 if (err != OK)
384 sock_reply(sock, err);
386 sock_reply(sock, OK);
389 static void udp_op_ioctl(struct socket * sock, message * m, __unused int blk)
391 debug_udp_print("socket num %ld req %c %d %d",
392 get_sock_num(sock),
393 (m->REQUEST >> 8) & 0xff,
394 m->REQUEST & 0xff,
395 (m->REQUEST >> 16) & _IOCPARM_MASK);
397 switch (m->REQUEST) {
398 case NWIOSUDPOPT:
399 udp_set_opt(sock, m);
400 break;
401 case NWIOGUDPOPT:
402 udp_get_opt(sock, m);
403 break;
404 default:
405 sock_reply(sock, EBADIOCTL);
406 return;
410 struct sock_ops sock_udp_ops = {
411 .open = udp_op_open,
412 .close = udp_op_close,
413 .read = udp_op_read,
414 .write = udp_op_write,
415 .ioctl = udp_op_ioctl,
416 .select = generic_op_select,
417 .select_reply = generic_op_select_reply