PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

servers/lwip/udp.c

http://www.minix3.org/
C | 418 lines | 304 code | 88 blank | 26 comment | 43 complexity | cc400f58204b717164b677fc02c5eb53 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 "socket.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(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_revive(sock, ret);
  116. sock->flags &= ~SOCK_FLG_OP_PENDING;
  117. return;
  118. } else {
  119. sock_revive(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)
  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 {
  168. /* store the message so we know how to reply */
  169. sock->mess = *m;
  170. /* operation is being processes */
  171. sock->flags |= SOCK_FLG_OP_PENDING;
  172. debug_udp_print("no data to read, suspending\n");
  173. sock_reply(sock, SUSPEND);
  174. }
  175. }
  176. static int udp_op_send(struct socket * sock,
  177. struct pbuf * pbuf,
  178. message * m)
  179. {
  180. int err;
  181. debug_udp_print("pbuf len %d\n", pbuf->len);
  182. if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK)
  183. return m->COUNT;
  184. else {
  185. debug_udp_print("udp_send failed %d", err);
  186. return EIO;
  187. }
  188. }
  189. static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, message * m)
  190. {
  191. int err;
  192. udp_io_hdr_t hdr;
  193. hdr = *(udp_io_hdr_t *) pbuf->payload;
  194. pbuf_header(pbuf, -(s16_t)sizeof(udp_io_hdr_t));
  195. debug_udp_print("data len %d pbuf len %d\n",
  196. hdr.uih_data_len, pbuf->len);
  197. if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr,
  198. ntohs(hdr.uih_dst_port))) == ERR_OK)
  199. return m->COUNT;
  200. else {
  201. debug_udp_print("udp_sendto failed %d", err);
  202. return EIO;
  203. }
  204. }
  205. static void udp_op_write(struct socket * sock, message * m)
  206. {
  207. int ret;
  208. struct pbuf * pbuf;
  209. debug_udp_print("socket num %ld data size %d",
  210. get_sock_num(sock), m->COUNT);
  211. pbuf = pbuf_alloc(PBUF_TRANSPORT, m->COUNT, PBUF_POOL);
  212. if (!pbuf) {
  213. ret = ENOMEM;
  214. goto write_err;
  215. }
  216. if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT,
  217. (cp_grant_id_t) m->IO_GRANT, 0)) != OK) {
  218. pbuf_free(pbuf);
  219. goto write_err;
  220. }
  221. if (sock->usr_flags & NWUO_RWDATONLY)
  222. ret = udp_op_send(sock, pbuf, m);
  223. else
  224. ret = udp_op_sendto(sock, pbuf, m);
  225. if (pbuf_free(pbuf) == 0) {
  226. panic("We cannot buffer udp packets yet!");
  227. }
  228. write_err:
  229. sock_reply(sock, ret);
  230. }
  231. static void udp_set_opt(struct socket * sock, message * m)
  232. {
  233. int err;
  234. nwio_udpopt_t udpopt;
  235. struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
  236. ip_addr_t loc_ip = ip_addr_any;
  237. assert(pcb);
  238. err = copy_from_user(m->m_source, &udpopt, sizeof(udpopt),
  239. (cp_grant_id_t) m->IO_GRANT, 0);
  240. if (err != OK)
  241. sock_reply(sock, err);
  242. debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
  243. debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
  244. (unsigned int) udpopt.nwuo_remaddr);
  245. debug_udp_print("udpopt.nwuo_remport = 0x%x",
  246. ntohs(udpopt.nwuo_remport));
  247. debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
  248. (unsigned int) udpopt.nwuo_locaddr);
  249. debug_udp_print("udpopt.nwuo_locport = 0x%x",
  250. ntohs(udpopt.nwuo_locport));
  251. sock->usr_flags = udpopt.nwuo_flags;
  252. /*
  253. * We will only get data from userspace and the remote address
  254. * and port are being set which means that from now on we must
  255. * know where to send data. Thus we should interpret this as
  256. * connect() call
  257. */
  258. if (sock->usr_flags & NWUO_RWDATONLY &&
  259. sock->usr_flags & NWUO_RP_SET &&
  260. sock->usr_flags & NWUO_RA_SET)
  261. udp_connect(pcb, (ip_addr_t *) &udpopt.nwuo_remaddr,
  262. ntohs(udpopt.nwuo_remport));
  263. /* Setting local address means binding */
  264. if (sock->usr_flags & NWUO_LP_SET)
  265. udp_bind(pcb, &loc_ip, ntohs(udpopt.nwuo_locport));
  266. /* We can only bind to random local port */
  267. if (sock->usr_flags & NWUO_LP_SEL)
  268. udp_bind(pcb, &loc_ip, 0);
  269. /* register a receive hook */
  270. udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock);
  271. sock_reply(sock, OK);
  272. }
  273. static void udp_get_opt(struct socket * sock, message * m)
  274. {
  275. int err;
  276. nwio_udpopt_t udpopt;
  277. struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
  278. assert(pcb);
  279. udpopt.nwuo_locaddr = pcb->local_ip.addr;
  280. udpopt.nwuo_locport = htons(pcb->local_port);
  281. udpopt.nwuo_remaddr = pcb->remote_ip.addr;
  282. udpopt.nwuo_remport = htons(pcb->remote_port);
  283. udpopt.nwuo_flags = sock->usr_flags;
  284. debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
  285. debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
  286. (unsigned int) udpopt.nwuo_remaddr);
  287. debug_udp_print("udpopt.nwuo_remport = 0x%x",
  288. ntohs(udpopt.nwuo_remport));
  289. debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
  290. (unsigned int) udpopt.nwuo_locaddr);
  291. debug_udp_print("udpopt.nwuo_locport = 0x%x",
  292. ntohs(udpopt.nwuo_locport));
  293. if ((unsigned) m->COUNT < sizeof(udpopt)) {
  294. sock_reply(sock, EINVAL);
  295. return;
  296. }
  297. err = copy_to_user(m->m_source, &udpopt, sizeof(udpopt),
  298. (cp_grant_id_t) m->IO_GRANT, 0);
  299. if (err != OK)
  300. sock_reply(sock, err);
  301. sock_reply(sock, OK);
  302. }
  303. static void udp_op_ioctl(struct socket * sock, message * m)
  304. {
  305. debug_udp_print("socket num %ld req %c %d %d",
  306. get_sock_num(sock),
  307. (m->REQUEST >> 8) & 0xff,
  308. m->REQUEST & 0xff,
  309. (m->REQUEST >> 16) & _IOCPARM_MASK);
  310. switch (m->REQUEST) {
  311. case NWIOSUDPOPT:
  312. udp_set_opt(sock, m);
  313. break;
  314. case NWIOGUDPOPT:
  315. udp_get_opt(sock, m);
  316. break;
  317. default:
  318. sock_reply(sock, EBADIOCTL);
  319. return;
  320. }
  321. }
  322. struct sock_ops sock_udp_ops = {
  323. .open = udp_op_open,
  324. .close = udp_op_close,
  325. .read = udp_op_read,
  326. .write = udp_op_write,
  327. .ioctl = udp_op_ioctl,
  328. .select = generic_op_select,
  329. .select_reply = generic_op_select_reply
  330. };