📄 relay.c
字号:
}
/**********************************************************************
*%FUNCTION: initRelay
*%ARGUMENTS:
* nsess -- maximum allowable number of sessions
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Initializes relay hash table and session tables.
***********************************************************************/
void
initRelay(int nsess)
{
int i;
NumSessions = 0;
MaxSessions = nsess;
AllSessions = calloc(MaxSessions, sizeof(PPPoESession));
if (!AllSessions) {
rp_fatal("Unable to allocate memory for PPPoE session table");
}
AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));
if (!AllHashes) {
rp_fatal("Unable to allocate memory for PPPoE hash table");
}
/* Initialize sessions in a linked list */
AllSessions[0].prev = NULL;
if (MaxSessions > 1) {
AllSessions[0].next = &AllSessions[1];
} else {
AllSessions[0].next = NULL;
}
for (i=1; i<MaxSessions-1; i++) {
AllSessions[i].prev = &AllSessions[i-1];
AllSessions[i].next = &AllSessions[i+1];
}
if (MaxSessions > 1) {
AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2];
AllSessions[MaxSessions-1].next = NULL;
}
FreeSessions = AllSessions;
ActiveSessions = NULL;
/* Initialize session numbers which we hand out */
for (i=0; i<MaxSessions; i++) {
AllSessions[i].sesNum = htons((UINT16_t) i+1);
}
/* Initialize hashes in a linked list */
AllHashes[0].prev = NULL;
AllHashes[0].next = &AllHashes[1];
for (i=1; i<2*MaxSessions-1; i++) {
AllHashes[i].prev = &AllHashes[i-1];
AllHashes[i].next = &AllHashes[i+1];
}
AllHashes[2*MaxSessions-1].prev = &AllHashes[2*MaxSessions-2];
AllHashes[2*MaxSessions-1].next = NULL;
FreeHashes = AllHashes;
}
/**********************************************************************
*%FUNCTION: createSession
*%ARGUMENTS:
* ac -- Ethernet interface on access-concentrator side
* cli -- Ethernet interface on client side
* acMac -- Access concentrator's MAC address
* cliMac -- Client's MAC address
* acSess -- Access concentrator's session ID.
*%RETURNS:
* PPPoESession structure; NULL if one could not be allocated
*%DESCRIPTION:
* Initializes relay hash table and session tables.
***********************************************************************/
PPPoESession *
createSession(PPPoEInterface const *ac,
PPPoEInterface const *cli,
unsigned char const *acMac,
unsigned char const *cliMac,
UINT16_t acSes)
{
PPPoESession *sess;
SessionHash *acHash, *cliHash;
if (NumSessions >= MaxSessions) {
printErr("Maximum number of sessions reached -- cannot create new session");
return NULL;
}
/* Grab a free session */
sess = FreeSessions;
FreeSessions = sess->next;
NumSessions++;
/* Link it to the active list */
sess->next = ActiveSessions;
if (sess->next) {
sess->next->prev = sess;
}
ActiveSessions = sess;
sess->prev = NULL;
sess->epoch = Epoch;
/* Get two hash entries */
acHash = FreeHashes;
cliHash = acHash->next;
FreeHashes = cliHash->next;
acHash->peer = cliHash;
cliHash->peer = acHash;
sess->acHash = acHash;
sess->clientHash = cliHash;
acHash->interface = ac;
cliHash->interface = cli;
memcpy(acHash->peerMac, acMac, ETH_ALEN);
acHash->sesNum = acSes;
acHash->ses = sess;
memcpy(cliHash->peerMac, cliMac, ETH_ALEN);
cliHash->sesNum = sess->sesNum;
cliHash->ses = sess;
addHash(acHash);
addHash(cliHash);
/* Log */
syslog(LOG_INFO,
"Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)",
acHash->peerMac[0], acHash->peerMac[1],
acHash->peerMac[2], acHash->peerMac[3],
acHash->peerMac[4], acHash->peerMac[5],
acHash->interface->name,
ntohs(acHash->sesNum),
cliHash->peerMac[0], cliHash->peerMac[1],
cliHash->peerMac[2], cliHash->peerMac[3],
cliHash->peerMac[4], cliHash->peerMac[5],
cliHash->interface->name,
ntohs(cliHash->sesNum));
return sess;
}
/**********************************************************************
*%FUNCTION: freeSession
*%ARGUMENTS:
* ses -- session to free
* msg -- extra message to log on syslog.
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Frees data used by a PPPoE session -- adds hashes and session back
* to the free list
***********************************************************************/
void
freeSession(PPPoESession *ses, char const *msg)
{
syslog(LOG_INFO,
"Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s",
ses->acHash->peerMac[0], ses->acHash->peerMac[1],
ses->acHash->peerMac[2], ses->acHash->peerMac[3],
ses->acHash->peerMac[4], ses->acHash->peerMac[5],
ses->acHash->interface->name,
ntohs(ses->acHash->sesNum),
ses->clientHash->peerMac[0], ses->clientHash->peerMac[1],
ses->clientHash->peerMac[2], ses->clientHash->peerMac[3],
ses->clientHash->peerMac[4], ses->clientHash->peerMac[5],
ses->clientHash->interface->name,
ntohs(ses->clientHash->sesNum), msg);
/* Unlink from active sessions */
if (ses->prev) {
ses->prev->next = ses->next;
} else {
ActiveSessions = ses->next;
}
if (ses->next) {
ses->next->prev = ses->prev;
}
/* Link onto free list -- this is a singly-linked list, so
we do not care about prev */
ses->next = FreeSessions;
FreeSessions = ses;
unhash(ses->acHash);
unhash(ses->clientHash);
NumSessions--;
}
/**********************************************************************
*%FUNCTION: unhash
*%ARGUMENTS:
* sh -- session hash to free
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Frees a session hash -- takes it out of hash table and puts it on
* free list.
***********************************************************************/
void
unhash(SessionHash *sh)
{
unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
if (sh->prev) {
sh->prev->next = sh->next;
} else {
Buckets[b] = sh->next;
}
if (sh->next) {
sh->next->prev = sh->prev;
}
/* Add to free list (singly-linked) */
sh->next = FreeHashes;
FreeHashes = sh;
}
/**********************************************************************
*%FUNCTION: addHash
*%ARGUMENTS:
* sh -- a session hash
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Adds a SessionHash to the hash table
***********************************************************************/
void
addHash(SessionHash *sh)
{
unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
sh->next = Buckets[b];
sh->prev = NULL;
if (sh->next) {
sh->next->prev = sh;
}
Buckets[b] = sh;
}
/**********************************************************************
*%FUNCTION: hash
*%ARGUMENTS:
* mac -- an Ethernet address
* sesNum -- a session number
*%RETURNS:
* A hash value combining Ethernet address with session number.
* Currently very simplistic; we may need to experiment with different
* hash values.
***********************************************************************/
unsigned int
hash(unsigned char const *mac, UINT16_t sesNum)
{
unsigned int ans1 =
((unsigned int) mac[0]) |
(((unsigned int) mac[1]) << 8) |
(((unsigned int) mac[2]) << 16) |
(((unsigned int) mac[3]) << 24);
unsigned int ans2 =
((unsigned int) sesNum) |
(((unsigned int) mac[4]) << 16) |
(((unsigned int) mac[5]) << 24);
return ans1 ^ ans2;
}
/**********************************************************************
*%FUNCTION: findSession
*%ARGUMENTS:
* mac -- an Ethernet address
* sesNum -- a session number
*%RETURNS:
* The session hash for peer address "mac", session number sesNum
***********************************************************************/
SessionHash *
findSession(unsigned char const *mac, UINT16_t sesNum)
{
unsigned int b = hash(mac, sesNum) % HASHTAB_SIZE;
SessionHash *sh = Buckets[b];
while(sh) {
if (!memcmp(mac, sh->peerMac, ETH_ALEN) && sesNum == sh->sesNum) {
return sh;
}
sh = sh->next;
}
return NULL;
}
/**********************************************************************
*%FUNCTION: fatalSys
*%ARGUMENTS:
* str -- error message
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Prints a message plus the errno value to stderr and syslog and exits.
***********************************************************************/
void
fatalSys(char const *str)
{
char buf[1024];
sprintf(buf, "%.256s: %.256s", str, strerror(errno));
printErr(buf);
exit(EXIT_FAILURE);
}
/**********************************************************************
*%FUNCTION: sysErr
*%ARGUMENTS:
* str -- error message
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Prints a message plus the errno value to syslog.
***********************************************************************/
void
sysErr(char const *str)
{
char buf[1024];
sprintf(buf, "%.256s: %.256s", str, strerror(errno));
printErr(buf);
}
/**********************************************************************
*%FUNCTION: rp_fatal
*%ARGUMENTS:
* str -- error message
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Prints a message to stderr and syslog and exits.
***********************************************************************/
void
rp_fatal(char const *str)
{
printErr(str);
exit(EXIT_FAILURE);
}
/**********************************************************************
*%FUNCTION: relayLoop
*%ARGUMENTS:
* None
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Runs the relay loop. This function never returns
***********************************************************************/
void
relayLoop()
{
fd_set readable, readableCopy;
int maxFD;
int i, r;
int sock;
/* Build the select set */
FD_ZERO(&readable);
maxFD = 0;
for (i=0; i<NumInterfaces; i++) {
sock = Interfaces[i].discoverySock;
if (sock > maxFD) maxFD = sock;
FD_SET(sock, &readable);
sock = Interfaces[i].sessionSock;
if (sock > maxFD) maxFD = sock;
FD_SET(sock, &readable);
if (CleanPipe[0] > maxFD) maxFD = CleanPipe[0];
FD_SET(CleanPipe[0], &readable);
}
maxFD++;
for(;;) {
readableCopy = readable;
for(;;) {
r = select(maxFD, &readableCopy, NULL, NULL, NULL);
if (r >= 0 || errno != EINTR) break;
}
if (r < 0) {
sysErr("select (relayLoop)");
continue;
}
/* Handle session packets first */
for (i=0; i<NumInterfaces; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -