PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/lwip/udp.c

http://www.minix3.org/
C | 419 lines | 305 code | 88 blank | 26 comment | 45 complexity | 502fbc2cd8900a799b1f76ce2d40b03b MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. #include <stdlib.h>
  2. #include <minix/sysutil.h>
  3. #include <sys/ioc_net.h>
  4. #include <net/gen/in.h>
  5. #include <net/gen/udp.h>
  6. #include <net/gen/udp_io.h>
  7. #include <net/gen/udp_io_hdr.h>
  8. #include <lwip/udp.h>
  9. #include <lwip/ip_addr.h>
  10. #include <minix/netsock.h>
  11. #include "proto.h"
  12. #define UDP_BUF_SIZE (4 << 10)
  13. #define sock_alloc_buf(s) debug_malloc(s)
  14. #define sock_free_buf(x) debug_free(x)
  15. #if 0
  16. #define debug_udp_print(str, ...) printf("LWIP %s:%d : " str "\n", \
  17. __func__, __LINE__, ##__VA_ARGS__)
  18. #else
  19. #define debug_udp_print(...) debug_print(__VA_ARGS__)
  20. #endif
  21. struct udp_recv_data {
  22. ip_addr_t ip;
  23. u16_t port;
  24. struct pbuf * pbuf;
  25. };
  26. #define udp_recv_alloc() debug_malloc(sizeof(struct udp_recv_data))
  27. static void udp_recv_free(void * data)
  28. {
  29. if (((struct udp_recv_data *)data)->pbuf)
  30. pbuf_free(((struct udp_recv_data *)data)->pbuf);
  31. debug_free(data);
  32. }
  33. static int udp_op_open(struct socket * sock, __unused message * m)
  34. {
  35. struct udp_pcb * pcb;
  36. debug_udp_print("socket num %ld", get_sock_num(sock));
  37. if (!(pcb = udp_new()))
  38. return ENOMEM;
  39. sock->buf = NULL;
  40. sock->buf_size = 0;
  41. sock->pcb = pcb;
  42. return OK;
  43. }
  44. static void udp_op_close(struct socket * sock, __unused message * m)
  45. {
  46. debug_udp_print("socket num %ld", get_sock_num(sock));
  47. /* deque and free all enqueued data before closing */
  48. sock_dequeue_data_all(sock, udp_recv_free);
  49. if (sock->pcb)
  50. udp_remove(sock->pcb);
  51. assert(sock->buf == NULL);
  52. /* mark it as unused */
  53. sock->ops = NULL;
  54. sock_reply_close(sock, OK);
  55. }
  56. static int udp_do_receive(struct socket * sock,
  57. message * m,
  58. struct udp_pcb *pcb,
  59. struct pbuf *pbuf,
  60. ip_addr_t *addr,
  61. u16_t port)
  62. {
  63. struct pbuf * p;
  64. unsigned rem_len = m->COUNT;
  65. unsigned written = 0, hdr_sz = 0;
  66. int err;
  67. debug_udp_print("user buffer size : %d", rem_len);
  68. /* FIXME make it both a single copy */
  69. if (!(sock->usr_flags & NWUO_RWDATONLY)) {
  70. udp_io_hdr_t hdr;
  71. hdr.uih_src_addr = addr->addr;
  72. hdr.uih_src_port = htons(port);
  73. hdr.uih_dst_addr = pcb->local_ip.addr;
  74. hdr.uih_dst_port = htons(pcb->local_port);
  75. hdr.uih_data_len = 0;
  76. hdr.uih_ip_opt_len = 0;
  77. err = copy_to_user(m->m_source,
  78. &hdr, sizeof(hdr),
  79. (cp_grant_id_t) m->IO_GRANT,
  80. 0);
  81. if (err != OK)
  82. return err;
  83. rem_len -= (hdr_sz = sizeof(hdr));
  84. }
  85. for (p = pbuf; p && rem_len; p = p->next) {
  86. size_t cp_len;
  87. cp_len = (rem_len < p->len) ? rem_len : p->len;
  88. err = copy_to_user(m->m_source, p->payload, cp_len,
  89. (cp_grant_id_t) m->IO_GRANT,
  90. hdr_sz + written);
  91. if (err != OK)
  92. return err;
  93. written += cp_len;
  94. rem_len -= cp_len;
  95. }
  96. debug_udp_print("copied %d bytes", written + hdr_sz);
  97. return written + hdr_sz;
  98. }
  99. static void udp_recv_callback(void *arg,
  100. struct udp_pcb *pcb,
  101. struct pbuf *pbuf,
  102. ip_addr_t *addr,
  103. u16_t port)
  104. {
  105. struct socket * sock = (struct socket *) arg;
  106. struct udp_recv_data * data;
  107. debug_udp_print("socket num : %ld addr : %x port : %d\n",
  108. get_sock_num(sock), (unsigned int) addr->addr, port);
  109. if (sock->flags & SOCK_FLG_OP_PENDING) {
  110. /* we are resuming a suspended operation */
  111. int ret;
  112. ret = udp_do_receive(sock, &sock->mess, pcb, pbuf, addr, port);
  113. if (ret > 0) {
  114. pbuf_free(pbuf);
  115. sock_reply(sock, ret);
  116. sock->flags &= ~SOCK_FLG_OP_PENDING;
  117. return;
  118. } else {
  119. sock_reply(sock, ret);
  120. sock->flags &= ~SOCK_FLG_OP_PENDING;
  121. }
  122. }
  123. /* Do not enqueue more data than allowed */
  124. if (sock->recv_data_size > UDP_BUF_SIZE) {
  125. pbuf_free(pbuf);
  126. return;
  127. }
  128. /*
  129. * nobody is waiting for the data or an error occured above, we enqueue
  130. * the packet
  131. */
  132. if (!(data = udp_recv_alloc())) {
  133. pbuf_free(pbuf);
  134. return;
  135. }
  136. data->ip = *addr;
  137. data->port = port;
  138. data->pbuf = pbuf;
  139. if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
  140. udp_recv_free(data);
  141. return;
  142. }
  143. /*
  144. * We don't need to notify when somebody is already waiting, reviving
  145. * read operation will do the trick for us. But we must announce new
  146. * data available here.
  147. */
  148. if (sock_select_read_set(sock))
  149. sock_select_notify(sock);
  150. }
  151. static void udp_op_read(struct socket * sock, message * m, int blk)
  152. {
  153. debug_udp_print("socket num %ld", get_sock_num(sock));
  154. if (sock->recv_head) {
  155. /* data available receive immeditely */
  156. struct udp_recv_data * data;
  157. int ret;
  158. data = (struct udp_recv_data *) sock->recv_head->data;
  159. ret = udp_do_receive(sock, m, (struct udp_pcb *) sock->pcb,
  160. data->pbuf, &data->ip, data->port);
  161. if (ret > 0) {
  162. sock_dequeue_data(sock);
  163. sock->recv_data_size -= data->pbuf->tot_len;
  164. udp_recv_free(data);
  165. }
  166. sock_reply(sock, ret);
  167. } else if (!blk)
  168. sock_reply(sock, EAGAIN);
  169. else {
  170. /* store the message so we know how to reply */
  171. sock->mess = *m;
  172. /* operation is being processes */
  173. sock->flags |= SOCK_FLG_OP_PENDING;
  174. debug_udp_print("no data to read, suspending\n");
  175. }
  176. }
  177. static int udp_op_send(struct socket * sock,
  178. struct pbuf * pbuf,
  179. message * m)
  180. {
  181. int err;
  182. debug_udp_print("pbuf len %d\n", pbuf->len);
  183. if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK)
  184. return m->COUNT;
  185. else {
  186. debug_udp_print("udp_send failed %d", err);
  187. return EIO;
  188. }
  189. }
  190. static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, message * m)
  191. {
  192. int err;
  193. udp_io_hdr_t hdr;
  194. hdr = *(udp_io_hdr_t *) pbuf->payload;
  195. pbuf_header(pbuf, -(s16_t)sizeof(udp_io_hdr_t));
  196. debug_udp_print("data len %d pbuf len %d\n",
  197. hdr.uih_data_len, pbuf->len);
  198. if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr,
  199. ntohs(hdr.uih_dst_port))) == ERR_OK)
  200. return m->COUNT;
  201. else {
  202. debug_udp_print("udp_sendto failed %d", err);
  203. return EIO;
  204. }
  205. }
  206. static void udp_op_write(struct socket * sock, message * m, __unused int blk)
  207. {
  208. int ret;
  209. struct pbuf * pbuf;
  210. debug_udp_print("socket num %ld data size %d",
  211. get_sock_num(sock), m->COUNT);
  212. pbuf = pbuf_alloc(PBUF_TRANSPORT, m->COUNT, PBUF_POOL);
  213. if (!pbuf) {
  214. ret = ENOMEM;
  215. goto write_err;
  216. }
  217. if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT,
  218. (cp_grant_id_t) m->IO_GRANT, 0)) != OK) {
  219. pbuf_free(pbuf);
  220. goto write_err;
  221. }
  222. if (sock->usr_flags & NWUO_RWDATONLY)
  223. ret = udp_op_send(sock, pbuf, m);
  224. else
  225. ret = udp_op_sendto(sock, pbuf, m);
  226. if (pbuf_free(pbuf) == 0) {
  227. panic("We cannot buffer udp packets yet!");
  228. }
  229. write_err:
  230. sock_reply(sock, ret);
  231. }
  232. static void udp_set_opt(struct socket * sock, message * m)
  233. {
  234. int err;
  235. nwio_udpopt_t udpopt;
  236. struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
  237. ip_addr_t loc_ip = ip_addr_any;
  238. assert(pcb);
  239. err = copy_from_user(m->m_source, &udpopt, sizeof(udpopt),
  240. (cp_grant_id_t) m->IO_GRANT, 0);
  241. if (err != OK)
  242. sock_reply(sock, err);
  243. debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
  244. debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
  245. (unsigned int) udpopt.nwuo_remaddr);
  246. debug_udp_print("udpopt.nwuo_remport = 0x%x",
  247. ntohs(udpopt.nwuo_remport));
  248. debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
  249. (unsigned int) udpopt.nwuo_locaddr);
  250. debug_udp_print("udpopt.nwuo_locport = 0x%x",
  251. ntohs(udpopt.nwuo_locport));
  252. sock->usr_flags = udpopt.nwuo_flags;
  253. /*
  254. * We will only get data from userspace and the remote address
  255. * and port are being set which means that from now on we must
  256. * know where to send data. Thus we should interpret this as
  257. * connect() call
  258. */
  259. if (sock->usr_flags & NWUO_RWDATONLY &&
  260. sock->usr_flags & NWUO_RP_SET &&
  261. sock->usr_flags & NWUO_RA_SET)
  262. udp_connect(pcb, (ip_addr_t *) &udpopt.nwuo_remaddr,
  263. ntohs(udpopt.nwuo_remport));
  264. /* Setting local address means binding */
  265. if (sock->usr_flags & NWUO_LP_SET)
  266. udp_bind(pcb, &loc_ip, ntohs(udpopt.nwuo_locport));
  267. /* We can only bind to random local port */
  268. if (sock->usr_flags & NWUO_LP_SEL)
  269. udp_bind(pcb, &loc_ip, 0);
  270. /* register a receive hook */
  271. udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock);
  272. sock_reply(sock, OK);
  273. }
  274. static void udp_get_opt(struct socket * sock, message * m)
  275. {
  276. int err;
  277. nwio_udpopt_t udpopt;
  278. struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
  279. assert(pcb);
  280. udpopt.nwuo_locaddr = pcb->local_ip.addr;
  281. udpopt.nwuo_locport = htons(pcb->local_port);
  282. udpopt.nwuo_remaddr = pcb->remote_ip.addr;
  283. udpopt.nwuo_remport = htons(pcb->remote_port);
  284. udpopt.nwuo_flags = sock->usr_flags;
  285. debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
  286. debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
  287. (unsigned int) udpopt.nwuo_remaddr);
  288. debug_udp_print("udpopt.nwuo_remport = 0x%x",
  289. ntohs(udpopt.nwuo_remport));
  290. debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
  291. (unsigned int) udpopt.nwuo_locaddr);
  292. debug_udp_print("udpopt.nwuo_locport = 0x%x",
  293. ntohs(udpopt.nwuo_locport));
  294. if ((unsigned) m->COUNT < sizeof(udpopt)) {
  295. sock_reply(sock, EINVAL);
  296. return;
  297. }
  298. err = copy_to_user(m->m_source, &udpopt, sizeof(udpopt),
  299. (cp_grant_id_t) m->IO_GRANT, 0);
  300. if (err != OK)
  301. sock_reply(sock, err);
  302. sock_reply(sock, OK);
  303. }
  304. static void udp_op_ioctl(struct socket * sock, message * m, __unused int blk)
  305. {
  306. debug_udp_print("socket num %ld req %c %d %d",
  307. get_sock_num(sock),
  308. (m->REQUEST >> 8) & 0xff,
  309. m->REQUEST & 0xff,
  310. (m->REQUEST >> 16) & _IOCPARM_MASK);
  311. switch (m->REQUEST) {
  312. case NWIOSUDPOPT:
  313. udp_set_opt(sock, m);
  314. break;
  315. case NWIOGUDPOPT:
  316. udp_get_opt(sock, m);
  317. break;
  318. default:
  319. sock_reply(sock, EBADIOCTL);
  320. return;
  321. }
  322. }
  323. struct sock_ops sock_udp_ops = {
  324. .open = udp_op_open,
  325. .close = udp_op_close,
  326. .read = udp_op_read,
  327. .write = udp_op_write,
  328. .ioctl = udp_op_ioctl,
  329. .select = generic_op_select,
  330. .select_reply = generic_op_select_reply
  331. };