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>
12 #include <lwip/ip_addr.h>
14 #include <minix/netsock.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)
23 #define debug_udp_print(str, ...) printf("LWIP %s:%d : " str "\n", \
24 __func__, __LINE__, ##__VA_ARGS__)
26 #define debug_udp_print(...) debug_print(__VA_ARGS__)
29 struct udp_recv_data
{
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
);
44 static int udp_op_open(struct socket
* sock
, __unused message
* m
)
48 debug_udp_print("socket num %ld", get_sock_num(sock
));
50 if (!(pcb
= udp_new()))
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
);
69 udp_remove(sock
->pcb
);
70 assert(sock
->buf
== NULL
);
72 /* mark it as unused */
75 sock_reply_close(sock
, OK
);
78 static int udp_do_receive(struct socket
* sock
,
86 unsigned rem_len
= m
->COUNT
;
87 unsigned written
= 0, hdr_sz
= 0;
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
)) {
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
,
106 (cp_grant_id_t
) m
->IO_GRANT
,
112 rem_len
-= (hdr_sz
= sizeof(hdr
));
115 for (p
= pbuf
; p
&& rem_len
; p
= p
->next
) {
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
,
130 debug_udp_print("copied %d bytes", written
+ hdr_sz
);
131 return written
+ hdr_sz
;
134 static void udp_recv_callback(void *arg
,
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 */
150 ret
= udp_do_receive(sock
, &sock
->mess
, pcb
, pbuf
, addr
, port
);
154 sock_reply(sock
, ret
);
155 sock
->flags
&= ~SOCK_FLG_OP_PENDING
;
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
) {
170 * nobody is waiting for the data or an error occured above, we enqueue
173 if (!(data
= udp_recv_alloc())) {
182 if (sock_enqueue_data(sock
, data
, data
->pbuf
->tot_len
) != OK
) {
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
;
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
);
212 sock_dequeue_data(sock
);
213 sock
->recv_data_size
-= data
->pbuf
->tot_len
;
216 sock_reply(sock
, ret
);
218 sock_reply(sock
, EAGAIN
);
220 /* store the message so we know how to reply */
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
,
235 debug_udp_print("pbuf len %d\n", pbuf
->len
);
237 if ((err
= udp_send(sock
->pcb
, pbuf
)) == ERR_OK
)
240 debug_udp_print("udp_send failed %d", err
);
245 static int udp_op_sendto(struct socket
* sock
, struct pbuf
* pbuf
, message
* m
)
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
)
261 debug_udp_print("udp_sendto failed %d", err
);
266 static void udp_op_write(struct socket
* sock
, message
* m
, __unused
int blk
)
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
);
280 if ((ret
= copy_from_user(m
->m_source
, pbuf
->payload
, m
->COUNT
,
281 (cp_grant_id_t
) m
->IO_GRANT
, 0)) != OK
) {
286 if (sock
->usr_flags
& NWUO_RWDATONLY
)
287 ret
= udp_op_send(sock
, pbuf
, m
);
289 ret
= udp_op_sendto(sock
, pbuf
, m
);
291 if (pbuf_free(pbuf
) == 0) {
292 panic("We cannot buffer udp packets yet!");
296 sock_reply(sock
, ret
);
299 static void udp_set_opt(struct socket
* sock
, message
* m
)
302 nwio_udpopt_t udpopt
;
303 struct udp_pcb
* pcb
= (struct udp_pcb
*) sock
->pcb
;
304 ip_addr_t loc_ip
= ip_addr_any
;
308 err
= copy_from_user(m
->m_source
, &udpopt
, sizeof(udpopt
),
309 (cp_grant_id_t
) m
->IO_GRANT
, 0);
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
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
)
354 nwio_udpopt_t udpopt
;
355 struct udp_pcb
* pcb
= (struct udp_pcb
*) sock
->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
);
380 err
= copy_to_user(m
->m_source
, &udpopt
, sizeof(udpopt
),
381 (cp_grant_id_t
) m
->IO_GRANT
, 0);
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",
393 (m
->REQUEST
>> 8) & 0xff,
395 (m
->REQUEST
>> 16) & _IOCPARM_MASK
);
397 switch (m
->REQUEST
) {
399 udp_set_opt(sock
, m
);
402 udp_get_opt(sock
, m
);
405 sock_reply(sock
, EBADIOCTL
);
410 struct sock_ops sock_udp_ops
= {
412 .close
= udp_op_close
,
414 .write
= udp_op_write
,
415 .ioctl
= udp_op_ioctl
,
416 .select
= generic_op_select
,
417 .select_reply
= generic_op_select_reply