该主要数lldp报文的缓存和缓存报文的发送,以及一些原始套接字的创建和本地基本信息的获取。
一些主要函数如下:
int socketInitializeLLDP(struct lldp_port *lldp_port)
{
struct ifreq *ifr = calloc(1, sizeof(struct ifreq));
struct sockaddr_ll *sll = calloc(1, sizeof(struct sockaddr_ll));
int retval = 0;
if(lldp_port->if_name == NULL)
{
debug_printf(DEBUG_NORMAL, "Got NULL interface in %s():%d\n", __FUNCTION__, __LINE__);
return XENOSOCK;
}
if(lldp_port->if_index <= 0)
{
debug_printf(DEBUG_NORMAL, "'%s' does not appear to be a valid interface name!\n", lldp_port->if_name);
return XENOSOCK;
}
debug_printf(DEBUG_INT, "'%s' is index %d\n", lldp_port->if_name, lldp_port->if_index);
/*
创建原始套接字,选择协议号0x88cc
*/
// Set up the raw socket for the LLDP ethertype
lldp_port->socket = socket(PF_PACKET, SOCK_RAW, htons(0x88CC));
if(lldp_port->socket < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't initialize raw socket for interface %s!\n", lldp_port->if_name);
return XENOSOCK;
}
// Set up the interface for binding
sll->sll_family = PF_PACKET;
sll->sll_ifindex = lldp_port->if_index;
sll->sll_protocol = htons(0x88CC);
// Bind the socket and the interface together to form a useable socket:
retval = bind(lldp_port->socket, (struct sockaddr *)sll, sizeof(struct sockaddr_ll));
if(retval < 0) {
debug_printf(DEBUG_NORMAL, "Error binding raw socket to interface %s in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
return XENOSOCK;
}
ifr->ifr_ifindex = lldp_port->if_index;
strncpy(ifr->ifr_name, &lldp_port->if_name[0], strlen(lldp_port->if_name));
if(strlen(ifr->ifr_name) == 0) {
debug_printf(DEBUG_NORMAL, "Invalid interface name in %s():%d\n", __FUNCTION__, __LINE__);
return XENOSOCK;
}
/* retval = _getmac(lldp_port);
if(retval < 0) {
debug_printf(DEBUG_NORMAL, "Error getting hardware (MAC) address for interface '%s' in %s():%d - %d:%s!\n", lldp_port->if_name, __FUNCTION__, __LINE__, errno, strerror(errno));
return retval;
}
retval = _getip(lldp_port);
if (retval < 0) {
debug_printf(DEBUG_NORMAL, "Error getting interface IP address for interface '%s' in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
}*/
refreshInterfaceData(lldp_port);
retval = ioctl(lldp_port->socket, SIOCGIFFLAGS, ifr);
if (retval == -1)
{
debug_printf(DEBUG_NORMAL, "Can't get flags for interface '%s' in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
}
if ((ifr->ifr_flags & IFF_UP) == 0) {
debug_printf(DEBUG_INT, "Interface '%s' is down. portEnabled = 0.\n", lldp_port->if_name);
lldp_port->portEnabled = 0;
}
// set allmulti on interface
// need to devise a graceful way to turn off allmulti otherwise it is left on for the interface when problem is terminated.
retval = ioctl(lldp_port->socket, SIOCGIFFLAGS, ifr);
if (retval == -1)
{
debug_printf(DEBUG_NORMAL, "Can't get flags for interface '%s' in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
}
/*
由于lldp交互的数据报文为多播报文,故此这里要设置端口接收并处理多播报文。若不这么设置,端口是接收不到多播报文的。
*/
ifr->ifr_flags |= IFF_ALLMULTI; // allmulti on (verified via ifconfig)
// ifr.ifr_flags &= ~IFF_ALLMULTI; // allmulti off (I think)
retval = ioctl(lldp_port->socket, SIOCSIFFLAGS, ifr);
if (retval == -1)
{
debug_printf(DEBUG_NORMAL, "Can't set flags for interface '%s' in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
}
// Discover MTU of our interface.
retval = ioctl(lldp_port->socket, SIOCGIFMTU, ifr);
if(retval < 0)
{
debug_printf(DEBUG_NORMAL, "Can't determine MTU for interface '%s' in %s():%d!\n", lldp_port->if_name, __FUNCTION__, __LINE__);
return retval;
}
lldp_port->mtu = ifr->ifr_ifru.ifru_mtu;
debug_printf(DEBUG_INT, "[%s] MTU is %d\n", lldp_port->if_name, lldp_port->mtu);
lldp_port->rx.frame = calloc(1, lldp_port->mtu - 4);
lldp_port->tx.frame = calloc(1, (lldp_port->mtu - 2));
if(!lldp_port->rx.frame) {
debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__);
} else {
debug_printf(DEBUG_INT, "Created framebuffer for %s at %x\n", lldp_port->if_name, &lldp_port->rx.frame);
}
if(!lldp_port->tx.frame) {
debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__);
} else {
debug_printf(DEBUG_INT, "Created framebuffer for %s at %x\n", lldp_port->if_name, &lldp_port->tx.frame);
}
debug_printf(DEBUG_INT, "Interface (%s) MTU is %d.\n", lldp_port->if_name, lldp_port->mtu);
free(ifr);
free(sll);
return 0;
}
其他_getmac和_getip就较为简单了,只是使用了ioctl系统调用来获取系统的MAC和IP等信息。
ssize_t lldp_write(struct lldp_port *lldp_port) {
/*
将在lldp_port->tx.frame中缓存的数据通过套接字发送出去发送出去
*/
// Write the frame to the wire
return sendto(lldp_port->socket, lldp_port->tx.frame, lldp_port->tx.sendsize, 0, NULL, 0);
}
ssize_t lldp_read(struct lldp_port *lldp_port) {
/*
将从套接字接收的数据缓存到lldp_port->rx.frame中
*/
lldp_port->rx.recvsize = recvfrom(lldp_port->socket, lldp_port->rx.frame, lldp_port->mtu, 0, 0, 0);
return(lldp_port->rx.recvsize);
}
在后面可以看到,该实现对于每一个底层接口都创建了一个原始套接字,并且使用select进行套接字的复用。这样每个接口的数据收发不会影响到其他底层接口。
本人享有博客文章的版权,转载请标明出处http://blog.csdn.net/baidu20008