sock.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*!
  2. * Copyright (C) Fraunhofer-Institut for Photonic Microsystems (IPMS)
  3. * Maria-Reiche-Str. 2
  4. * 01109 Dresden
  5. *
  6. * Unauthorized copying of this file, via any medium is strictly prohibited
  7. * Proprietary and confidential
  8. *
  9. * \file sock.c
  10. * \author zimmerli
  11. * \date 2020-01-21
  12. * \brief Ethernet Socket
  13. *
  14. */
  15. #include "sock.h"
  16. #include <kernel/base/klibc.h>
  17. #include <kernel/net/ether.h>
  18. #include <kernel/net/netdev.h>
  19. #include <kernel/lwip/lwip_port.h>
  20. #include <tsn_rtos_config.h>
  21. #include <string.h>
  22. #if USE_TSN_RTOS_LWIP
  23. #include <lwip/netif.h>
  24. #endif
  25. // ----------------------------------------------------------------
  26. #define SOCKSRX_MAX 16
  27. #define SOCKSTX_MAX 16
  28. #define DEFAULT_QSZ 16
  29. //#define DEBUG_PRINT_RX
  30. static struct sock_ethrx_s *_socks_rx[SOCKSRX_MAX] = { 0 };
  31. static struct sock_ethtx_s *_socks_tx[SOCKSTX_MAX] = { 0 };
  32. //ERSTMAL
  33. #ifdef DEBUG_PRINT_RX
  34. extern void __internal_unset_indent();
  35. extern void __internal_set_indent();
  36. #endif
  37. static const char *SOCKET_CONTEXT = "SOCKET";
  38. void display_frame(char *ctx, uint8_t *data, uint8_t len)
  39. {
  40. logs(LOG_ALWAYS, SOCKET_CONTEXT, " frame (%s, %u): ", ctx, len);
  41. for (uint8_t i = 0; i < len; i++)
  42. logc(LOG_ALWAYS, "%02X ", (data[i]));
  43. loge(LOG_ALWAYS, "\n");
  44. }
  45. // ----------------------------------------------------------------
  46. /**
  47. * \brief Received data, called by network device driver
  48. *
  49. * @param netdev pointer to netdev handling the received frame
  50. * @param netb pointer to received network buffer
  51. */
  52. uint32_t cnt = 0;
  53. void socket_rx(struct netdev_s *netdev, struct netb_s *netb)
  54. {
  55. uint32_t idx, tmp;
  56. uint32_t protosz;
  57. uint16_t ethtype_hbo;
  58. cnt++;
  59. /*
  60. * get ethertype
  61. * pull ethernet protocol
  62. * support for vlan
  63. */
  64. protosz = 14;
  65. ethtype_hbo = MEM16(netb->data + 12);
  66. ethtype_hbo = klibc_ntohs(ethtype_hbo);
  67. if (ethtype_hbo == ETH_TYPE_VLAN) {
  68. protosz += 4;
  69. ethtype_hbo = MEM16(netb->data + 16);
  70. ethtype_hbo = klibc_ntohs(ethtype_hbo);
  71. }
  72. /* find rx socket */
  73. for (idx = 0; idx < SOCKSRX_MAX; ++idx) {
  74. if (_socks_rx[idx] && (_socks_rx[idx]->ethtype_hbo == ethtype_hbo)) {
  75. if (!_socks_rx[idx]->netdev || (_socks_rx[idx]->netdev == netb->netdev) || _socks_rx[idx]->netdev == netdev) {
  76. netb_pull(netb, protosz);
  77. /* add to socket queue */
  78. // logk(LOG_DEBUG, SOCKET_CONTEXT, "put netbuf in sock rx queue %d (ethtype: 0x%04X)\n", idx, ethtype_hbo);
  79. tmp = xQueueSend(_socks_rx[idx]->queue_rx, &netb, 0);
  80. if (tmp != pdPASS) {
  81. _socks_rx[idx]->netdev->stats.rx_dropped++;
  82. kfree_netb(netb);
  83. }
  84. _socks_rx[idx]->netdev->stats.rx_packets++;
  85. return;
  86. }
  87. }
  88. }
  89. /*
  90. * to lwIP
  91. */
  92. #if (USE_TSN_RTOS_NET_LWIP)
  93. lwip_recv_skb(netdev, netb);
  94. #else
  95. /* free buffer */
  96. kfree_netb(netb);
  97. #endif
  98. }
  99. /**
  100. * \brief Create MAC-layer RX socket for specified ether type
  101. *
  102. * @param ethtype_hbo ether type, host-byte-order
  103. * @return pointer to socket or NULL on error
  104. */
  105. struct sock_ethrx_s *socket_ethrx(uint16_t ethtype_hbo)
  106. {
  107. uint32_t idx;
  108. /* search empty rx sock ptr */
  109. for (idx = 0; idx < SOCKSRX_MAX; ++idx) {
  110. if (!_socks_rx[idx])
  111. break;
  112. }
  113. if (idx >= SOCKSRX_MAX)
  114. return NULL;
  115. /* alloc / init */
  116. _socks_rx[idx] = kallocz(sizeof(struct sock_ethrx_s));
  117. if (_socks_rx[idx]) {
  118. _socks_rx[idx]->ethtype_hbo = ethtype_hbo;
  119. _socks_rx[idx]->queue_rx = xQueueCreate(DEFAULT_QSZ, sizeof(struct netb_s *));
  120. }
  121. return _socks_rx[idx];
  122. }
  123. /**
  124. * \brief Bind socket to device
  125. *
  126. * Will only receive from device or from any device (device==NULL)
  127. *
  128. * @param sock pointer to socket
  129. * @param device pointer to netdev device, set NULL for any device
  130. */
  131. void socket_ethrx_bind(struct sock_ethrx_s *sock, struct netdev_s *device)
  132. {
  133. if (!sock)
  134. return;
  135. sock->netdev = device;
  136. }
  137. // ----------------------------------------------------------------
  138. /**
  139. * \brief Create MAC-layer TX socket for specified ether type
  140. *
  141. * @param ethtype_hbo ether type, host-byte-order
  142. * @return pointer to socket, NULL on error
  143. */
  144. struct sock_ethtx_s *socket_ethtx(uint16_t ethtype_hbo)
  145. {
  146. uint32_t idx;
  147. /* search empty tx sock ptr */
  148. for (idx = 0; idx < SOCKSTX_MAX; ++idx) {
  149. if (!_socks_tx[idx])
  150. break;
  151. }
  152. if (idx >= SOCKSTX_MAX)
  153. return NULL;
  154. /* alloc / init */
  155. _socks_tx[idx] = kallocz(sizeof(struct sock_ethtx_s));
  156. if (_socks_tx[idx]) {
  157. _socks_tx[idx]->ethtype_hbo = ethtype_hbo;
  158. }
  159. return _socks_tx[idx];
  160. }
  161. /**
  162. * \brief Bind socket to device
  163. *
  164. * @param sock pointer to socket
  165. * @param device pointer to netdev device
  166. */
  167. void socket_ethtx_bind(struct sock_ethtx_s *sock, struct netdev_s *device)
  168. {
  169. if (!sock)
  170. return;
  171. sock->netdev = device;
  172. }
  173. static struct netb_s *_socktx_alloc_netb(uint32_t resv_sz, uint32_t timeout)
  174. {
  175. struct netb_s *netb;
  176. netb = kalloc_netb(timeout);
  177. if (netb) {
  178. netb_reserve(netb, resv_sz);
  179. }
  180. return netb;
  181. }
  182. static int32_t _socktx_xmit(struct sock_ethtx_s *sock, struct netb_s *netb)
  183. {
  184. netb->priority = sock->traffic_prio;
  185. netb->tstamp_id = sock->tstamp_id;
  186. return netdev_xmit(sock->netdev, netb);
  187. }
  188. static void _socktx_mac_hdr(struct netb_s *netb, uint8_t *src, uint8_t *dst, uint16_t ethtype, uint16_t vlantag)
  189. {
  190. uint32_t proto_sz;
  191. /* calc mac header size && push to front */
  192. proto_sz = 14;
  193. if (vlantag)
  194. proto_sz += 4;
  195. netb_push(netb, proto_sz);
  196. /* set header, conversion to network byte order */
  197. memcpy((void *)(netb->data + 0), dst, MAC_ADDR_LEN);
  198. memcpy((void *)(netb->data + 6), src, MAC_ADDR_LEN);
  199. if (vlantag) {
  200. MEM16(netb->data + 12) = klibc_htons(ETH_TYPE_VLAN);
  201. MEM16(netb->data + 14) = klibc_htons(vlantag);
  202. }
  203. MEM16(netb->data + proto_sz - 2) = klibc_htons(ethtype);
  204. }
  205. static void _socktx_udp_hdr(struct netb_s *netb, struct udp_proto_s *udp)
  206. {
  207. register uint16_t tmp;
  208. uint16_t payload_sz;
  209. uint32_t csum;
  210. uint32_t src_ip_nbo, dst_ip_nbo;
  211. uint32_t idx;
  212. // ip conversion (needed for pseudo header)
  213. src_ip_nbo = klibc_htonl(udp->src_ip_hbo);
  214. dst_ip_nbo = klibc_htonl(udp->dst_ip_hbo);
  215. payload_sz = netb_length(netb);
  216. /* UDP */
  217. netb_push(netb, 8);
  218. MEM16(netb->data + 0) = klibc_htons(udp->src_port_hbo); // src
  219. MEM16(netb->data + 2) = klibc_htons(udp->dst_port_hbo); // dst
  220. tmp = netb_length(netb);
  221. MEM16(netb->data + 4) = klibc_htons(tmp); // len (incl udp header)
  222. MEM16(netb->data + 6) = 0; // csum
  223. /* UDP checksum */
  224. csum = 0;
  225. // pseudo header
  226. csum += src_ip_nbo & 0xFFFF;
  227. csum += src_ip_nbo >> 16;
  228. csum += dst_ip_nbo & 0xFFFF;
  229. csum += dst_ip_nbo >> 16;
  230. csum += klibc_htons(0x0011); // protocol
  231. csum += MEM16(netb->data + 4);
  232. csum += MEM16(netb->data + 0);
  233. csum += MEM16(netb->data + 2);
  234. csum += MEM16(netb->data + 4); // length included twice!
  235. // payload csum
  236. // payload odd byte=0
  237. if (payload_sz & 0x01)
  238. MEM8(netb->tail) = 0x00;
  239. for (idx = 0; idx < payload_sz; idx += 2) {
  240. csum += MEM16(netb->data + 8 + idx);
  241. }
  242. // set
  243. while (csum > 0xFFFF) {
  244. csum = (csum >> 16) + (csum & 0xFFFF);
  245. }
  246. csum = ~csum; // invert
  247. if (!csum)
  248. csum = ~0; // never 0
  249. MEM16(netb->data + 6) = csum;
  250. /* IPv4 */
  251. netb_push(netb, 20);
  252. MEM16(netb->data + 0) = klibc_htons(0x4500); // diffserv
  253. tmp = netb_length(netb);
  254. MEM16(netb->data + 2) = klibc_htons(tmp); // total length
  255. MEM16(netb->data + 4) = klibc_htons(0); // id
  256. MEM16(netb->data + 6) = klibc_htons(0); // fragm, flags
  257. MEM16(netb->data + 8) = klibc_htons(0x8611); // ttl, proto udp=0x11
  258. MEM16(netb->data + 10) = klibc_htons(0); // hdr checksum, 0 for calculation
  259. __put_unaligned_le32(src_ip_nbo, netb->data + 12); // src ip addr
  260. __put_unaligned_le32(dst_ip_nbo, netb->data + 16); // dst ip addr
  261. // IP header checksum
  262. csum = 0;
  263. for (tmp = 0; tmp < 20; tmp += 2) {
  264. csum += MEM16(netb->data + tmp);
  265. }
  266. while (csum > 0xFFFF) {
  267. csum = (csum >> 16) + (csum & 0xFFFF);
  268. }
  269. // update checksum
  270. MEM16(netb->data + 10) = ~csum; // set hdr checksum
  271. }
  272. /**
  273. * \brief Send data over socket
  274. *
  275. * @param sock pointer to socket
  276. * @param ptr pointer to payload
  277. * @param length length of payload in bytes
  278. * @param dstmac destination mac address
  279. * @return error code, NETDEV_RESULT_OK on success
  280. */
  281. int32_t socket_ethtx_send(struct sock_ethtx_s *sock, void *ptr, uint32_t length, uint8_t *dstmac)
  282. {
  283. struct netb_s *netb;
  284. uint32_t space;
  285. int32_t retval;
  286. if (!sock || !sock->netdev)
  287. return NETDEV_ERR_GENERAL;
  288. /* calc needed head space && allocate buffer */
  289. space = sock->netdev->needed_head + 14;
  290. if (sock->vlantag_hbo)
  291. space += 4;
  292. netb = _socktx_alloc_netb(space, 10);
  293. if (!netb)
  294. return NETDEV_ERR_GENERAL;
  295. /* put payload data to buffer*/
  296. memcpy((void *)netb->tail, ptr, length);
  297. netb_put(netb, length);
  298. /* set eth protocol header */
  299. _socktx_mac_hdr(netb, sock->netdev->dev_addr, dstmac, sock->ethtype_hbo, sock->vlantag_hbo);
  300. /* send to device */
  301. retval = _socktx_xmit(sock, netb);
  302. /* always free allocated buffer */
  303. kfree_netb(netb);
  304. return retval;
  305. }
  306. /**
  307. * \brief Send UDP data over socket
  308. *
  309. * @param sock pointer to socket
  310. * @param udp pointer to UDP settings
  311. * @param ptr pointer to payload
  312. * @param length length of payload in bytes
  313. * @return error code, NETDEV_RESULT_OK on success
  314. */
  315. int32_t socket_ethtx_send_udp(struct sock_ethtx_s *sock, struct udp_proto_s *udp, void *ptr, uint32_t length)
  316. {
  317. uint8_t dstmac[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
  318. struct netb_s *netb;
  319. uint32_t space;
  320. int32_t retval;
  321. if (!sock || !sock->netdev)
  322. return NETDEV_ERR_GENERAL;
  323. /* calc needed head space && allocate buffer */
  324. space = sock->netdev->needed_head + 14 + 28;
  325. if (sock->vlantag_hbo)
  326. space += 4;
  327. netb = _socktx_alloc_netb(space, 10);
  328. if (!netb)
  329. return NETDEV_ERR_GENERAL;
  330. /* put payload data to buffer*/
  331. memcpy((void *)netb->tail, ptr, length);
  332. netb_put(netb, length);
  333. /* UDP protocol */
  334. _socktx_udp_hdr(netb, udp);
  335. if ((udp->dst_ip_hbo & 0xF0000000) == 0xE0000000) {
  336. // multicast IP -> set dst mac
  337. dstmac[3] = (udp->dst_ip_hbo >> 16) & 0x7F;
  338. dstmac[4] = (udp->dst_ip_hbo >> 8) & 0xFF;
  339. dstmac[5] = udp->dst_ip_hbo & 0xFF;
  340. }
  341. /* set eth protocol header */
  342. _socktx_mac_hdr(netb, sock->netdev->dev_addr, dstmac, ETH_TYPE_IP, sock->vlantag_hbo);
  343. /* send to device */
  344. retval = _socktx_xmit(sock, netb);
  345. /* always free allocated buffer */
  346. kfree_netb(netb);
  347. return retval;
  348. }