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
)
48 debug_udp_print("socket num %ld", get_sock_num(sock
));
50 if (!(pcb
= udp_new()))
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
);
69 udp_remove(sock
->pcb
);
70 assert(sock
->buf
== NULL
);
72 /* mark it as unused */
78 static int udp_do_receive(struct socket
* sock
,
79 struct sock_req
* req
,
86 size_t rem_len
= req
->size
;
87 unsigned int written
= 0, hdr_sz
= 0;
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
)) {
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
,
110 rem_len
-= (hdr_sz
= sizeof(hdr
));
113 for (p
= pbuf
; p
&& rem_len
; p
= p
->next
) {
116 cp_len
= (rem_len
< p
->len
) ? rem_len
: p
->len
;
117 err
= copy_to_user(req
->endpt
, p
->payload
, cp_len
, req
->grant
,
127 debug_udp_print("copied %d bytes", written
+ hdr_sz
);
128 return written
+ hdr_sz
;
131 static void udp_recv_callback(void *arg
,
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 */
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
;
158 /* Do not enqueue more data than allowed */
159 if (sock
->recv_data_size
> UDP_BUF_SIZE
) {
165 * nobody is waiting for the data or an error occured above, we enqueue
168 if (!(data
= udp_recv_alloc())) {
177 if (sock_enqueue_data(sock
, data
, data
->pbuf
->tot_len
) != OK
) {
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
;
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
);
207 sock_dequeue_data(sock
);
208 sock
->recv_data_size
-= data
->pbuf
->tot_len
;
215 /* store the message so we know how to reply */
217 /* operation is being processes */
218 sock
->flags
|= SOCK_FLG_OP_PENDING
;
220 debug_udp_print("no data to read, suspending\n");
225 static int udp_op_send(struct socket
* sock
,
231 debug_udp_print("pbuf len %d\n", pbuf
->len
);
233 if ((err
= udp_send(sock
->pcb
, pbuf
)) == ERR_OK
)
236 debug_udp_print("udp_send failed %d", err
);
241 static int udp_op_sendto(struct socket
* sock
, struct pbuf
* pbuf
, size_t size
)
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
)
257 debug_udp_print("udp_sendto failed %d", err
);
262 static int udp_op_write(struct socket
* sock
, struct sock_req
* req
,
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
);
275 if ((ret
= copy_from_user(req
->endpt
, pbuf
->payload
, req
->size
,
276 req
->grant
, 0)) != OK
) {
281 if (sock
->usr_flags
& NWUO_RWDATONLY
)
282 ret
= udp_op_send(sock
, pbuf
, req
->size
);
284 ret
= udp_op_sendto(sock
, pbuf
, req
->size
);
286 if (pbuf_free(pbuf
) == 0) {
287 panic("We cannot buffer udp packets yet!");
293 static int udp_set_opt(struct socket
* sock
, endpoint_t endpt
,
297 nwio_udpopt_t udpopt
;
298 struct udp_pcb
* pcb
= (struct udp_pcb
*) sock
->pcb
;
299 ip_addr_t loc_ip
= ip_addr_any
;
303 err
= copy_from_user(endpt
, &udpopt
, sizeof(udpopt
), grant
, 0);
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
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
);
344 static int udp_get_opt(struct socket
* sock
, endpoint_t endpt
,
347 nwio_udpopt_t udpopt
;
348 struct udp_pcb
* pcb
= (struct udp_pcb
*) sock
->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
,
376 debug_udp_print("socket num %ld req %c %ld %ld",
378 (unsigned char) (req
->req
>> 8),
379 req
->req
& 0xff, _MINIX_IOCTL_SIZE(req
->req
));
383 r
= udp_set_opt(sock
, req
->endpt
, req
->grant
);
386 r
= udp_get_opt(sock
, req
->endpt
, req
->grant
);
395 struct sock_ops sock_udp_ops
= {
397 .close
= udp_op_close
,
399 .write
= udp_op_write
,
400 .ioctl
= udp_op_ioctl
,
401 .select
= generic_op_select
,
402 .select_reply
= generic_op_select_reply