Separate this functionality out of the net.c behemoth Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>master
parent
eafc8db0e3
commit
f575ae1f7d
@ -0,0 +1,375 @@ |
|||||||
|
/*
|
||||||
|
* Copied from Linux Monitor (LiMon) - Networking. |
||||||
|
* |
||||||
|
* Copyright 1994 - 2000 Neil Russell. |
||||||
|
* (See License) |
||||||
|
* Copyright 2000 Roland Borde |
||||||
|
* Copyright 2000 Paolo Scaffardi |
||||||
|
* Copyright 2000-2002 Wolfgang Denk, wd@denx.de |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <net.h> |
||||||
|
#if defined(CONFIG_CDP_VERSION) |
||||||
|
#include <timestamp.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "cdp.h" |
||||||
|
|
||||||
|
/* Ethernet bcast address */ |
||||||
|
const uchar NetCDPAddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc }; |
||||||
|
|
||||||
|
#define CDP_DEVICE_ID_TLV 0x0001 |
||||||
|
#define CDP_ADDRESS_TLV 0x0002 |
||||||
|
#define CDP_PORT_ID_TLV 0x0003 |
||||||
|
#define CDP_CAPABILITIES_TLV 0x0004 |
||||||
|
#define CDP_VERSION_TLV 0x0005 |
||||||
|
#define CDP_PLATFORM_TLV 0x0006 |
||||||
|
#define CDP_NATIVE_VLAN_TLV 0x000a |
||||||
|
#define CDP_APPLIANCE_VLAN_TLV 0x000e |
||||||
|
#define CDP_TRIGGER_TLV 0x000f |
||||||
|
#define CDP_POWER_CONSUMPTION_TLV 0x0010 |
||||||
|
#define CDP_SYSNAME_TLV 0x0014 |
||||||
|
#define CDP_SYSOBJECT_TLV 0x0015 |
||||||
|
#define CDP_MANAGEMENT_ADDRESS_TLV 0x0016 |
||||||
|
|
||||||
|
#define CDP_TIMEOUT 250UL /* one packet every 250ms */ |
||||||
|
|
||||||
|
static int CDPSeq; |
||||||
|
static int CDPOK; |
||||||
|
|
||||||
|
ushort CDPNativeVLAN; |
||||||
|
ushort CDPApplianceVLAN; |
||||||
|
|
||||||
|
static const uchar CDP_SNAP_hdr[8] = { |
||||||
|
0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 }; |
||||||
|
|
||||||
|
static ushort |
||||||
|
CDP_compute_csum(const uchar *buff, ushort len) |
||||||
|
{ |
||||||
|
ushort csum; |
||||||
|
int odd; |
||||||
|
ulong result = 0; |
||||||
|
ushort leftover; |
||||||
|
ushort *p; |
||||||
|
|
||||||
|
if (len > 0) { |
||||||
|
odd = 1 & (ulong)buff; |
||||||
|
if (odd) { |
||||||
|
result = *buff << 8; |
||||||
|
len--; |
||||||
|
buff++; |
||||||
|
} |
||||||
|
while (len > 1) { |
||||||
|
p = (ushort *)buff; |
||||||
|
result += *p++; |
||||||
|
buff = (uchar *)p; |
||||||
|
if (result & 0x80000000) |
||||||
|
result = (result & 0xFFFF) + (result >> 16); |
||||||
|
len -= 2; |
||||||
|
} |
||||||
|
if (len) { |
||||||
|
leftover = (signed short)(*(const signed char *)buff); |
||||||
|
/*
|
||||||
|
* CISCO SUCKS big time! (and blows too): |
||||||
|
* CDP uses the IP checksum algorithm with a twist; |
||||||
|
* for the last byte it *sign* extends and sums. |
||||||
|
*/ |
||||||
|
result = (result & 0xffff0000) | |
||||||
|
((result + leftover) & 0x0000ffff); |
||||||
|
} |
||||||
|
while (result >> 16) |
||||||
|
result = (result & 0xFFFF) + (result >> 16); |
||||||
|
|
||||||
|
if (odd) |
||||||
|
result = ((result >> 8) & 0xff) | |
||||||
|
((result & 0xff) << 8); |
||||||
|
} |
||||||
|
|
||||||
|
/* add up 16-bit and 17-bit words for 17+c bits */ |
||||||
|
result = (result & 0xffff) + (result >> 16); |
||||||
|
/* add up 16-bit and 2-bit for 16+c bit */ |
||||||
|
result = (result & 0xffff) + (result >> 16); |
||||||
|
/* add up carry.. */ |
||||||
|
result = (result & 0xffff) + (result >> 16); |
||||||
|
|
||||||
|
/* negate */ |
||||||
|
csum = ~(ushort)result; |
||||||
|
|
||||||
|
/* run time endian detection */ |
||||||
|
if (csum != htons(csum)) /* little endian */ |
||||||
|
csum = htons(csum); |
||||||
|
|
||||||
|
return csum; |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
CDPSendTrigger(void) |
||||||
|
{ |
||||||
|
uchar *pkt; |
||||||
|
ushort *s; |
||||||
|
ushort *cp; |
||||||
|
Ethernet_t *et; |
||||||
|
int len; |
||||||
|
ushort chksum; |
||||||
|
#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \ |
||||||
|
defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM) |
||||||
|
char buf[32]; |
||||||
|
#endif |
||||||
|
|
||||||
|
pkt = NetTxPacket; |
||||||
|
et = (Ethernet_t *)pkt; |
||||||
|
|
||||||
|
/* NOTE: trigger sent not on any VLAN */ |
||||||
|
|
||||||
|
/* form ethernet header */ |
||||||
|
memcpy(et->et_dest, NetCDPAddr, 6); |
||||||
|
memcpy(et->et_src, NetOurEther, 6); |
||||||
|
|
||||||
|
pkt += ETHER_HDR_SIZE; |
||||||
|
|
||||||
|
/* SNAP header */ |
||||||
|
memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)); |
||||||
|
pkt += sizeof(CDP_SNAP_hdr); |
||||||
|
|
||||||
|
/* CDP header */ |
||||||
|
*pkt++ = 0x02; /* CDP version 2 */ |
||||||
|
*pkt++ = 180; /* TTL */ |
||||||
|
s = (ushort *)pkt; |
||||||
|
cp = s; |
||||||
|
/* checksum (0 for later calculation) */ |
||||||
|
*s++ = htons(0); |
||||||
|
|
||||||
|
/* CDP fields */ |
||||||
|
#ifdef CONFIG_CDP_DEVICE_ID |
||||||
|
*s++ = htons(CDP_DEVICE_ID_TLV); |
||||||
|
*s++ = htons(CONFIG_CDP_DEVICE_ID); |
||||||
|
sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther); |
||||||
|
memcpy((uchar *)s, buf, 16); |
||||||
|
s += 16 / 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_PORT_ID |
||||||
|
*s++ = htons(CDP_PORT_ID_TLV); |
||||||
|
memset(buf, 0, sizeof(buf)); |
||||||
|
sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index()); |
||||||
|
len = strlen(buf); |
||||||
|
if (len & 1) /* make it even */ |
||||||
|
len++; |
||||||
|
*s++ = htons(len + 4); |
||||||
|
memcpy((uchar *)s, buf, len); |
||||||
|
s += len / 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_CAPABILITIES |
||||||
|
*s++ = htons(CDP_CAPABILITIES_TLV); |
||||||
|
*s++ = htons(8); |
||||||
|
*(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES); |
||||||
|
s += 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_VERSION |
||||||
|
*s++ = htons(CDP_VERSION_TLV); |
||||||
|
memset(buf, 0, sizeof(buf)); |
||||||
|
strcpy(buf, CONFIG_CDP_VERSION); |
||||||
|
len = strlen(buf); |
||||||
|
if (len & 1) /* make it even */ |
||||||
|
len++; |
||||||
|
*s++ = htons(len + 4); |
||||||
|
memcpy((uchar *)s, buf, len); |
||||||
|
s += len / 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_PLATFORM |
||||||
|
*s++ = htons(CDP_PLATFORM_TLV); |
||||||
|
memset(buf, 0, sizeof(buf)); |
||||||
|
strcpy(buf, CONFIG_CDP_PLATFORM); |
||||||
|
len = strlen(buf); |
||||||
|
if (len & 1) /* make it even */ |
||||||
|
len++; |
||||||
|
*s++ = htons(len + 4); |
||||||
|
memcpy((uchar *)s, buf, len); |
||||||
|
s += len / 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_TRIGGER |
||||||
|
*s++ = htons(CDP_TRIGGER_TLV); |
||||||
|
*s++ = htons(8); |
||||||
|
*(ulong *)s = htonl(CONFIG_CDP_TRIGGER); |
||||||
|
s += 2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_POWER_CONSUMPTION |
||||||
|
*s++ = htons(CDP_POWER_CONSUMPTION_TLV); |
||||||
|
*s++ = htons(6); |
||||||
|
*s++ = htons(CONFIG_CDP_POWER_CONSUMPTION); |
||||||
|
#endif |
||||||
|
|
||||||
|
/* length of ethernet packet */ |
||||||
|
len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE); |
||||||
|
et->et_protlen = htons(len); |
||||||
|
|
||||||
|
len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr); |
||||||
|
chksum = CDP_compute_csum((uchar *)NetTxPacket + len, |
||||||
|
(uchar *)s - (NetTxPacket + len)); |
||||||
|
if (chksum == 0) |
||||||
|
chksum = 0xFFFF; |
||||||
|
*cp = htons(chksum); |
||||||
|
|
||||||
|
(void) eth_send(NetTxPacket, (uchar *)s - NetTxPacket); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
CDPTimeout(void) |
||||||
|
{ |
||||||
|
CDPSeq++; |
||||||
|
|
||||||
|
if (CDPSeq < 3) { |
||||||
|
NetSetTimeout(CDP_TIMEOUT, CDPTimeout); |
||||||
|
CDPSendTrigger(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
/* if not OK try again */ |
||||||
|
if (!CDPOK) |
||||||
|
NetStartAgain(); |
||||||
|
else |
||||||
|
NetState = NETLOOP_SUCCESS; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
CDPDummyHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, |
||||||
|
unsigned len) |
||||||
|
{ |
||||||
|
/* nothing */ |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
CDPHandler(const uchar *pkt, unsigned len) |
||||||
|
{ |
||||||
|
const uchar *t; |
||||||
|
const ushort *ss; |
||||||
|
ushort type, tlen; |
||||||
|
ushort vlan, nvlan; |
||||||
|
|
||||||
|
/* minimum size? */ |
||||||
|
if (len < sizeof(CDP_SNAP_hdr) + 4) |
||||||
|
goto pkt_short; |
||||||
|
|
||||||
|
/* check for valid CDP SNAP header */ |
||||||
|
if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0) |
||||||
|
return; |
||||||
|
|
||||||
|
pkt += sizeof(CDP_SNAP_hdr); |
||||||
|
len -= sizeof(CDP_SNAP_hdr); |
||||||
|
|
||||||
|
/* Version of CDP protocol must be >= 2 and TTL != 0 */ |
||||||
|
if (pkt[0] < 0x02 || pkt[1] == 0) |
||||||
|
return; |
||||||
|
|
||||||
|
/*
|
||||||
|
* if version is greater than 0x02 maybe we'll have a problem; |
||||||
|
* output a warning |
||||||
|
*/ |
||||||
|
if (pkt[0] != 0x02) |
||||||
|
printf("**WARNING: CDP packet received with a protocol version " |
||||||
|
"%d > 2\n", pkt[0] & 0xff); |
||||||
|
|
||||||
|
if (CDP_compute_csum(pkt, len) != 0) |
||||||
|
return; |
||||||
|
|
||||||
|
pkt += 4; |
||||||
|
len -= 4; |
||||||
|
|
||||||
|
vlan = htons(-1); |
||||||
|
nvlan = htons(-1); |
||||||
|
while (len > 0) { |
||||||
|
if (len < 4) |
||||||
|
goto pkt_short; |
||||||
|
|
||||||
|
ss = (const ushort *)pkt; |
||||||
|
type = ntohs(ss[0]); |
||||||
|
tlen = ntohs(ss[1]); |
||||||
|
if (tlen > len) |
||||||
|
goto pkt_short; |
||||||
|
|
||||||
|
pkt += tlen; |
||||||
|
len -= tlen; |
||||||
|
|
||||||
|
ss += 2; /* point ss to the data of the TLV */ |
||||||
|
tlen -= 4; |
||||||
|
|
||||||
|
switch (type) { |
||||||
|
case CDP_DEVICE_ID_TLV: |
||||||
|
break; |
||||||
|
case CDP_ADDRESS_TLV: |
||||||
|
break; |
||||||
|
case CDP_PORT_ID_TLV: |
||||||
|
break; |
||||||
|
case CDP_CAPABILITIES_TLV: |
||||||
|
break; |
||||||
|
case CDP_VERSION_TLV: |
||||||
|
break; |
||||||
|
case CDP_PLATFORM_TLV: |
||||||
|
break; |
||||||
|
case CDP_NATIVE_VLAN_TLV: |
||||||
|
nvlan = *ss; |
||||||
|
break; |
||||||
|
case CDP_APPLIANCE_VLAN_TLV: |
||||||
|
t = (const uchar *)ss; |
||||||
|
while (tlen > 0) { |
||||||
|
if (tlen < 3) |
||||||
|
goto pkt_short; |
||||||
|
|
||||||
|
ss = (const ushort *)(t + 1); |
||||||
|
|
||||||
|
#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE |
||||||
|
if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE) |
||||||
|
vlan = *ss; |
||||||
|
#else |
||||||
|
/* XXX will this work; dunno */ |
||||||
|
vlan = ntohs(*ss); |
||||||
|
#endif |
||||||
|
t += 3; tlen -= 3; |
||||||
|
} |
||||||
|
break; |
||||||
|
case CDP_TRIGGER_TLV: |
||||||
|
break; |
||||||
|
case CDP_POWER_CONSUMPTION_TLV: |
||||||
|
break; |
||||||
|
case CDP_SYSNAME_TLV: |
||||||
|
break; |
||||||
|
case CDP_SYSOBJECT_TLV: |
||||||
|
break; |
||||||
|
case CDP_MANAGEMENT_ADDRESS_TLV: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
CDPApplianceVLAN = vlan; |
||||||
|
CDPNativeVLAN = nvlan; |
||||||
|
|
||||||
|
CDPOK = 1; |
||||||
|
return; |
||||||
|
|
||||||
|
pkt_short: |
||||||
|
printf("** CDP packet is too short\n"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
CDPStart(void) |
||||||
|
{ |
||||||
|
printf("Using %s device\n", eth_get_name()); |
||||||
|
CDPSeq = 0; |
||||||
|
CDPOK = 0; |
||||||
|
|
||||||
|
CDPNativeVLAN = htons(-1); |
||||||
|
CDPApplianceVLAN = htons(-1); |
||||||
|
|
||||||
|
NetSetTimeout(CDP_TIMEOUT, CDPTimeout); |
||||||
|
NetSetHandler(CDPDummyHandler); |
||||||
|
|
||||||
|
CDPSendTrigger(); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
/*
|
||||||
|
* Copied from Linux Monitor (LiMon) - Networking. |
||||||
|
* |
||||||
|
* Copyright 1994 - 2000 Neil Russell. |
||||||
|
* (See License) |
||||||
|
* Copyright 2000 Roland Borde |
||||||
|
* Copyright 2000 Paolo Scaffardi |
||||||
|
* Copyright 2000-2002 Wolfgang Denk, wd@denx.de |
||||||
|
*/ |
||||||
|
|
||||||
|
#if defined(CONFIG_CMD_CDP) |
||||||
|
|
||||||
|
#ifndef __CDP_H__ |
||||||
|
#define __CDP_H__ |
||||||
|
|
||||||
|
void CDPStart(void); |
||||||
|
void CDPHandler(const uchar *pkt, unsigned len); |
||||||
|
|
||||||
|
#endif /* __CDP_H__ */ |
||||||
|
#endif |
Loading…
Reference in new issue