Commit 4e14a98a authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'lldp' into proposed_master

parents eae94a74 51d9336f
......@@ -554,3 +554,11 @@ config PPSI
boolean
help
Select this option for the ppsi engine (now only option)
config LLDP
depends on DEVELOPER
boolean "Include LLDP protocol transmit-only"
help
This enable LLDP support. LLDP is a vendor-neutral link layer protocol
used by network devices for advertising their identity, capabilities,
and neighbors on local area network.
......@@ -11,3 +11,4 @@ obj-$(CONFIG_IP) += lib/ipv4.o lib/arp.o lib/icmp.o lib/udp.o lib/bootp.o
obj-$(CONFIG_SYSLOG) += lib/syslog.o
obj-$(CONFIG_LATENCY_PROBE) += lib/latency.o
obj-$(CONFIG_SNMP) += lib/snmp.o
obj-$(CONFIG_LLDP) += lib/lldp.o
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 GSI (www.gsi.de)
* Author: Cesar Prados <c.prados@gsi.de>
*
* LLDP transmit-only station
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <string.h>
#include "revision.h"
#include "ptpd_netif.h"
#include "lldp.h"
#include "endpoint.h"
#include "ipv4.h"
#include "shell.h"
#include <wrpc.h> /*needed for htons()*/
static char lldpdu[LLDP_PKT_LEN];
static uint16_t lldpdu_len;
/* tx-only socket */
static struct wrpc_socket __static_lldp_socket = {
.queue.buff = NULL,
.queue.size = 0,
};
static struct wrpc_socket *lldp_socket;
static struct wr_sockaddr addr;
static void lldp_header_tlv(int tlv_type) {
lldpdu_len = tlv_offset[tlv_type];
lldpdu[lldpdu_len] = tlv_type * 2;
lldpdu[lldpdu_len + LLDP_SUBTYPE] = tlv_type_len[tlv_type];
lldpdu_len += LLDP_HEADER;
}
static void lldp_add_tlv(int tlv_type) {
unsigned char mac[6];
unsigned char ipWR[4];
switch(tlv_type) {
case END_LLDP:
/* header */
lldp_header_tlv(tlv_type);
/* End TLV */
memcpy(lldpdu + lldpdu_len, 0x0, tlv_type_len[tlv_type]);
break;
case CHASSIS_ID:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Chassis Component */
lldpdu[lldpdu_len] = 4;
get_mac_addr(mac);
memcpy(lldpdu + (lldpdu_len + LLDP_SUBTYPE), mac, 6);
break;
case PORT_ID:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Interce Alias */
lldpdu[lldpdu_len] = 7;
strcpy(lldpdu + (lldpdu_len + LLDP_SUBTYPE), "WR Port");
break;
case TTL:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Time to Live */
lldpdu[lldpdu_len + LLDP_SUBTYPE] = 0x20; /* sec */
break;
case PORT:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Info srting */
if (HAS_IP) {
getIP(ipWR);
char buf[32];
format_ip(buf, ipWR);
strcpy(lldpdu + lldpdu_len, buf);
}
break;
case SYS_NAME:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Info srting */
/* TODO get host system name from wr-core outer world */
strcpy(lldpdu + lldpdu_len, "WR PTP Core");
break;
case SYS_DESCR:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Info srting */
strcpy(lldpdu + lldpdu_len, build_revision);
break;
case SYS_CAPLTY:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Info string */
memset(lldpdu + lldpdu_len, 0x0, 4);
break;
case MNG_ADD:
/* header */
lldp_header_tlv(tlv_type);
/* TLV Info string */
/* TODO get host system name from wr-core outer world */
lldpdu[lldpdu_len] = 0x4; /* len */
lldpdu[lldpdu_len + LLDP_SUBTYPE] = 0x1; /* mngt add subtype */
lldpdu[lldpdu_len + IF_SUBTYPE] = 0x1; /* if subtype */
lldpdu[lldpdu_len + IF_NUM] = 0x1; /* if number */
break;
case USER_DEF:
/* TODO define WR TLV */
break;
default:
break;
}
}
static void lldp_init(void)
{
struct wr_sockaddr saddr;
int i;
/* LLDP: raw ethernet*/
memset(&saddr, 0x0, sizeof(saddr));
saddr.ethertype = htons(LLDP_ETH_TYP);
lldp_socket = ptpd_netif_create_socket(&__static_lldp_socket, &saddr,
PTPD_SOCK_RAW_ETHERNET, 0);
memset(&addr, 0x0, sizeof(struct wr_sockaddr));
memcpy(addr.mac, LLDP_MCAST_MAC, 6);
/* add mandatory LLDP TLVs */
memset(lldpdu, 0x0, LLDP_PKT_LEN);
lldpdu_len = 0;
for (i=CHASSIS_ID; i <= SYS_CAPLTY; i++)
lldp_add_tlv(i);
/* add optional TLVs */
lldp_add_tlv(MNG_ADD);
/* end TLVs */
lldp_add_tlv(END_LLDP);
}
static int lldp_poll(void)
{
static int ticks;
/* periodic tasks */
if (ticks > LLDP_TX_FQ) {
if (HAS_IP && (ip_status != IP_TRAINING)) {
lldp_add_tlv(PORT);
/* update other dynamic TLVs */
}
ptpd_netif_sendto(lldp_socket, &addr, lldpdu, LLDP_PKT_LEN, 0);
ticks = 0;
return 1;
} else {
ticks += 1;
return 0;
}
}
DEFINE_WRC_TASK(lldp) = {
.name = "lldp",
.init = lldp_init,
.job = lldp_poll,
};
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 GSI (www.gsi.de)
* Author: Cesar Prados <c.prados@gsi.de>
*
* LLDP transmit-only station
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#ifndef __LLDP_H
#define __LLDP_H
#define LLDP_MCAST_MAC "\x01\x80\xC2\x00\x00\x0E"
#define LLDP_ETH_TYP 0x88CC
#define LLDP_PKT_LEN 0x9E /* 158 bytes */
#define TLV_MAX 0xA
#define LLDP_HEADER 0x2
#define LLDP_SUBTYPE 0x1
#define IF_SUBTYPE 0x6
#define IF_NUM 0x10
#define LLDP_TX_FQ 1000
enum TLV_TYPE { END_LLDP = 0, /* mandatory TLVs */
CHASSIS_ID,
PORT_ID,
TTL,
PORT, /* optional TLVs */
SYS_NAME,
SYS_DESCR,
SYS_CAPLTY,
MNG_ADD,
USER_DEF
};
uint16_t tlv_type_len[TLV_MAX] = { 0x0, /* LEN_LLDP_END */
0x7, /* LEN_CHASSIS_ID */
0x14, /* LEN_PORT_ID */
0x2, /* LEN_TTL */
0x14, /* LEN_PORT */
0x14, /* LEN_SYS_NAME */
0x14, /* LEN_SYS_DESCR */
0x4, /* LEN_SYS_CAPLTY */
0xC /* LEN_MNG_ADD */
};
uint16_t tlv_offset[TLV_MAX] = { 0x79, /* LEN_LLDP_END */
0x0, /* LEN_CHASSIS_ID */
0x9, /* LEN_PORT_ID */
0x1F, /* LEN_TTL */
0x23, /* LEN_PORT */
0x39, /* LEN_SYS_NAME */
0x4F, /* LEN_SYS_DESCR */
0x65, /* LEN_SYS_CAPLTY */
0x6B /* LEN_MNG_ADD */
};
#endif /* __LLDP_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment