otError UdpSocket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo) { otError error = OT_ERROR_NONE; MessageInfo messageInfoLocal; UdpHeader udpHeader; messageInfoLocal = aMessageInfo; if (messageInfoLocal.GetSockAddr().IsUnspecified()) { messageInfoLocal.SetSockAddr(GetSockName().GetAddress()); } if (GetSockName().mPort == 0) { GetSockName().mPort = static_cast<Udp *>(mTransport)->GetEphemeralPort(); } if (messageInfoLocal.GetPeerAddr().IsUnspecified()) { VerifyOrExit(!GetPeerName().GetAddress().IsUnspecified(), error = OT_ERROR_INVALID_ARGS); messageInfoLocal.SetPeerAddr(GetPeerName().GetAddress()); } if (messageInfoLocal.mPeerPort == 0) { VerifyOrExit(GetPeerName().mPort != 0, error = OT_ERROR_INVALID_ARGS); messageInfoLocal.mPeerPort = GetPeerName().mPort; } udpHeader.SetSourcePort(GetSockName().mPort); udpHeader.SetDestinationPort(messageInfoLocal.mPeerPort); udpHeader.SetLength(sizeof(udpHeader) + aMessage.GetLength()); udpHeader.SetChecksum(0); SuccessOrExit(error = aMessage.Prepend(&udpHeader, sizeof(udpHeader))); aMessage.SetOffset(0); SuccessOrExit(error = static_cast<Udp *>(mTransport)->SendDatagram(aMessage, messageInfoLocal, kProtoUdp)); exit: return error; }
otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) { otError error = OT_ERROR_NONE; UdpHeader udpHeader; uint16_t payloadLength; uint16_t checksum; payloadLength = aMessage.GetLength() - aMessage.GetOffset(); // check length VerifyOrExit(payloadLength >= sizeof(UdpHeader), error = OT_ERROR_PARSE); // verify checksum checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), payloadLength, kProtoUdp); checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VerifyOrExit(checksum == 0xffff, error = OT_ERROR_DROP); #endif VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(udpHeader), &udpHeader) == sizeof(udpHeader), error = OT_ERROR_PARSE); aMessage.MoveOffset(sizeof(udpHeader)); aMessageInfo.mPeerPort = udpHeader.GetSourcePort(); aMessageInfo.mSockPort = udpHeader.GetDestinationPort(); // find socket for (UdpSocket *socket = mSockets; socket; socket = socket->GetNext()) { if (socket->GetSockName().mPort != udpHeader.GetDestinationPort()) { continue; } if (socket->GetSockName().mScopeId != 0 && socket->GetSockName().mScopeId != aMessageInfo.mInterfaceId) { continue; } if (!aMessageInfo.GetSockAddr().IsMulticast() && !socket->GetSockName().GetAddress().IsUnspecified() && socket->GetSockName().GetAddress() != aMessageInfo.GetSockAddr()) { continue; } // verify source if connected socket if (socket->GetPeerName().mPort != 0) { if (socket->GetPeerName().mPort != udpHeader.GetSourcePort()) { continue; } if (!socket->GetPeerName().GetAddress().IsUnspecified() && socket->GetPeerName().GetAddress() != aMessageInfo.GetPeerAddr()) { continue; } } socket->HandleUdpReceive(aMessage, aMessageInfo); } exit: return error; }
ThreadError Ip6::SendDatagram(Message &message, MessageInfo &messageInfo, IpProto ipproto) { ThreadError error = kThreadError_None; Header header; uint16_t payloadLength = message.GetLength(); uint16_t checksum; const NetifUnicastAddress *source; header.Init(); header.SetPayloadLength(payloadLength); header.SetNextHeader(ipproto); header.SetHopLimit(messageInfo.mHopLimit ? messageInfo.mHopLimit : kDefaultHopLimit); if (messageInfo.GetSockAddr().IsUnspecified()) { VerifyOrExit((source = Netif::SelectSourceAddress(messageInfo)) != NULL, error = kThreadError_Error); header.SetSource(source->GetAddress()); } else { header.SetSource(messageInfo.GetSockAddr()); } header.SetDestination(messageInfo.GetPeerAddr()); if (header.GetDestination().IsLinkLocal() || header.GetDestination().IsLinkLocalMulticast()) { VerifyOrExit(messageInfo.mInterfaceId != 0, error = kThreadError_Drop); } if (messageInfo.GetPeerAddr().IsRealmLocalMulticast()) { SuccessOrExit(error = AddMplOption(message, header, ipproto, payloadLength)); } SuccessOrExit(error = message.Prepend(&header, sizeof(header))); // compute checksum checksum = ComputePseudoheaderChecksum(header.GetSource(), header.GetDestination(), payloadLength, ipproto); switch (ipproto) { case kProtoUdp: SuccessOrExit(error = Udp::UpdateChecksum(message, checksum)); break; case kProtoIcmp6: SuccessOrExit(error = Icmp::UpdateChecksum(message, checksum)); break; default: break; } exit: if (error == kThreadError_None) { error = HandleDatagram(message, NULL, messageInfo.mInterfaceId, NULL, false); } return error; }