int csp_route_work(uint32_t timeout) { csp_qfifo_t input; csp_packet_t * packet; csp_conn_t * conn; csp_socket_t * socket; #ifdef CSP_USE_RDP /* Check connection timeouts (currently only for RDP) */ csp_conn_check_timeouts(); #endif /* Get next packet to route */ if (csp_qfifo_read(&input) != CSP_ERR_NONE) return -1; packet = input.packet; csp_log_packet("INP: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %"PRIu16" VIA: %s", packet->id.src, packet->id.dst, packet->id.dport, packet->id.sport, packet->id.pri, packet->id.flags, packet->length, input.interface->name); /* Here there be promiscuous mode */ #ifdef CSP_USE_PROMISC csp_promisc_add(packet); #endif #ifdef CSP_USE_DEDUP /* Check for duplicates */ if (csp_dedup_is_duplicate(packet)) { /* Discard packet */ csp_log_packet("Duplicate packet discarded"); csp_buffer_free(packet); return 0; } #endif /* If the message is not to me, route the message to the correct interface */ if ((packet->id.dst != csp_get_address()) && (packet->id.dst != CSP_BROADCAST_ADDR)) { /* Find the destination interface */ csp_iface_t * dstif = csp_rtable_find_iface(packet->id.dst); /* If the message resolves to the input interface, don't loop it back out */ if ((dstif == NULL) || ((dstif == input.interface) && (input.interface->split_horizon_off == 0))) { csp_buffer_free(packet); return 0; } /* Otherwise, actually send the message */ if (csp_send_direct(packet->id, packet, dstif, 0) != CSP_ERR_NONE) { csp_log_warn("Router failed to send"); csp_buffer_free(packet); } /* Next message, please */ return 0; } /* Discard packets with unsupported options */ if (csp_route_check_options(input.interface, packet) != CSP_ERR_NONE) { csp_buffer_free(packet); return 0; } /* The message is to me, search for incoming socket */ socket = csp_port_get_socket(packet->id.dport); /* If the socket is connection-less, deliver now */ if (socket && (socket->opts & CSP_SO_CONN_LESS)) { if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { csp_buffer_free(packet); return 0; } if (csp_queue_enqueue(socket->socket, &packet, 0) != CSP_QUEUE_OK) { csp_log_error("Conn-less socket queue full"); csp_buffer_free(packet); return 0; } return 0; } /* Search for an existing connection */ conn = csp_conn_find(packet->id.ext, CSP_ID_CONN_MASK); /* If this is an incoming packet on a new connection */ if (conn == NULL) { /* Reject packet if no matching socket is found */ if (!socket) { csp_buffer_free(packet); return 0; } /* Run security check on incoming packet */ if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { csp_buffer_free(packet); return 0; } /* New incoming connection accepted */ csp_id_t idout; idout.pri = packet->id.pri; idout.src = csp_get_address(); idout.dst = packet->id.src; idout.dport = packet->id.sport; idout.sport = packet->id.dport; idout.flags = packet->id.flags; /* Create connection */ conn = csp_conn_new(packet->id, idout); if (!conn) { csp_log_error("No more connections available"); csp_buffer_free(packet); return 0; } /* Store the socket queue and options */ conn->socket = socket->socket; conn->opts = socket->opts; /* Packet to existing connection */ } else { /* Run security check on incoming packet */ if (csp_route_security_check(conn->opts, input.interface, packet) < 0) { csp_buffer_free(packet); return 0; } } #ifdef CSP_USE_RDP /* Pass packet to RDP module */ if (packet->id.flags & CSP_FRDP) { csp_rdp_new_packet(conn, packet); return 0; } #endif /* Pass packet to UDP module */ csp_udp_new_packet(conn, packet); return 0; }
int csp_send_direct(csp_id_t idout, csp_packet_t * packet, uint32_t timeout) { if (packet == NULL) { csp_log_error("csp_send_direct called with NULL packet\r\n"); goto err; } csp_route_t * ifout = csp_route_if(idout.dst); if ((ifout == NULL) || (ifout->interface == NULL) || (ifout->interface->nexthop == NULL)) { csp_log_error("No route to host: %#08x\r\n", idout.ext); goto err; } csp_log_packet("Output: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %u VIA: %s\r\n", idout.src, idout.dst, idout.dport, idout.sport, idout.pri, idout.flags, packet->length, ifout->interface->name); /* * Copy identifier to packet. This originally happened below (after * encryption), but doing it here makes logging simpler and doesn't * affect the encryption stuff at all. */ packet->id.ext = idout.ext; /* Log the packet as sent by the application (before encryption) */ if (csp_packet_callback) csp_packet_callback(CSP_OUTPUT, ifout->interface->name, packet); #if 0 #ifdef __linux__ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); double sec = ts.tv_sec + ts.tv_nsec / 1e9; #else double sec = (float)xTaskGetTickCount() / configTICK_RATE_HZ; #endif printf("%.3f: packet contents (%d bytes):", sec, packet->length); for (int i = 0; i < packet->length; i++) { if (i % 16 == 0) printf("\n"); printf("%02x ", packet->data[i]); } printf("\n\n"); #endif #ifdef CSP_USE_PROMISC /* Loopback traffic is added to promisc queue by the router */ if (idout.dst != my_address && idout.src == my_address) { packet->id.ext = idout.ext; csp_promisc_add(packet, csp_promisc_queue); } #endif /* Only encrypt packets from the current node */ if (idout.src == my_address) { /* Append HMAC */ if (idout.flags & CSP_FHMAC) { #ifdef CSP_USE_HMAC /* Calculate and add HMAC */ if (csp_hmac_append(packet) != 0) { /* HMAC append failed */ csp_log_warn("HMAC append failed!\r\n"); goto tx_err; } #else csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet\r\n"); goto tx_err; #endif } /* Append CRC32 */ if (idout.flags & CSP_FCRC32) { #ifdef CSP_USE_CRC32 /* Calculate and add CRC32 */ if (csp_crc32_append(packet) != 0) { /* CRC32 append failed */ csp_log_warn("CRC32 append failed!\r\n"); goto tx_err; } #else csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r\n"); idout.flags &= ~(CSP_FCRC32); #endif } if (idout.flags & CSP_FXTEA) { #ifdef CSP_USE_XTEA /* Create nonce */ uint32_t nonce, nonce_n; nonce = (uint32_t)rand(); nonce_n = csp_hton32(nonce); memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); /* Create initialization vector */ uint32_t iv[2] = {nonce, 1}; /* Encrypt data */ if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { /* Encryption failed */ csp_log_warn("Encryption failed! Discarding packet\r\n"); goto tx_err; } packet->length += sizeof(nonce_n); #else csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet\r\n"); goto tx_err; #endif } } /* Store length before passing to interface */ uint16_t bytes = packet->length; uint16_t mtu = ifout->interface->mtu; if (mtu > 0 && bytes > mtu) { csp_log_warn("Attempt to send a packet larger than the interface's mtu.\r\n"); goto tx_err; } /* Log the packet as sent over the interface */ if (csp_packet_callback) csp_packet_callback(CSP_OUTPUT_RAW, ifout->interface->name, packet); if ((*ifout->interface->nexthop)(ifout->interface, packet, timeout) != CSP_ERR_NONE) goto tx_err; /* Update our transmit-time estimates, if the interface supports it */ if (ifout->interface->tx_ms_per_byte) { /* * If the completion time is in the past, that means * the interface is not currently transmitting. */ uint32_t time_now = csp_get_ms(); if (csp_time_after(time_now, ifout->interface->tx_done_time)) ifout->interface->tx_done_time = time_now; ifout->interface->tx_done_time += ifout->interface->tx_ms_per_packet + bytes * ifout->interface->tx_ms_per_byte; #if 0 printf("DEBUG: now %u, expected completion at %u\n", time_now, ifout->interface->tx_done_time); #endif } ifout->interface->tx++; ifout->interface->txbytes += bytes; return CSP_ERR_NONE; tx_err: ifout->interface->tx_error++; err: return CSP_ERR_TX; }
int csp_send_direct(csp_id_t idout, csp_packet_t * packet, uint32_t timeout) { if (packet == NULL) { csp_log_error("csp_send_direct called with NULL packet\r\n"); goto err; } csp_route_t * ifout = csp_route_if(idout.dst); if ((ifout == NULL) || (ifout->interface == NULL) || (ifout->interface->nexthop == NULL)) { csp_log_error("No route to host: %#08x\r\n", idout.ext); goto err; } csp_log_packet("Sending packet size %u from %u to %u port %u via interface %s\r\n", packet->length, idout.src, idout.dst, idout.dport, ifout->interface->name); #ifdef CSP_USE_PROMISC /* Loopback traffic is added to promisc queue by the router */ if (idout.dst != my_address) { packet->id.ext = idout.ext; csp_promisc_add(packet, csp_promisc_queue); } #endif if (idout.flags & CSP_SEQNR) { #ifdef CSP_USE_SEQNR /*Append the gloal seqnr. to the packet */ if(csp_seqnr_append(packet) != 0) { /* SEQNR append failed */ csp_log_warn("SEQNR append failed !\r\n"); goto tx_err; } #else csp_log_warn("Attempt to send packet with SEQNR, but csp was compiled without SEQNR support. Discarding packet\r\n"); goto tx_err; #endif } /* Only encrypt packets from the current node */ if (idout.src == my_address) { /* Append HMAC */ if (idout.flags & CSP_FHMAC) { #ifdef CSP_USE_HMAC /* Calculate and add HMAC */ if (csp_hmac_append(packet) != 0) { /* HMAC append failed */ csp_log_warn("HMAC append failed!\r\n"); goto tx_err; } #else csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet\r\n"); goto tx_err; #endif } /* Append CRC32 */ if (idout.flags & CSP_FCRC32) { #ifdef CSP_USE_CRC32 /* Calculate and add CRC32 */ if (csp_crc32_append(packet) != 0) { /* CRC32 append failed */ csp_log_warn("CRC32 append failed!\r\n"); goto tx_err; } #else csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r\n"); idout.flags &= ~(CSP_FCRC32); #endif } if (idout.flags & CSP_FXTEA) { #ifdef CSP_USE_XTEA /* Create nonce */ uint32_t nonce, nonce_n; nonce = (uint32_t)rand(); nonce_n = csp_hton32(nonce); memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); /* Create initialization vector */ uint32_t iv[2] = {nonce, 1}; /* Encrypt data */ if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { /* Encryption failed */ csp_log_warn("Encryption failed! Discarding packet\r\n"); goto tx_err; } packet->length += sizeof(nonce_n); #else csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet\r\n"); goto tx_err; #endif } } /* Copy identifier to packet */ packet->id.ext = idout.ext; /* Store length before passing to interface */ uint16_t bytes = packet->length; uint16_t mtu = ifout->interface->mtu; if (mtu > 0 && bytes > mtu) goto tx_err; if ((*ifout->interface->nexthop)(packet, timeout) != CSP_ERR_NONE) goto tx_err; ifout->interface->tx++; ifout->interface->txbytes += bytes; return CSP_ERR_NONE; tx_err: ifout->interface->tx_error++; err: return CSP_ERR_TX; }
int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout) { if (packet == NULL) { csp_log_error("csp_send_direct called with NULL packet"); goto err; } if ((ifout == NULL) || (ifout->nexthop == NULL)) { csp_log_error("No route to host: %#08x", idout.ext); goto err; } csp_log_packet("OUT: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %u VIA: %s", idout.src, idout.dst, idout.dport, idout.sport, idout.pri, idout.flags, packet->length, ifout->name); /* Copy identifier to packet (before crc, xtea and hmac) */ packet->id.ext = idout.ext; #ifdef CSP_USE_PROMISC /* Loopback traffic is added to promisc queue by the router */ if (idout.dst != csp_get_address() && idout.src == csp_get_address()) { packet->id.ext = idout.ext; csp_promisc_add(packet); } #endif /* Only encrypt packets from the current node */ if (idout.src == csp_get_address()) { /* Append HMAC */ if (idout.flags & CSP_FHMAC) { #ifdef CSP_USE_HMAC /* Calculate and add HMAC (does not include header for backwards compatability with csp1.x) */ if (csp_hmac_append(packet, false) != 0) { /* HMAC append failed */ csp_log_warn("HMAC append failed!"); goto tx_err; } #else csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); goto tx_err; #endif } /* Append CRC32 */ if (idout.flags & CSP_FCRC32) { #ifdef CSP_USE_CRC32 /* Calculate and add CRC32 (does not include header for backwards compatability with csp1.x) */ if (csp_crc32_append(packet, false) != 0) { /* CRC32 append failed */ csp_log_warn("CRC32 append failed!"); goto tx_err; } #else csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r"); idout.flags &= ~(CSP_FCRC32); #endif } if (idout.flags & CSP_FXTEA) { #ifdef CSP_USE_XTEA /* Create nonce */ uint32_t nonce, nonce_n; nonce = (uint32_t)rand(); nonce_n = csp_hton32(nonce); memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); /* Create initialization vector */ uint32_t iv[2] = {nonce, 1}; /* Encrypt data */ if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { /* Encryption failed */ csp_log_warn("Encryption failed! Discarding packet"); goto tx_err; } packet->length += sizeof(nonce_n); #else csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); goto tx_err; #endif } } /* Store length before passing to interface */ uint16_t bytes = packet->length; uint16_t mtu = ifout->mtu; if (mtu > 0 && bytes > mtu) goto tx_err; if ((*ifout->nexthop)(ifout, packet, timeout) != CSP_ERR_NONE) goto tx_err; ifout->tx++; ifout->txbytes += bytes; return CSP_ERR_NONE; tx_err: ifout->tx_error++; err: return CSP_ERR_TX; }