error_t udpSendDatagram(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written) { error_t error; size_t offset; ChunkedBuffer *buffer; //Allocate a memory buffer to hold the UDP datagram buffer = udpAllocBuffer(0, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Copy data payload error = chunkedBufferAppend(buffer, data, length); //Successful processing? if(!error) { //Send UDP datagram error = udpSendDatagramEx(socket->interface, socket->localPort, destIpAddr, destPort, buffer, offset, socket->ttl); } //Successful processing? if(!error) { //Total number of data bytes successfully transmitted if(written != NULL) *written = length; } //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t rawSocketSendEthPacket(Socket *socket, const void *data, size_t length, size_t *written) { error_t error; uint32_t crc; ChunkedBuffer *buffer; NetInterface *interface; //Select the relevant network interface if(!socket->interface) interface = tcpIpStackGetDefaultInterface(); else interface = socket->interface; //Allocate a buffer memory to hold the raw Ethernet packet buffer = chunkedBufferAlloc(0); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Copy the raw data error = chunkedBufferAppend(buffer, data, length); //Successful processing? if(!error) { //Automatic padding not supported by hardware? if(!interface->nicDriver->autoPadding) { //The host controller should manually add padding //to the packet before transmitting it if(length < (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE)) { //Add padding as necessary size_t n = (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE) - length; //Append padding bytes error = chunkedBufferAppend(buffer, ethPadding, n); //Any error to report? if(error) return error; //Adjust frame length length += n; } } //CRC generation not supported by hardware? if(!interface->nicDriver->autoCrcGen) { //Compute CRC over the header and payload crc = ethCalcCrcEx(buffer, 0, length); //Convert from host byte order to little-endian byte order crc = htole32(crc); //Append the calculated CRC value error = chunkedBufferAppend(buffer, &crc, sizeof(crc)); //Any error to report? if(error) return error; //Adjust frame length length += sizeof(crc); } //Debug message TRACE_DEBUG("Sending raw Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length); //Send the resulting packet over the specified link error = nicSendPacket(interface, buffer, 0); } //Successful processing? if(!error) { //Total number of bytes successfully transmitted if(written != NULL) *written = length; } //Free previously allocated memory block chunkedBufferFree(buffer); //Return status code return error; }
error_t rawSocketSendIpPacket(Socket *socket, const IpAddr *destIpAddr, const void *data, size_t length, size_t *written) { error_t error; size_t offset; uint_t timeToLive; ChunkedBuffer *buffer; NetInterface *interface; IpPseudoHeader pseudoHeader; //The socket may be bound to a particular network interface interface = socket->interface; //Allocate a buffer memory to hold the raw IP datagram buffer = ipAllocBuffer(0, &offset); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Copy the raw data error = chunkedBufferAppend(buffer, data, length); //Any error to report? if(error) break; #if (IPV4_SUPPORT == ENABLED) //Destination address is an IPv4 address? if(destIpAddr->length == sizeof(Ipv4Addr)) { Ipv4Addr srcIpAddr; //Select the source IPv4 address and the relevant network interface //to use when sending data to the specified destination host error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr, &srcIpAddr); //Any error to report? if(error) break; //Format IPv4 pseudo header pseudoHeader.length = sizeof(Ipv4PseudoHeader); pseudoHeader.ipv4Data.srcAddr = srcIpAddr; pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr; pseudoHeader.ipv4Data.reserved = 0; pseudoHeader.ipv4Data.protocol = socket->protocol; pseudoHeader.ipv4Data.length = htons(length); //Set TTL value timeToLive = IPV4_DEFAULT_TTL; } else #endif #if (IPV6_SUPPORT == ENABLED) //Destination address is an IPv6 address? if(destIpAddr->length == sizeof(Ipv6Addr)) { //Select the source IPv6 address and the relevant network interface //to use when sending data to the specified destination host error = ipv6SelectSourceAddr(&interface, &destIpAddr->ipv6Addr, &pseudoHeader.ipv6Data.srcAddr); //Any error to report? if(error) break; //Format IPv6 pseudo header pseudoHeader.length = sizeof(Ipv6PseudoHeader); pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr; pseudoHeader.ipv6Data.length = htonl(length); pseudoHeader.ipv6Data.reserved = 0; pseudoHeader.ipv6Data.nextHeader = socket->protocol; //Set Hop Limit value timeToLive = IPV6_DEFAULT_HOP_LIMIT; } else #endif //Invalid destination address? { //An internal error has occurred error = ERROR_FAILURE; //Exit immediately break; } //Send raw IP datagram error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, timeToLive); //Failed to send data? if(error) break; //Total number of bytes successfully transmitted if(written != NULL) *written = length; //End of exception handling block } while(0); //Free previously allocated memory block chunkedBufferFree(buffer); //Return status code return error; }