3. udp头:struct udphdr
static void AppendIpv6Header(U8 *packet, DhcpMessageIpv6T *msg)
{
struct ip6_hdr *ip6hdr = DML_CAST_PTR(struct ip6_hdr *, packet);
/* Parameter checks */
DML_ASSERTR(packet != NULL);
DML_ASSERTR(msg != NULL);
/* Fill in the IPv6 header. */
ip6hdr->ip6_flow = htonl ((6 << 28) | (0 << 20) | 0); // IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)
ip6hdr->ip6_plen = htons(UDPHDR_LEN + msg->len);
ip6hdr->ip6_nxt = IPPROTO_UDP;
ip6hdr->ip6_hops = MAXTTL;
memcpy(ip6hdr->ip6_src.s6_addr, msg->srcIp6, sizeof(msg->srcIp6));
memcpy(ip6hdr->ip6_dst.s6_addr, msg->dstIp6, sizeof(msg->dstIp6));
}
static void AppendUdpHeader(U8 *packet, DhcpMessageIpv6T *msg)
{
struct udphdr *udphdr = DML_CAST_PTR(struct udphdr *, packet);
U32 udpLength = 0;
/* Parameter checks */
DML_ASSERTR(packet != NULL);
DML_ASSERTR(msg != NULL);
/* Calculate the UDP datagram length */
udpLength = UDPHDR_LEN + msg->len;
/* Fill in the UDP header. */
udphdr->dest = htons(msg->dstPort);
udphdr->source = htons(msg->srcPort);
udphdr->len = htons(udpLength);
udphdr->check = 0;
}
static DmlErrorT OpenSendL2SocketIpv6(DhcpCRawSocketIpv6T *dhcpSock)
{
S32 sock;
U32 on = 1;
/* Parameter checks */
DML_ASSERTRC(dhcpSock != NULL, DML_PARAM);
DML_ASSERTRC(dhcpSock->sendL2Sock == INVALID_SOCKET, DML_ERROR);
/*
* Create a socket for sending/receiving broadcast DHCP messages
*/
sock = socket (PF_INET6, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0)
{
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_CRIT, "Could not create RAW Socket, errno=%s", strerror(errno));
return DML_ERROR;
}
/* Enable sending broadcast frames on this socket. */
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
{
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_CRIT, "Could set BROADCAST option on socket, errno=%s", strerror(errno));
close(sock);
return DML_ERROR;
}
dhcpSock->sendL2Sock = sock;
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_TRACE,"Open DHCP send socket - %d\n", sock);
return DML_OK;
}
DmlErrorT DhcpCRawSockSendL2Ipv6(DhcpCRawSocketIpv6T *dhcpSock, DhcpMessageIpv6T *msg)
{
S32 rc;
U8 datagram[DHCP_MAX_MSG_SIZE];
U8 *datagramPtr = datagram;
U8 *udpPtr = NULL;
U32 datagramLen = 0;
struct ethhdr *eth = NULL;
struct sockaddr_pkt sockAddr;
/* Parameter checks */
DML_ASSERTRC(dhcpSock != NULL, DML_PARAM);
DML_ASSERTRC(msg != NULL, DML_PARAM);
/* Fill in the Ethernet header. */
eth = DML_CAST_PTR(struct ethhdr *, datagramPtr);
memcpy(eth->h_dest, msg->dstMac, sizeof(eth->h_dest));
memcpy(eth->h_source, msg->srcMac, sizeof(eth->h_source));
eth->h_proto = htons(ETH_P_IPV6);
datagramPtr += ETHHDR_LEN;
datagramLen += ETHHDR_LEN;
/* Fill in the IP header. */
AppendIpv6Header(datagramPtr, msg);
datagramPtr += IPV6HDR_LEN;
datagramLen += IPV6HDR_LEN;
/* Fill in the UDP header.
*
* Note, save a pointer to the UDP header because the checksum
* will have to be computed over the entire frame after the data
* is copied in. */
udpPtr = datagramPtr;
AppendUdpHeader(datagramPtr, msg);
datagramPtr += UDPHDR_LEN;
datagramLen += UDPHDR_LEN;
/* Check if there is enough room to copy the DHCP message into the
* datagram buffer. */
if ((sizeof(datagram) - datagramLen) <= msg->len)
{
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_ERR,
"Datagram buffer size %u too small for DHCP message length %u", sizeof(datagram), msg->len);
return DML_ERROR;
}
/* Copy in the DHCP message into the datagram buffer */
memcpy(datagramPtr, &msg->pkt, msg->len);
datagramPtr += msg->len;
datagramLen += msg->len;
/* Update the UDP checksum */
UpdateUdpChecksumIpv6(udpPtr, msg);
/* Set up a socket address */
memset (&sockAddr, 0, sizeof sockAddr);
sockAddr.spkt_family = AF_PACKET;
strncpy ((char *)sockAddr.spkt_device, dhcpSock->name, sizeof sockAddr.spkt_device);
sockAddr.spkt_protocol = htons(ETH_P_IPV6);
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_TRACE,"send to broadcast socket %d to %s\n",
dhcpSock->bcastSock, dhcpSock->name);
/* Send the raw IP packet */
rc = sendto(dhcpSock->bcastSock, datagram, datagramLen, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
if (rc != (S32)(datagramLen))
{
DML_LOG(DML_EVT_COMP_DHCP_CLIENT, DML_LOG_LVL_ERR, "sendto() failed: %s\n", strerror(errno));
return DML_ERROR;
}
return DML_OK;
}