Files
m241Neelima/components/ip_net2-6.9/ipdhcps/src/ipdhcps_packet.c
T
2026-07-30 11:19:44 +05:30

440 lines
14 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcps_packet.c,v $ $Revision: 1.24.10.4 $
* $Source: /home/interpeak/CVSRoot/ipdhcps/src/ipdhcps_packet.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
*
* Design and implementation by Jonas Rendel <jonas@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipdhcps_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_err.h>
#include <ipcom_inet.h>
#include <ipcom_os.h>
#include <ipcom_shell.h>
#include <ipcom_sock.h>
#include <ipcom_sock.h>
#include <ipcom_syslog.h>
#include <ipcom_tmo2.h>
#include <ipcom_type.h>
#include "ipdhcps.h"
#include "ipdhcps_h.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#ifndef IP_ETH_ADDR_SIZE
#define IP_ETH_ADDR_SIZE 6
#endif
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN Ipdhcps_data ipdhcpsc;
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC Ip_ssize_t ipdhcps_send_to_relay_agent(Ipdhcps_handle *handle);
IP_STATIC Ip_ssize_t ipdhcps_send_to_client (Ipdhcps_handle *handle,
Ip_bool force_broadcast);
IP_STATIC Ip_ssize_t ipdhcps_send_execute (Ipdhcps_handle *handle,
Ip_u32 dst, Ip_u16 port);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
IP_STATIC Ip_u8 chaddr_bcast[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcps_send_to_client
*===========================================================================
* Description: DHCP send routine used when transmitting to clients that
* can be reached directly (no relay agent inbetween).
* Because we can not assume that the client will respond to
* arp requests we can not use ordinary udp sockets. Instead
* we build raw DHCP/UDP/IP packets ourselves and transmit them
* on a packet socket using the clients link-layer address.but when
* it comes to INFORM MESSAGE, udp socket is a better choice.
*
* Parameters: handle - pointer to ipdhcps handle
* Returns: number of bytes sent. -1 if something failed.
*
*/
IP_STATIC Ip_ssize_t
ipdhcps_send_to_client(Ipdhcps_handle *handle, Ip_bool force_broadcast)
{
Ip_ssize_t retval;
Ip_u32 ciaddr;
Ip_u8 *chaddr;
int fd;
struct Ip_sockaddr_ll dest;
#define IPDHCPS_MSG_INFORM 8
if ( handle->saved_msg_type == IPDHCPS_MSG_INFORM&&handle->packet->hdr.ciaddr)
return ipdhcps_send_execute (handle, handle->packet->hdr.ciaddr, ipdhcpsc.config.client_port);
/* Get packet socket to write raw frames on */
if((fd = ipcom_socket(IP_AF_PACKET,
IP_SOCK_DGRAM,
ip_htons(IP_ETH_P_IP))) == IP_INVALID_SOCKET)
{
IPCOM_LOG0(DEBUG, "ipdhcps_send :: failed to get packet socket.");
IPDHCPS_LEAVE(-1);
}
/* Find out destination address */
if((force_broadcast == IP_TRUE)
|| (ip_ntohs(handle->packet->hdr.flags) & IPDHCPS_BROADCAST_FLAG))
{
/* Client must be broadcasted to */
ciaddr = IP_INADDR_BROADCAST;
chaddr = chaddr_bcast;
}
else if(handle->packet->hdr.ciaddr != 0)
{
/* Unicast packet to clients ciaddr */
ciaddr = handle->packet->hdr.ciaddr;
chaddr = handle->packet->hdr.chaddr;
}
else
{
/* Unicast packet to clients yiaddr */
ciaddr = handle->packet->hdr.yiaddr;
chaddr = handle->packet->hdr.chaddr;
}
/* Setup destination ll address */
ipcom_memset(&dest, 0, sizeof(dest));
dest.sll_family = IP_AF_PACKET;
dest.sll_protocol = ip_htons(IP_ETH_P_IP);
dest.sll_ifindex = (Ip_u32)handle->recv_if->ifindex;
dest.sll_halen = IP_ETH_ADDR_SIZE;
ipcom_memcpy(dest.sll_addr, chaddr, IP_ETH_ADDR_SIZE);
/* Clear IP and UDP headers */
ipcom_memset(handle->raw_packet,
0,
sizeof(Ipcom_ip_header) +
sizeof(Ipdhcps_udp_header));
/* Init headers */
handle->raw_packet->ip.protocol = IP_IPPROTO_UDP;
handle->raw_packet->ip.src.addr32 = handle->recv_if->siaddr;
handle->raw_packet->ip.dst.addr32 = ciaddr;
handle->raw_packet->udp.src_port = ip_htons(ipdhcpsc.config.server_port);
handle->raw_packet->udp.dst_port = ip_htons(ipdhcpsc.config.client_port);
handle->raw_packet->udp.length = (Ip_u16)(ip_htons(sizeof(Ipdhcps_udp_header) + handle->packet_len));
handle->raw_packet->ip.length = handle->raw_packet->udp.length;
/* Calculate UDP checksum (pseudo header+header+payload) */
handle->raw_packet->udp.checksum = ipcom_in_checksum((Ip_u16*)handle->raw_packet,
sizeof(Ipcom_ip_header) +
sizeof(Ipdhcps_udp_header) +
handle->packet_len );
handle->raw_packet->ip.length = (Ip_u16)(ip_htons(sizeof(Ipcom_ip_header) +
sizeof(Ipdhcps_udp_header) +
handle->packet_len));
handle->raw_packet->ip.vers_len = 0x40; /* Ipv4 */
handle->raw_packet->ip.vers_len |= sizeof(Ipcom_ip_header) / sizeof(Ip_u32);
handle->raw_packet->ip.ttl = 64;
handle->raw_packet->ip.checksum = ipcom_in_checksum((Ip_u16*)&handle->raw_packet->ip,
sizeof(Ipcom_ip_header));
/* Transmit packet */
retval = ipcom_sendto(fd,
handle->raw_packet,
(Ip_size_t) ip_ntohs(handle->raw_packet->ip.length),
0,
(struct Ip_sockaddr*) &dest,
sizeof(struct Ip_sockaddr_ll));
leave:
if(fd != IP_INVALID_SOCKET)
ipcom_socketclose(fd);
return retval;
}
/*
*===========================================================================
* ipdhcps_send_execute
*===========================================================================
* Description: DHCP send routine used when transmitting to clients that
* can be reached via a relay agent or the ACK is for INFORM.
* We use a standard udp socket to send the dhcp packet
*
* Parameters: handle - pointer to ipdhcps handle
* dst - destination
* port - remote port
* Returns: number of bytes sent. -1 if something failed.
*
*/
IP_STATIC Ip_ssize_t
ipdhcps_send_execute (Ipdhcps_handle *handle, Ip_u32 dst, Ip_u16 port)
{
Ip_ssize_t retval;
int opt;
int fd;
struct Ip_sockaddr_in addr;
if((fd = ipcom_socket(IP_AF_INET,
IP_SOCK_DGRAM,
IP_IPPROTO_UDP)) == IP_INVALID_SOCKET)
{
IPCOM_LOG0(DEBUG,"ipdhcps_send :: failed to get socket.");
IPDHCPS_LEAVE(-1);
}
opt = 1;
if(ipcom_setsockopt(fd,
IP_SOL_SOCKET,
IP_SO_REUSEADDR,
&opt,
sizeof(opt)) == -1)
{
IPCOM_LOG0(DEBUG, "ipdhcps_send :: failed to set sockopt.");
IPDHCPS_LEAVE(-1);
}
/* Bind socket to receiving interface */
memset(&addr, 0, sizeof(struct Ip_sockaddr_in));
addr.sin_family = IP_AF_INET;
addr.sin_port = ip_htons(ipdhcpsc.config.server_port);
addr.sin_addr.s_addr = handle->recv_if->siaddr;
if(ipcom_bind(fd,
(struct Ip_sockaddr*)&addr,
sizeof(struct Ip_sockaddr_in)) == -1)
{
IPCOM_LOG0(DEBUG, "ipdhcps_send :: failed to bind socket.");
IPDHCPS_LEAVE(-1);
}
/* Send to agent */
addr.sin_port = ip_htons(port);
addr.sin_addr.s_addr = dst;
retval = ipcom_sendto(fd,
handle->packet,
handle->packet_len,
0,
(struct Ip_sockaddr*)&addr,
sizeof(struct Ip_sockaddr_in));
leave:
if(fd != IP_INVALID_SOCKET)
ipcom_socketclose(fd);
return retval;
}
/*
*===========================================================================
* ipdhcps_send_to_relay_agent
*===========================================================================
* Description: DHCP send routine used when transmitting to clients that
* can only be reached via a relay agent.
* We use a standard udp socket to send the dhcp packet to
* the relay agent in question.
*
* Parameters: handle - pointer to ipdhcps handle
* Returns: number of bytes sent. -1 if something failed.
*
*/
IP_STATIC Ip_ssize_t
ipdhcps_send_to_relay_agent(Ipdhcps_handle *handle)
{
ip_assert(handle->packet != IP_NULL);
ip_assert(handle->packet->hdr.giaddr != 0);
return ipdhcps_send_execute (handle, handle->packet->hdr.giaddr, ipdhcpsc.config.server_port);
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcps_send_packet
*===========================================================================
* Description: Wrapper function for sending dhcp packets.
*
* Parameters: handle - pointer to ipdhcps handle
* Returns: number of bytes sent.
* -1 if something failed.
*/
IP_GLOBAL Ip_ssize_t
ipdhcps_send_packet(Ipdhcps_handle *handle, Ip_bool force_broadcast)
{
Ip_ssize_t retval;
if(handle->packet->hdr.giaddr != 0)
retval = ipdhcps_send_to_relay_agent(handle);
else
retval = ipdhcps_send_to_client(handle, force_broadcast);
return retval;
}
/*
*===========================================================================
* ipdhcps_receive_packet
*===========================================================================
* Description: This function is used for receiving packets of type DHCP.
* only packets of type DHCP received on interfaces define and
* enabled for IPDHCPS are forwarded to the caller.
*
* Parameters: fd - receive socket descriptor
* handle - ipdhcps handle
*
* Returns: number of bytes received.
* -1 if something failed.
*/
IP_GLOBAL Ip_ssize_t
ipdhcps_receive_packet(int fd, Ipdhcps_handle *handle)
{
struct Ip_msghdr msg;
struct Ip_iovec iov[1];
struct Ip_cmsghdr *cmptr;
struct Ip_in_pktinfo *pktinfo;
struct Ip_sockaddr_in src_addr;
Ip_ssize_t n;
union {
struct Ip_cmsghdr cm;
char control[IP_CMSG_SPACE(sizeof(struct Ip_in_pktinfo))];
} control_un;
iov[0].iov_base = handle->packet;
iov[0].iov_len =(Ip_size_t)ipdhcpsc.config.packet_size;
msg.msg_name = &src_addr;
msg.msg_namelen = sizeof(src_addr);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_flags = 0;
ipcom_memset(&src_addr, 0, sizeof(src_addr));
ipcom_memset(iov[0].iov_base, 0, iov[0].iov_len);
n = ipcom_recvmsg(fd, &msg, 0);
if(n > 0)
{
/* Get info about receiving interface */
if(((cmptr = IP_CMSG_FIRSTHDR(&msg)) != IP_NULL) &&
cmptr->cmsg_len == IP_CMSG_LEN(sizeof(struct Ip_in_pktinfo)))
{
pktinfo = (struct Ip_in_pktinfo*)IP_CMSG_DATA(cmptr);
handle->recv_if = ipdhcps_interface_find((int)pktinfo->ipi_ifindex);
handle->dst_addr = pktinfo->ipi_addr.s_addr;
handle->src_addr = src_addr.sin_addr.s_addr;
/* Drop if interface unknown */
if(handle->recv_if == IP_NULL)
{
IPCOM_LOG1(INFO,
"ipdhcps_daemon :: unable to locate interface %d",
pktinfo->ipi_ifindex);
return 0;
}
/* Drop if interface disabled */
if(handle->recv_if->enabled == IP_FALSE
|| handle->recv_if->functional == IP_FALSE)
return 0;
/* The vend data could be NULL in BOOTP */
if (ip_ntohl(handle->packet->hdr.cookie) == 0)
return n;
/* Drop if packet is not DHCP */
else if(ip_ntohl(handle->packet->hdr.cookie) != IPDHCPS_MAGIC_COOKIE)
return 0;
}
else
{
IPCOM_LOG0(DEBUG, "ipdhcps_receive :: got no interface info");
return 0;
}
}
return n;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/