📄 relay.c
字号:
/* Set destination address to MAC address in relay ID */
memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
/* Set source address to MAC address of interface */
memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
/* Send the PADO to the proper client */
sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
}
/**********************************************************************
*%FUNCTION: relayHandlePADR
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADR packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADR packet.
***********************************************************************/
void
relayHandlePADR(PPPoEInterface const *iface,
PPPoEPacket *packet,
int size)
{
PPPoETag tag;
unsigned char *loc;
int ifIndex;
int cliIndex;
/* Can a client legally be behind this interface? */
if (!iface->clientOK) {
syslog(LOG_ERR,
"PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
cliIndex = iface - Interfaces;
/* Source address must be unicast */
if (NOT_UNICAST(packet->ethHdr.h_source)) {
syslog(LOG_ERR,
"PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* Destination address must be interface's MAC address */
if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
return;
}
/* Find relay tag */
loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
if (!loc) {
syslog(LOG_ERR,
"PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* If it's the wrong length, ignore it */
if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
syslog(LOG_ERR,
"PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* Extract interface index */
memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
if (ifIndex < 0 || ifIndex >= NumInterfaces ||
!Interfaces[ifIndex].acOK ||
iface == &Interfaces[ifIndex]) {
syslog(LOG_ERR,
"PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* Replace Relay-ID tag with opposite-direction tag */
memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex));
memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
/* Set destination address to MAC address in relay ID */
memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
/* Set source address to MAC address of interface */
memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
/* Send the PADR to the proper access concentrator */
sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
}
/**********************************************************************
*%FUNCTION: relayHandlePADS
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADS packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADS packet.
***********************************************************************/
void
relayHandlePADS(PPPoEInterface const *iface,
PPPoEPacket *packet,
int size)
{
PPPoETag tag;
unsigned char *loc;
int ifIndex;
int acIndex;
PPPoESession *ses = NULL;
SessionHash *sh;
/* Can a server legally be behind this interface? */
if (!iface->acOK) {
syslog(LOG_ERR,
"PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
acIndex = iface - Interfaces;
/* Source address must be unicast */
if (NOT_UNICAST(packet->ethHdr.h_source)) {
syslog(LOG_ERR,
"PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* Destination address must be interface's MAC address */
if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
return;
}
/* Find relay tag */
loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
if (!loc) {
syslog(LOG_ERR,
"PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* If it's the wrong length, ignore it */
if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
syslog(LOG_ERR,
"PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* Extract interface index */
memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
if (ifIndex < 0 || ifIndex >= NumInterfaces ||
!Interfaces[ifIndex].clientOK ||
iface == &Interfaces[ifIndex]) {
syslog(LOG_ERR,
"PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
packet->ethHdr.h_source[0],
packet->ethHdr.h_source[1],
packet->ethHdr.h_source[2],
packet->ethHdr.h_source[3],
packet->ethHdr.h_source[4],
packet->ethHdr.h_source[5],
iface->name);
return;
}
/* If session ID is zero, it's the AC respoding with an error.
Just relay it; do not create a session */
if (packet->session != htons(0)) {
/* Check for existing session */
sh = findSession(packet->ethHdr.h_source, packet->session);
if (sh) ses = sh->ses;
/* If already an existing session, assume it's a duplicate PADS. Send
the frame, but do not create a new session. Is this the right
thing to do? Arguably, should send an error to the client and
a PADT to the server, because this could happen due to a
server crash and reboot. */
if (!ses) {
/* Create a new session */
ses = createSession(iface, &Interfaces[ifIndex],
packet->ethHdr.h_source,
loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session);
if (!ses) {
/* Can't allocate session -- send error PADS to client and
PADT to server */
PPPoETag hostUniq, *hu;
if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) {
hu = &hostUniq;
} else {
hu = NULL;
}
relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex],
loc + TAG_HDR_SIZE + sizeof(ifIndex),
hu, "RP-PPPoE: Relay: Unable to allocate session");
relaySendError(CODE_PADT, packet->session, iface,
packet->ethHdr.h_source, NULL,
"RP-PPPoE: Relay: Unable to allocate session");
return;
}
}
/* Replace session number */
packet->session = ses->sesNum;
}
/* Remove relay-ID tag */
removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
/* Set destination address to MAC address in relay ID */
memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
/* Set source address to MAC address of interface */
memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
/* Send the PADS to the proper client */
sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
}
/**********************************************************************
*%FUNCTION: relaySendError
*%ARGUMENTS:
* code -- PPPoE packet code (PADS or PADT, typically)
* session -- PPPoE session number
* iface -- interface on which to send frame
* mac -- Ethernet address to which frame should be sent
* hostUniq -- if non-NULL, a hostUniq tag to add to error frame
* errMsg -- error message to insert into Generic-Error tag.
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Sends either a PADS or PADT packet with a Generic-Error tag and an
* error message.
***********************************************************************/
void
relaySendError(unsigned char code,
UINT16_t session,
PPPoEInterface const *iface,
unsigned char const *mac,
PPPoETag const *hostUniq,
char const *errMsg)
{
PPPoEPacket packet;
PPPoETag errTag;
int size;
memcpy(packet.ethHdr.h_source, iface->mac, ETH_ALEN);
memcpy(packet.ethHdr.h_dest, mac, ETH_ALEN);
packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
packet.type = 1;
packet.ver = 1;
packet.code = code;
packet.session = session;
packet.length = htons(0);
if (hostUniq) {
if (addTag(&packet, hostUniq) < 0) return;
}
errTag.type = htons(TAG_GENERIC_ERROR);
errTag.length = htons(strlen(errMsg));
strcpy(errTag.payload, errMsg);
if (addTag(&packet, &errTag) < 0) return;
size = ntohs(packet.length) + HDR_SIZE;
if (code == CODE_PADT) {
sendPacket(NULL, iface->discoverySock, &packet, size);
} else {
sendPacket(NULL, iface->sessionSock, &packet, size);
}
}
/**********************************************************************
*%FUNCTION: alarmHandler
*%ARGUMENTS:
* sig -- signal number
*%RETURNS:
* Nothing
*%DESCRIPTION:
* SIGALRM handler. Increments Epoch; if necessary, writes a byte of
* data to the alarm pipe to trigger the stale-session cleaner.
***********************************************************************/
void
alarmHandler(int sig)
{
alarm(1);
Epoch++;
CleanCounter++;
if (CleanCounter == CleanPeriod) {
write(CleanPipe[1], "", 1);
}
}
/**********************************************************************
*%FUNCTION: cleanSessions
*%ARGUMENTS:
* None
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Goes through active sessions and cleans sessions idle for longer
* than IdleTimeout seconds.
***********************************************************************/
void cleanSessions(void)
{
PPPoESession *cur, *next;
cur = ActiveSessions;
while(cur) {
next = cur->next;
if (Epoch - cur->epoch > IdleTimeout) {
/* Send PADT to each peer */
relaySendError(CODE_PADT, cur->acHash->sesNum,
cur->acHash->interface,
cur->acHash->peerMac, NULL,
"RP-PPPoE: Relay: Session exceeded idle timeout");
relaySendError(CODE_PADT, cur->clientHash->sesNum,
cur->clientHash->interface,
cur->clientHash->peerMac, NULL,
"RP-PPPoE: Relay: Session exceeded idle timeout");
freeSession(cur, "Idle Timeout");
}
cur = next;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -