Files
m241Neelima/components/ip_net2-6.9/ipppp/src/ipppp_pppoe.c
T
2026-07-30 11:19:44 +05:30

1844 lines
62 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipppp_pppoe.c,v $ $Revision: 1.59.10.10 $
* $Source: /home/interpeak/CVSRoot/ipppp/src/ipppp_pppoe.c,v $
* $Author: csun $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Lennart Bang <lob@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* PPPoE implementation for IPPPP based on the following RFC:
* ==============================================================
* RFC 2516 - A Method for Transmitting PPP Over Ethernet (PPPoE)
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipppp_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPPPP_USE_PPPOE
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_err.h>
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
#include "ipppp_h.h"
#ifdef IPNET
#include <ipnet_h.h>
#include <ipnet_eth.h>
#elif defined(IPLITE)
#include <iplite_h.h>
#else
#error MUST_CHOOSE_STACK
#endif
#ifdef OPENSSL_FIPS
#include <openssl/fips.h>
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPPPP_PPPOE_LINK_INDEX 0 /* no reason to run MPPP on PPPoE */
#define PPPOE_TYPE_CLIENT 0
#define PPPOE_TYPE_SERVER 1
#define PPPOE_SESSIONID_WRAP_THRESHOLD 0x8000
/*
*===========================================================================
* Ethernet stuff
*===========================================================================
*/
#define IPPPP_PPPOE_MAC_DIS 0x8863
#define IPPPP_PPPOE_MAC_SES 0x8864
#define IPPPP_ETH_ADDR_SIZE 6
/*
*===========================================================================
* PPPoE tags
*===========================================================================
*/
#define IPPPP_PPPOE_TAG_HSIZE 4
#define IPPPP_PPPOE_NON_ALGORITHM_LENGTH 4
#define IPPPP_PPPOE_TAG_SET16(xpay, xlen, val16) \
do { \
xpay[xlen] = (Ip_u8)((val16 & 0xff00) >> 8); \
xlen++; \
xpay[xlen] = (Ip_u8)((val16 & 0x00ff)); \
xlen++; \
} while(0)
#define IPPPP_PPPOE_TAG_End_Of_List 0x0000
#define IPPPP_PPPOE_TAG_Service_Name 0x0101
#define IPPPP_PPPOE_TAG_AC_Name 0x0102
#define IPPPP_PPPOE_TAG_Host_Uniq 0x0103
#define IPPPP_PPPOE_TAG_AC_Cookie 0x0104
#define IPPPP_PPPOE_TAG_Vendor_Specific 0x0105
#define IPPPP_PPPOE_TAG_Relay_Session_Id 0x0110
#define IPPPP_PPPOE_TAG_Service_Name_Error 0x0201
#define IPPPP_PPPOE_TAG_AC_System_Error 0x0202
#define IPPPP_PPPOE_TAG_Generic_Error 0x0203
#ifdef IPNET
#define IPSTACK_TIMEOUT_SCHEDULE ipnet_timeout_schedule
#define IPSTACK_TIMEOUT_CANCEL ipnet_timeout_cancel
#define Ipstack_timeout_handler Ipnet_timeout_handler
#define Ipstack_timeout Ipnet_timeout
#else
#define IPSTACK_TIMEOUT_SCHEDULE iplite_timeout_schedule
#define IPSTACK_TIMEOUT_CANCEL iplite_timeout_cancel
#define Ipstack_timeout_handler Iplite_timeout_handler
#define Ipstack_timeout Iplite_timeout
#endif
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipppp_pkt_pppoe_struct
{
Ip_u8 ver_type; /* Version and code, always 0x11 */
Ip_u8 code;
Ip_u16 session_id;
Ip_u16 length;
Ip_u8 payload[1];
}
Ipppp_pkt_pppoe;
/*
*===========================================================================
* Ipppp_pkt_eth
*===========================================================================
* PPPoeE header from RFC 2516.
*/
typedef struct Ipppp_pkt_eth_struct
{
Ip_u8 eth_dst[6]; /* Destination Ethernet address. */
Ip_u8 eth_src[6]; /* Sender Ethernet address. */
Ip_u16 eth_type; /* Ethernet type, e.g. IP = 0x0800 etc. */
}
Ipppp_pkt_eth;
/* PPPoE ver_type value. */
#define IPPPP_PPPOE_HDR_VERTYPE 0x11
/* PPPoE code */
#define IPPPP_PPPOE_HDR_CODE_PADI 0x9
#define IPPPP_PPPOE_HDR_CODE_PADO 0x7
#define IPPPP_PPPOE_HDR_CODE_PADR 0x19
#define IPPPP_PPPOE_HDR_CODE_PADS 0x65
#define IPPPP_PPPOE_HDR_CODE_PADT 0xa7
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN Ipppp_data ipppp;
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC void ipppp_pppoe_if_detach(Ipcom_netif *pppif);
IP_STATIC Ipcom_netif *ipppp_pppoe_if_malloc(char *ifname, int iftype);
IP_STATIC void ipppp_pppoe_timeout(Ipcom_netif *ethif);
IP_STATIC void ipppp_pppoe_send_padi(Ipcom_netif *ethif);
IP_GLOBAL int ipppp_pppoe_input(Ipcom_netif *ethif, Ipcom_pkt *pkt);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
* Ethernet broadcast MAC
*/
const Ip_u16 ipppp_eth_addr_broadcast_storage[] = {
0xffff, 0xffff, 0xffff
};
const Ip_u8 *ipppp_eth_addr_broadcast = (Ip_u8 *) ipppp_eth_addr_broadcast_storage;
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipppp_pppoe_set_cookie
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IPPPP_PPPOE_USE_MD5
IP_STATIC void
ipppp_pppoe_set_cookie(Ip_u8 *buf, Ip_u8 *eth_src)
{
MD5_CTX ctx;
char *name;
Ip_size_t namelen;
#ifdef OPENSSL_FIPS
if (FIPS_mode())
{
ipppp_log(IPCOM_LOG_WARNING,IP_NULL, IP_NULL, "<ippppoe> :: ipppp_pppoe_set_cookie with MD5 as OPENSSL FIPS is not enabled");
return;
}
#endif
MD5_Init(&ctx);
MD5_Update(&ctx, eth_src, 6);
MD5_Update(&ctx, ipppp.pppoe.secret, IPPPP_PPPOE_SECRET_SIZE);
namelen = sizeof(ipppp.buf);
name = ipcom_sysvar_get("ipppp.pppoe.secret_name", ipppp.buf, &namelen);
if (name)
{
namelen = ipcom_strlen(name);
MD5_Update(&ctx, name, namelen);
}
MD5_Final(buf, &ctx);
}
#endif /* IPPPP_PPPOE_USE_MD5 */
/*
*===========================================================================
* ipppp_pppoe_find_netif
*===========================================================================
* Description: Given the ifindex of an ethernet I/F,
* check all the pppoe interfaces that are attached to it
* Parameters:
* Returns:
*
*/
IP_STATIC Ipcom_netif *
ipppp_pppoe_find_netif(Ip_u32 ethindex)
{
Ipcom_netif * netif = IP_NULL;
Ipppp_netif * pppif;
Ip_u32 i;
#ifdef IPPPP_USE_PPPMP
Ip_u32 j;
#endif
for (i = 0; i < ipnet->netifs->size; i++, netif = IP_NULL)
{
if (
((netif = (Ipcom_netif *) ipnet->netifs->table[i]) != IP_NULL) &&
(netif->type == IP_IFT_PPPOE) &&
((pppif = (Ipppp_netif *) netif->plink) != IP_NULL) &&
(IP_BIT_ISFALSE(netif->flags, IP_IFF_RUNNING)) &&
(pppif->pppoe_eth_ifindex == ethindex)
)
{
Ipppp_link * link;
#ifdef IPPPP_USE_PPPMP
for (j = 0; j < IPPPP_MAX_LINKS; j++)
{
link = &pppif->link[j];
if (link->phases[IPPPP_PHASE_LCP].state == IPPPP_STATE_STARTING)
return (netif);
}
#else
link = &pppif->link[0];
if (link->phases[IPPPP_PHASE_LCP].state == IPPPP_STATE_STARTING)
return (netif);
#endif /* IPPPP_USE_PPPMP */
}
}
return IP_NULL;
}
/*
*===========================================================================
* ipppp_pppoe_sessionidtonetif
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipcom_netif *
ipppp_pppoe_sessionidtonetif(Ip_u32 session_id)
{
Ipcom_netif * netif = IP_NULL;
Ipppp_netif * pppif;
Ip_u32 i;
for (i = 0; i < ipnet->netifs->size; i++, netif = IP_NULL)
{
if (
((netif = (Ipcom_netif *) ipnet->netifs->table[i]) != IP_NULL) &&
(netif->type == IP_IFT_PPPOE) &&
((pppif = (Ipppp_netif *) netif->plink) != IP_NULL) &&
(IP_BIT_ISSET(netif->flags, IP_IFF_RUNNING))
)
{
#ifdef IPPPP_USE_PPPMP
Ipppp_link * link;
int j;
for (j = 0; j < IPPPP_MAX_LINKS; j++)
{
link = &pppif->link[j];
if ((IP_BIT_ISSET(link->data.flags, IPPPP_LINKFLAG_UP)) &&
(link->data.pppoe_session_id == session_id))
{
netif->link_index = link->link_index;
return (netif);
}
}
#else
if (session_id == pppif->pppoe_peer_session_id_n)
return (netif);
#endif /* IPPPP_USE_PPPMP */
}
}
return IP_NULL;
}
/*
*===========================================================================
* ipppp_pppoe_ascii_addr
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC char *
ipppp_pppoe_ascii_addr(Ip_u8 *num_addr)
{
int i;
static Ip_u8 ascii_addr[24];
for (i = 0; i < 6; i++)
{
ipcom_sprintf((char*)ascii_addr + (i*3), "%02x", (int)num_addr[i]);
if (i < 5)
ascii_addr[2 + (i*3)] = ':';
}
return (char *)ascii_addr;
}
/*
*===========================================================================
* ipppp_pppoe_padx_print
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IP_DEBUG
IP_STATIC void
ipppp_pppoe_padx_print(Ipcom_netif *netif, Ipppp_pkt_pppoe *pppoe_hdr, Ip_bool input, Ip_s32 ethindex)
{
ipppp_log(IPCOM_LOG_DEBUG, netif, IP_NULL, "<ippppoe> :: %s %s [len %d] [ses %d] [eth %ld]",
input ? "receiving" : "sending",
pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADI ? "PADI" :
pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADO ? "PADO" :
pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADR ? "PADR" :
pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADS ? "PADS" :
pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADT ? "PADT" : "unknown",
ip_ntohs(pppoe_hdr->length),
ip_ntohs(pppoe_hdr->session_id),
ethindex);
}
#else
#define ipppp_pppoe_padx_print(x,y,z,w) IP_NOOP
#endif
/*
*===========================================================================
* ipppp_pppoe_timeout
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipppp_pppoe_timeout(Ipcom_netif *ethif)
{
ipppp_pppoe_send_padi(ethif);
}
/*
*===========================================================================
* ipppp_pppoe_send_padt
*===========================================================================
* Description: Send Terminate packet
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipppp_pppoe_send_padt(Ipcom_netif *ethif, Ipppp_pkt_eth *in, Ip_u16 session_id_n)
{
Ipcom_pkt *pkt;
Ipppp_pkt_pppoe *pppoe_hdr;
/* Get memory for the PADT packet. */
pkt = ipcom_pkt_malloc(sizeof(Ipppp_pkt_eth) + 256, IP_FLAG_FC_STACKCONTEXT);
if (pkt == IP_NULL)
return;
pkt->ifindex = ethif->ifindex;
pkt->fd = -1;
ipcom_pkt_reserve_data(pkt, 0);
/* PPPoE header. */
pppoe_hdr = ipcom_pkt_push_front(pkt, IPPPP_PPPOE_HDR_SIZE);
pppoe_hdr->ver_type = IPPPP_PPPOE_HDR_VERTYPE;
pppoe_hdr->code = IPPPP_PPPOE_HDR_CODE_PADT;
pppoe_hdr->session_id = session_id_n;
pppoe_hdr->length = 0;
/* Ethernet header. */
ipnet_eth_add_hdr(pkt,
(void *) ethif,
in->eth_src,
ethif->link_addr,
ip_htons(IPPPP_PPPOE_MAC_DIS));
/* Send the PADT. */
ipppp_pppoe_padx_print(ethif, pppoe_hdr, IP_FALSE, (Ip_s32)ethif->ifindex);
(void)ipcom_ppp_ioevent(ethif, IPPPP_EIOXOUTPUT_IF, pkt);
}
/*
*===========================================================================
* ipppp_pppoe_send_padi
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipppp_pppoe_send_padi(Ipcom_netif *ethif)
{
Ipcom_pkt *pkt;
Ipppp_pkt_pppoe *pppoe_hdr;
char *service_name;
Ip_size_t service_name_len;
Ip_u16 tag_length;
Ipnet_netif *netif = (Ipnet_netif *)ethif;
int vr = ipcom_proc_vr_get();
/* Get memory for the PADI packet. */
pkt = ipcom_pkt_malloc(sizeof(Ipppp_pkt_eth) + 256, IP_FLAG_FC_STACKCONTEXT);
if (pkt == IP_NULL)
return;
/* Set virtual router index */
if (vr != netif->vr_index)
ipcom_proc_vr_set(netif->vr_index);
pkt->ifindex = ethif->ifindex;
pkt->fd = -1;
pkt->start = ipcom_conf_max_link_hdr_size;
pkt->end = pkt->start;
pkt->ipstart = pkt->start;
/* PPPoE header */
pppoe_hdr = ipcom_pkt_push_back(pkt, IPPPP_PPPOE_HDR_SIZE);
pppoe_hdr->ver_type = IPPPP_PPPOE_HDR_VERTYPE;
pppoe_hdr->code = IPPPP_PPPOE_HDR_CODE_PADI;
pppoe_hdr->session_id = 0;
/* PPPoE tags */
tag_length = 0;
/* Add Service_Name tag for PADO packet reply */
IPPPP_PPPOE_TAG_SET16(pppoe_hdr->payload, tag_length, IPPPP_PPPOE_TAG_Service_Name);
service_name_len = sizeof(ipppp.buf);
service_name = ipcom_sysvar_get("ipppp.pppoe.service_name", ipppp.buf, &service_name_len);
if (service_name == IP_NULL || service_name_len < 1)
{
IPPPP_PPPOE_TAG_SET16(pppoe_hdr->payload, tag_length, 0);
}
else
{
IPPPP_PPPOE_TAG_SET16(pppoe_hdr->payload, tag_length, service_name_len);
ipcom_strcpy((char *)pppoe_hdr->payload + tag_length, ipppp.buf);
tag_length = (Ip_u16)(tag_length + service_name_len);
}
/* Ethernet header */
ipnet_eth_add_hdr(pkt,
(void *)ethif,
ipppp_eth_addr_broadcast,
ethif->link_addr,
ip_htons(IPPPP_PPPOE_MAC_DIS));
/* Move pkt end past the pppoe payload */
pkt->end += tag_length;
/* Send the PADI. */
pppoe_hdr->length = ip_htons(tag_length);
ipppp_pppoe_padx_print(ethif, pppoe_hdr, IP_FALSE, (Ip_s32)ethif->ifindex);
(void)ipcom_ppp_ioevent(ethif, IPPPP_EIOXOUTPUT_IF, pkt);
/* Restore virtual router index */
if (vr != netif->vr_index)
ipcom_proc_vr_set(vr);
/* Reset timer */
(void)IPSTACK_TIMEOUT_SCHEDULE(4000,
(Ipstack_timeout_handler)ipppp_pppoe_timeout,
ethif,
(Ipstack_timeout **)&((Ipstack_netif *)ethif)->eth->pppoe_tmo_handle);
}
/*
*===========================================================================
* ipppp_pppoe_drv_ioctl
*===========================================================================
* Description: PPPoE driver ioctl. Always called code unlock.
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipppp_pppoe_drv_ioctl(Ipcom_netif *netif, Ip_u32 command, void *data)
{
Ipppp_netif *pppif;
Ipppp_phase *phase;
Ipstack_netif *ethif = IP_NULL;
struct Ip_pppreq *pppreq = data;
int ret = 0;
unsigned long ifindexul;
unsigned long ioretul;
ip_assert(netif);
ip_assert(netif->type == IP_IFT_PPPOE);
ip_assert(netif->ifindex > 0);
pppif = netif->plink;
ip_assert(pppif);
#ifdef IPPPP_USE_PPPMP
phase = &pppif->link[netif->link_index].phases[IPPPP_PHASE_LINK];
#else
phase = &pppif->link[0].phases[IPPPP_PHASE_LINK];
#endif
switch (command)
{
case IP_SIOCXOPEN:
case IP_SIOCXCLOSE:
case IP_SIOCXDETACH:
case IP_SIOCIFDESTROY:
/* Lookup Ethernet interface */
ipppp_lock();
if (pppif->pppoe_eth_ifindex != 0)
{
ifindexul = (unsigned long)pppif->pppoe_eth_ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
ethif = (Ipstack_netif *)ioretul;
if (ethif != IP_NULL && ethif->eth == IP_NULL)
ethif = IP_NULL; /* non-Ethernet interface, clear pointer */
}
break;
default:
break;
}
ip_assert(ethif == IP_NULL || ethif->eth != IP_NULL);
switch (command)
{
/***** Locked ioctls *****/
case IP_SIOCXOPEN:
/* Must be bound to Ethernet interface */
if (ethif == IP_NULL)
{
ret = -IP_ERRNO_ENXIO;
}
else if (IP_BIT_ISSET(netif->flags, IP_IFF_LINK1))
{
/* Client */
if (phase->state == IPPPP_STATE_INITIAL)
{
/* Initial state -> start searching */
ipppp_pppoe_send_padi((Ipcom_netif *)ethif);
phase->state = IPPPP_STATE_REQSENT;
}
}
else
{
/* Server -> signal link up immediately. */
ipppp_unlock();
(void)netif->link_ioevent(netif, IP_EIOXUP, data, 0);
return 0;
}
goto unlock_leave;
case IP_SIOCXCLOSE:
if (IP_BIT_ISSET(netif->flags, IP_IFF_LINK1) && ethif != IP_NULL)
{
/* PPPoE client */
if (phase->state == IPPPP_STATE_REQSENT)
/* Cancel PADI timer */
IPSTACK_TIMEOUT_CANCEL(ethif->eth->pppoe_tmo_handle);
phase->state = IPPPP_STATE_INITIAL;
}
/* Signal link down immediately. */
(void)netif->link_ioevent(netif, IP_EIOXDOWN, data, IP_FLAG_FC_STACKCONTEXT);
goto unlock_leave;
case IP_SIOCXDETACH:
if (IP_BIT_ISSET(netif->flags, IP_IFF_LINK1) && ethif != IP_NULL)
{
/* PPPoE client */
if (phase->state == IPPPP_STATE_REQSENT)
{
/* Cancel PADI timer */
IPSTACK_TIMEOUT_CANCEL(ethif->eth->pppoe_tmo_handle);
}
phase->state = IPPPP_STATE_INITIAL;
}
goto unlock_leave;
case IP_SIOCIFDESTROY:
if (IP_BIT_ISSET(netif->flags, IP_IFF_RUNNING))
return -IP_ERRNO_EBUSY;
/* Detach & free interface */
ipppp_pppoe_if_detach(netif);
goto unlock_leave;
/***** Unlocked ioctls *****/
case IP_SIOCXPPPGDRVCONF:
pppreq->pppru.drvconf.drv_flags = IP_DRVPPP_FLAG_NOFLAG
| IP_DRVPPP_FLAG_NOESCAPE
| IP_DRVPPP_FLAG_NOFCS
| IP_DRVPPP_FLAG_NOACFC;
pppreq->pppru.drvconf.baudrate = 0;
pppreq->pppru.drvconf.rcv_accm = 0;
pppreq->pppru.drvconf.snd_accm = 0;
pppreq->pppru.drvconf.mru = 1492;
pppreq->pppru.drvconf.mtu = 1492;
break;
case IP_SIOCXPPPSETIF:
{
Ip_u32 ifindex;
/* check for run status on netif */
if (phase->state > IPPPP_STATE_INITIAL)
return -IP_ERRNO_EPERM;
#ifdef IPNET
ethif = (Ipstack_netif *)ipnet_if_nametonetif(IPCOM_VR_ANY, pppreq->pppru.if_name);
if (ethif == IP_NULL)
return -IP_ERRNO_ESRCH;
ifindex = ethif->ipcom.ifindex;
#else
ifindex = ipcom_if_nametoindex(pppreq->pppru.if_name);
if (ifindex == 0)
return -IP_ERRNO_ESRCH;
#endif /* IPNET */
ipppp_lock();
/* Get previous Ethernet interface (if any) */
ifindexul = (unsigned long)pppif->pppoe_eth_ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
ethif = (Ipstack_netif *)ioretul;
if (ethif != IP_NULL && ethif->eth != IP_NULL)
{
/* Always unbind */
ethif->eth->pppoe_ppp_ifindex = 0;
pppif->pppoe_eth_ifindex = 0;
}
if (ifindex == netif->ifindex)
break; /* Bind to self, unbind */
/* Get new Ethernet interface */
ifindexul = (unsigned long)ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
ethif = (Ipstack_netif *)ioretul;
if (ethif == IP_NULL || ethif->eth == IP_NULL)
{
ret = -IP_ERRNO_ENXIO;
}
else
{
/* Bind to new Ethernet interface */
pppif->pppoe_eth_ifindex = ethif->ipcom.ifindex;
ethif->eth->pppoe_ppp_ifindex = netif->ifindex;
}
goto unlock_leave;
}
/* never gets to this point, no break needed here */
default:
ret = -IP_ERRNO_EINVAL;
break;
}
return ret;
unlock_leave:
ipppp_unlock();
return ret;
}
/*
*===========================================================================
* ipppp_pppoe_drv_output
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipppp_pppoe_drv_output(Ipcom_netif *netif, Ipcom_pkt *pkt)
{
Ipppp_netif *pppif;
Ipcom_netif *ethif;
Ipppp_pkt_pppoe *pppoe_hdr;
unsigned long ifindexul;
unsigned long ioretul;
int ret;
ip_assert(netif);
ip_assert(netif->type == IP_IFT_PPPOE);
ip_assert(netif->ifindex > 0);
pppif = netif->plink;
ip_assert(pppif);
/* Lookup Ethernet interface that is bound to the PPPoE interface */
ifindexul = (unsigned long)pppif->pppoe_eth_ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
ethif = (Ipcom_netif *)ioretul;
if (ethif == IP_NULL)
{
ret = -IP_ERRNO_ENETDOWN;
goto discard;
}
if (!IP_BIT_ISSET(ethif->flags, IP_IFF_UP))
{
ret = -IP_ERRNO_ENETDOWN;
goto discard;
}
#ifdef IPNET_USE_VLAN
ip_assert(ethif->type == IP_IFT_ETHER || ethif->type == IP_IFT_L2VLAN);
#else
ip_assert(ethif->type == IP_IFT_ETHER);
#endif
(void)ipcom_ppp_ioevent(ethif, IPPPP_EIOXIF_LOCK, IP_NULL);
#ifdef IPPPP_USE_PPPMP
if (IP_BIT_ISSET(pppif->pppflags, IPPPP_PPPIFFLAG_MP_BUNDLE) ||
IP_BIT_ISSET(pppif->pppflags, IPPPP_PPPIFFLAG_MP_MEMBER))
{
Ipppp_link * link = &pppif->link[netif->link_index];
pppif->pppoe_peer_session_id_n = (Ip_u16)link->data.pppoe_session_id;
}
#endif /* IPPPP_USE_PPPMP */
/* PPPoE header. */
pppoe_hdr = ipcom_pkt_push_front(pkt, IPPPP_PPPOE_HDR_SIZE);
pppoe_hdr->ver_type = IPPPP_PPPOE_HDR_VERTYPE;
pppoe_hdr->code = 0;
pppoe_hdr->length = (Ip_u16)(ipcom_pkt_get_length(pkt) - IPPPP_PPPOE_HDR_SIZE);
pppoe_hdr->length = ip_htons(pppoe_hdr->length);
if (pppif->pppoe_peer_session_id_n != 0)
pppoe_hdr->session_id = (Ip_u16)ip_htons(pppif->pppoe_peer_session_id_n); /* client mode */
else
pppoe_hdr->session_id = (Ip_u16)ip_htons(netif->ifindex);
pkt->ifindex = ethif->ifindex;
/* Ethernet header. */
ipnet_eth_add_hdr(pkt,
(void *) ethif,
pppif->pppoe_peer_eth_addr,
ethif->link_addr,
ip_htons(IPPPP_PPPOE_MAC_SES));
/* Output the PPPoE packet on the Ethernet. */
ret = (int)ipcom_ppp_ioevent(ethif, IPPPP_EIOXOUTPUT_IF, pkt);
(void)ipcom_ppp_ioevent(ethif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
/* Don't propagate the error code; we may do a double free in the non blocking case */
return 0;
discard:
ipcom_pkt_free(pkt);
return ret;
}
/*
*===========================================================================
* ipppp_pppoe_if_malloc
*===========================================================================
* Description: Create PPPoE interface. Must be called locked!
* Parameters:
* Returns:
*
*/
IP_STATIC Ipcom_netif *
ipppp_pppoe_if_malloc(char *ifname, int iftype)
{
Ipcom_netif *netif;
Ipppp_netif *pppif;
/* Allocate netif as being PPP, then change to PPPoE. */
netif = ipcom_if_malloc(IP_IFT_PPP);
if (netif == IP_NULL)
return IP_NULL;
/* Init PPPoE pppif stuff. */
netif->link_index = IPPPP_PPPOE_LINK_INDEX;
netif->type = IP_IFT_PPPOE;
netif->mtu = 1492;
netif->link_hdr_size = IPPPP_ETH_HDR_SIZE + IPPPP_PPPOE_HDR_SIZE + 2;
netif->drv_ioctl = ipppp_pppoe_drv_ioctl;
netif->drv_output = ipppp_pppoe_drv_output;
/* Interface name */
if (ifname)
{
ipcom_strncpy(netif->name, ifname, IP_IFNAMSIZ);
netif->name[IP_IFNAMSIZ-1] = 0;
}
else
{
int name_index;
name_index = ipcom_atoi(&netif->name[3]);
ipcom_sprintf(netif->name, "pppoe%d", name_index);
}
/* Large ifindex tells us that the session ID has (or is about to) wrap */
if ((iftype == PPPOE_TYPE_SERVER) &&
(ipnet->next_ifindex >= PPPOE_SESSIONID_WRAP_THRESHOLD))
{
Ip_u32 ifindex = ++ipnet->next_ifindex & 0x7fff;
/* Get an OK ifindex to use also for session ID */
while ((ifindex == 0) || (ipcom_hash_get(ipnet->netifs, &ifindex) != IP_NULL))
{
ifindex = (ifindex+1) & 0x7fff;
if (ifindex == (ipnet->next_ifindex & 0x7fff))
{
/* Tried all numbers, have to give up */
(void)ipcom_if_free(netif);
return IP_NULL;
}
}
netif->ifindex = ifindex;
}
/* Attach the PPPoE interface. */
if (ipcom_if_attach(netif) < 0)
{
(void)ipcom_if_free(netif);
return IP_NULL;
}
/* Configure PPPoE (must be locked) */
/*!MPPP RFC2516:7 Do not neg/ack ACFC (0xff 0x03) */
pppif = netif->plink;
pppif->link[0].ppp_flags |= (IP_PPP_FLAG_NOACCOMP | IP_PPP_FLAG_NOACCM);
return netif;
}
/*
*===========================================================================
* ipppp_pppoe_if_create_server
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipcom_netif *
ipppp_pppoe_if_create_server(Ipcom_netif *ethif, Ipppp_pkt_eth *in_eth_hdr, Ipppp_pkt_pppoe *out_pppoe_hdr)
{
Ipcom_netif *netif;
Ipppp_netif *pppif;
#ifdef IPNET_USE_VLAN
ip_assert(ethif->type == IP_IFT_ETHER || ethif->type == IP_IFT_L2VLAN);
#else
ip_assert(ethif->type == IP_IFT_ETHER);
#endif
ip_assert(((Ipstack_netif *)ethif)->eth != IP_NULL);
/* Malloc PPPoE interface */
netif = ipppp_pppoe_if_malloc(IP_NULL, PPPOE_TYPE_SERVER);
if (netif == IP_NULL)
return IP_NULL;
/* Auto bind interface */
pppif = netif->plink;
pppif->pppoe_eth_ifindex = ethif->ifindex;
ipcom_memcpy(pppif->pppoe_peer_eth_addr, in_eth_hdr->eth_src, IPPPP_ETH_ADDR_SIZE);
/* Set out session ID. */
out_pppoe_hdr->session_id = (Ip_u16)ip_htons(netif->ifindex);
/* One more session. */
ipppp.pppoe.num_sessions++;
((Ipstack_netif *)ethif)->eth->pppoe_num_sessions++;
/* Success */
return netif;
}
/*
*===========================================================================
* ipppp_pppoe_if_detach
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipppp_pppoe_if_detach(Ipcom_netif *netif)
{
Ipstack_netif *ethif;
Ipppp_netif *pppif;
int ret;
unsigned long ioretul;
unsigned long ifindexul;
ip_assert(netif->type == IP_IFT_PPPOE);
pppif = netif->plink;
ip_assert(pppif);
ipppp_log(IPCOM_LOG_INFO, netif, IP_NULL, "<ippppoe> :: detaching PPPoE [ses %ld]", netif->ifindex);
/* Reduce session count. */
ipppp.pppoe.num_sessions--;
ip_assert(ipppp.pppoe.num_sessions >= 0);
ifindexul = (unsigned long)pppif->pppoe_eth_ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
ethif = (Ipstack_netif *)ioretul;
if (ethif != IP_NULL)
{
ip_assert(ethif->eth != IP_NULL);
ethif->eth->pppoe_num_sessions--;
ethif->eth->pppoe_ppp_ifindex = 0;
ip_assert(ethif->eth->pppoe_num_sessions >= 0);
}
/* Detach interface. */
ret = ipcom_if_detach(netif);
ip_assert(ret > 0);
if (ret > 0)
(void)ipcom_if_free(netif); /* Free interface. */
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipppp_pppoe_create
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipppp_pppoe_create(struct Ip_ifreq *ifreq)
{
Ipcom_netif *netif;
Ipppp_netif *pppif;
Ipppp_link *link;
Ip_u32 i;
int vr = ipcom_proc_vr_get();
/* Set virtual router index */
if (vr != ifreq->ip_ifr_vr)
ipcom_proc_vr_set(ifreq->ip_ifr_vr);
/* Malloc PPPoE client interface */
netif = ipppp_pppoe_if_malloc(ifreq->ifr_name, PPPOE_TYPE_CLIENT);
/* Restore virtual router index */
if (vr != ifreq->ip_ifr_vr)
ipcom_proc_vr_set(vr);
if (netif == IP_NULL)
return -IP_ERRNO_ENOMEM;
IP_BIT_SET(netif->flags, IP_IFF_LINK1); /* PPPoE client interface */
/* Init PPP links. */
pppif = (Ipppp_netif *)netif->plink;
for (i = 0; i < IPPPP_MAX_LINKS; i++)
{
if (pppif && (link = &pppif->link[i]))
IP_BIT_SET(link->ppp_flags, IP_PPP_FLAG_NOPCOMP);
}
/* link states = initial, reqsent (PADI), opened */
return 0;
}
#ifdef IPPPP_USE_PPPMP
/*
*===========================================================================
* ipppp_pppoe_find_link
*===========================================================================
* Description: Find link that matches the session ID.
* Setting it to netif_index is previous behavior (was it?).
* Parameters:
* Returns: Link index, if one is found, otherwise -1.
*
*/
IP_STATIC int
ipppp_pppoe_find_link(Ipcom_netif *netif, int session_id)
{
Ipppp_netif *pppif = netif->plink;
Ipppp_link *link;
int i, link_index;
if (IP_BIT_ISFALSE(pppif->pppflags, IPPPP_PPPIFFLAG_MP_BUNDLE))
link_index = netif->link_index;
else
{
link_index = -1;
for (i = 0; i < pppif->data.mp.mp_links; i++)
{
link = &pppif->link[i];
if (session_id == (int)link->data.pppoe_session_id)
{
link_index = netif->link_index = i;
break;
}
}
}
return (link_index);
}
#endif /* IPPPP_USE_PPPMP */
/*
*===========================================================================
* ipppp_pppoe_input
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipppp_pppoe_input(Ipcom_netif *ethif, Ipcom_pkt *pkt)
{
Ipppp_pkt_eth *eth_hdr;
Ipppp_pkt_pppoe *pppoe_hdr;
Ipcom_pkt *reply_pkt = IP_NULL;
Ipcom_netif *netif = IP_NULL;
Ipppp_netif *pppif = IP_NULL;
Ipstack_netif_eth *ethif_eth = ((Ipstack_netif *)ethif)->eth;
unsigned long ioretul;
unsigned long ifindexul;
unsigned long sessionidul;
int ret;
int max_sessions;
int session_id;
int err_status; /* 0 ok, -1 error, 1 start PPPoE */
#ifdef IPPPP_USE_PPPMP
Ipppp_link *link;
#endif /* IPPPP_USE_PPPMP */
Ip_u16 eth_type;
int vr = ipcom_proc_vr_get();
#ifdef IPNET_USE_VLAN
ip_assert(ethif->type == IP_IFT_ETHER || ethif->type == IP_IFT_L2VLAN);
#else
ip_assert(ethif->type == IP_IFT_ETHER);
#endif
ip_assert(ethif_eth != IP_NULL);
/* Set virtual router index */
if (vr != pkt->vr_index)
ipcom_proc_vr_set(pkt->vr_index);
eth_hdr = (Ipppp_pkt_eth *)&pkt->data[pkt->start];
pppoe_hdr = (Ipppp_pkt_pppoe *)&pkt->data[pkt->start + ethif->link_hdr_size];
eth_type = (Ip_u16)IP_GET_NTOHS(&pkt->data[pkt->start + ethif->link_hdr_size - 2]);
/* Don't read my own output Ethernet packets. */
if (ipcom_memcmp(eth_hdr->eth_src, ethif->link_addr, IPPPP_ETH_ADDR_SIZE) == 0)
goto leave;
/* PPPoE version and type check. */
if (pppoe_hdr->ver_type != IPPPP_PPPOE_HDR_VERTYPE)
{
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL, "<ippppoe> :: invalid PPPoE version 0x%x or type 0x%x [eth %ld]",
pppoe_hdr->ver_type >> 4, pppoe_hdr->ver_type & 0xf, ethif->ifindex);
goto leave;
}
/* PPPoE length check. */
if (ip_ntohs(pppoe_hdr->length) > (IP_ETH_MTU - IPPPP_PPPOE_HDR_SIZE))
{
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL, "<ippppoe> :: invalid PPPoE length %d [eth %ld]",
ip_ntohs(pppoe_hdr->length), ethif->ifindex);
goto leave;
}
session_id = (int)ip_ntohs(pppoe_hdr->session_id);
/***** PPPoE session frames. *****/
if (eth_type == IPPPP_PPPOE_MAC_SES)
{
sessionidul = (unsigned long)session_id;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)sessionidul);
netif = (Ipcom_netif *)ioretul;
if (netif == IP_NULL || netif->type != IP_IFT_PPPOE || IP_BIT_ISSET(netif->flags, IP_IFF_LINK1))
{
/* If the peer session id fails check if client interface */
netif = ipppp_pppoe_sessionidtonetif((Ip_u32)session_id);
if (netif == IP_NULL)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: received PPPoE session packet with unknown session-id(%d) code (%d) [eth %ld]",
session_id,
pppoe_hdr->code,
ethif->ifindex);
goto leave;
}
if (netif->type != IP_IFT_PPPOE || IP_BIT_ISFALSE(netif->flags, IP_IFF_LINK1))
goto leave;
pppif = netif->plink;
if (pppif->link[0].phases[IPPPP_PHASE_LINK].state < IPPPP_STATE_OPENED)
goto leave; /* discard PPP frames if pppoe client is in searching mode */
}
ip_assert(netif->type == IP_IFT_PPPOE);
pppif = netif->plink;
/* Lock this PPP interface. */
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_LOCK, IP_NULL);
/* PPPoE code must be set to 0 in session stage.
* Syslog a warning but let it slide.
*/
if (pppoe_hdr->code != 0)
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: PPPoE session packet with non-zero code (%d) [in %s] [ses %ld] [eth %ld]",
pppoe_hdr->code,
ipppp_pppoe_ascii_addr(eth_hdr->eth_src),
netif->ifindex, ethif->ifindex);
goto send_padt;
}
/* Check Ethernet source address (must match). */
if (ipcom_memcmp(eth_hdr->eth_src, pppif->pppoe_peer_eth_addr, 6) != 0)
{
ipppp_log(IPCOM_LOG_DEBUG,
ethif, IP_NULL, "<ippppoe> :: session - Ethernet source address mismatch [in %s] [ses %ld] [eth %ld]",
ipppp_pppoe_ascii_addr(eth_hdr->eth_src), netif->ifindex, ethif->ifindex);
goto send_padt;
}
/* Success, pass PPP packet to ipppp_input(). */
pkt->start += ethif->link_hdr_size + IPPPP_PPPOE_HDR_SIZE;
ipcom_pkt_trim_tail(pkt, ipcom_pkt_get_length(pkt) - (int)ip_htons(pppoe_hdr->length));
pkt->ifindex = netif->ifindex;
#ifdef IPPPP_USE_PPPMP
/*
* Server use netif ifindex as session number and always use link 0
*/
if (IP_BIT_ISFALSE(netif->flags, IP_IFF_LINK1))
pkt->link_cookie = IPPPP_PPPOE_LINK_INDEX;
else
{
int link_found = ipppp_pppoe_find_link(netif, session_id);
if (link_found < 0)
{
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL,
"<ippppoe> :: PPPoE session %d does not match an open link.",
session_id);
pkt->link_cookie = 0;
goto send_padt;
}
else
pkt->link_cookie = (Ip_ptrdiff_t)link_found;
}
#else
pkt->link_cookie = IPPPP_PPPOE_LINK_INDEX;
#endif
ret = ipppp_input(netif, pkt);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
/* Restore virtual router index */
if (vr != pkt->vr_index)
ipcom_proc_vr_set(vr);
return ret;
/* Send a PADT. */
send_padt:
if (netif != IP_NULL)
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
ipppp_pppoe_send_padt(ethif, eth_hdr, pppoe_hdr->session_id);
goto leave;
}
/***** PPPoE discovery frames only. *****/
if (eth_type != IPPPP_PPPOE_MAC_DIS)
{
ipppp_log(IPCOM_LOG_ERR,
ethif, IP_NULL, "<ippppoe> :: invalid Ethernet frame 0x%x [eth %ld]",
eth_type, ethif->ifindex);
goto leave;
}
/* for ppope control packet */
if (pkt->next_part != IP_NULL)
{
int vr_pkt = pkt->vr_index;
/* linearize pppoe control packet, that will not consume cpu too much. */
pkt = ipcom_pkt_make_linear(pkt);
if(pkt == IP_NULL)
{
/* Restore virtual router index */
if (vr != vr_pkt)
ipcom_proc_vr_set(vr);
return 0;
}
eth_hdr = (Ipppp_pkt_eth *)&pkt->data[pkt->start];
pppoe_hdr = (Ipppp_pkt_pppoe *)&pkt->data[pkt->start + ethif->link_hdr_size];
}
ipppp_pppoe_padx_print(ethif, pppoe_hdr, IP_TRUE, (Ip_s32)ethif->ifindex);
/***** Act on the PPPoE Discovery code *****/
switch(pppoe_hdr->code)
{
case IPPPP_PPPOE_HDR_CODE_PADI: /* PPPoE Active Discovery Initiation packet */
case IPPPP_PPPOE_HDR_CODE_PADR: /* PPPoE Active Discovery Request packet */
/***** Check if PPPoE server is enabled *****/
if (ipcom_sysvar_get_conf_as_int("ipppp.pppoe.server", IP_NULL, ethif->name) != 1)
{
/* Silent discard */
goto leave;
}
/* Ignore PADI or PADR if total number of sessions reached. */
max_sessions = ipcom_sysvar_get_as_int("ipppp.pppoe.max_sessions", 16);
if (ipppp.pppoe.num_sessions >= max_sessions)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: ignoring PPPoE PAD[I|R] - total sessions reached [%d/%d] [eth %ld]",
ipppp.pppoe.num_sessions, max_sessions, ethif->ifindex);
goto leave;
}
/* Ignore PADI or PADR if max number of sessions per interface reached. */
max_sessions = ipcom_sysvar_get_conf_as_int("ipppp.pppoe.max_eth_sessions", IP_NULL, ethif->name);
if (ethif_eth->pppoe_num_sessions >= max_sessions)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: ignoring PPPoE PAD[I|R] - maximum interface sessions reached [%d/%d] [eth %ld]",
ethif_eth->pppoe_num_sessions, max_sessions, ethif->ifindex);
goto leave;
}
/* fall through */
case IPPPP_PPPOE_HDR_CODE_PADO: /* PPPoE Active Discovery Offer packet */
/* Session_id must be 0 for all PAD[I|R|O] packets */
if (pppoe_hdr->session_id != 0)
{
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL, "<ippppoe> :: invalid PPPoE PADx session_id 0x%x (must be 0) [eth %ld]",
session_id, ethif->ifindex);
goto leave;
}
/* fall through */
case IPPPP_PPPOE_HDR_CODE_PADS: /* PPPoE Active Discovery Session-confirmation packet */
{
Ipppp_pkt_pppoe *reply_pppoe_hdr;
Ip_u8 *tagp;
Ip_u16 tag_type, tag_length, out_length;
int in_length;
Ip_bool service_ok = IP_FALSE;
#ifdef IPPPP_PPPOE_USE_MD5
#ifdef OPENSSL_FIPS
Ip_bool cookie_ok;
if (FIPS_mode())
cookie_ok = IP_TRUE;
else
cookie_ok = IP_FALSE;
#else
Ip_bool cookie_ok = IP_FALSE;
#endif /* end OPENSSL_FIPS */
#else
Ip_bool cookie_ok = IP_TRUE;
#endif
/* Get memory for the PAD[O|S|R] reply. */
reply_pkt = ipcom_pkt_malloc(sizeof(Ipppp_pkt_eth) + 512, IP_FLAG_FC_STACKCONTEXT);
if (reply_pkt == IP_NULL)
{
ipppp_log(IPCOM_LOG_ERR, ethif, IP_NULL, "<ippppoe> :: ipcom_pkt_malloc() failed, no memory");
goto leave;
}
reply_pkt->ifindex = ethif->ifindex;
reply_pkt->fd = -1;
reply_pkt->start = ipcom_conf_max_link_hdr_size;
reply_pkt->ipstart = reply_pkt->start;
reply_pkt->end = reply_pkt->start;
reply_pppoe_hdr = ipcom_pkt_push_back(reply_pkt, IPPPP_PPPOE_HDR_SIZE);
reply_pppoe_hdr->session_id = 0;
out_length = 0;
/* Parse PPPoE tags. */
in_length = (int)ip_ntohs(pppoe_hdr->length);
tagp = pppoe_hdr->payload;
while (in_length >= IPPPP_PPPOE_TAG_HSIZE)
{
tag_type = (Ip_u16)IP_GET_NTOHS(&tagp[0]);
tag_length = (Ip_u16)IP_GET_NTOHS(&tagp[2]);
in_length -= IPPPP_PPPOE_TAG_HSIZE;
if (tag_length > in_length)
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: invalid PPPoE PADX tag length = %d, type = 0x%x [eth %ld]",
tag_length, tag_type, ethif->ifindex);
goto leave;
}
switch(tag_type)
{
/* Must contain exactly one tag of type 'Service-Name' */
case IPPPP_PPPOE_TAG_Service_Name:
/* Verify peer service_name */
if (service_ok == IP_FALSE)
{
Ip_u8 *service_name;
Ip_u16 service_length;
service_name = &tagp[IPPPP_PPPOE_TAG_HSIZE];
service_length = tag_length;
service_ok = IP_TRUE;
if (service_length > 0)
{
Ip_u8 *service_name_l;
Ip_size_t service_length_l;
service_length_l = sizeof(ipppp.buf);
service_name_l = (Ip_u8 *)ipcom_sysvar_get_conf("ipppp.pppoe.service_name", ipppp.buf, &service_length_l,
IP_NULL, ethif->name);
if (service_name_l != IP_NULL && service_length_l > 0)
{
if (ipcom_memcmp(service_name, service_name_l,
IP_MIN(service_length, service_length_l))) /*lint !e670 Possible access beyond array */
service_ok = IP_FALSE;
}
}
/* if service_name is useable, copy it into the reply and accept no more */
if (service_ok == IP_TRUE)
{
ipcom_memcpy(reply_pppoe_hdr->payload + out_length, tagp, (Ip_size_t)(IPPPP_PPPOE_TAG_HSIZE + tag_length));
out_length = (Ip_u16)(out_length + IPPPP_PPPOE_TAG_HSIZE + tag_length);
}
}
break;
/* Copy the tags below to the output packet. */
case IPPPP_PPPOE_TAG_Host_Uniq:
case IPPPP_PPPOE_TAG_Relay_Session_Id:
ipcom_memcpy(reply_pppoe_hdr->payload + out_length, tagp, (Ip_size_t)(IPPPP_PPPOE_TAG_HSIZE + tag_length)); /*lint !e669 Possible data overrun */ /*lint !e670 Possible access beyond array */
out_length = (Ip_u16)(out_length + IPPPP_PPPOE_TAG_HSIZE + tag_length);
break;
case IPPPP_PPPOE_TAG_AC_Cookie:
if (pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADR)
{
#ifdef IPPPP_PPPOE_USE_MD5
#ifdef OPENSSL_FIPS
if (!FIPS_mode())
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: PPPoE ipppp_pppoe_set_cookie with MD5 as OPENSSL FIPS is not enabled");
#endif
if (tag_length == MD5_DIGEST_LENGTH)
{
ipppp_pppoe_set_cookie(ipppp.pppoe.gen_cookie, eth_hdr->eth_src);
if (ipcom_memcmp(ipppp.pppoe.gen_cookie, &tagp[IPPPP_PPPOE_TAG_HSIZE], MD5_DIGEST_LENGTH) == 0) /*lint !e670 Possible access beyond array */
cookie_ok = IP_TRUE;
}
#ifdef OPENSSL_FIPS
} /* FIPS_mode checking */
#endif
#endif /* IPPPP_PPPOE_USE_MD5 */
#ifdef OPENSSL_FIPS
#ifdef IPPPP_PPPOE_USE_MD5
else
#endif
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: PPPoE ipppp_pppoe_set_cookie with MD5 is disabled as OPENSSL FIPS is enabled");
if (tag_length == IPPPP_PPPOE_NON_ALGORITHM_LENGTH)
cookie_ok = IP_TRUE;
}
#endif
}
else if (pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADO)
{
/* Received PADO with cookie -> send it back in PADR */
ipcom_memcpy(reply_pppoe_hdr->payload + out_length, tagp, (Ip_size_t)(IPPPP_PPPOE_TAG_HSIZE + tag_length)); /*lint !e669 Possible data overrun */ /*lint !e670 Possible access beyond array */
#ifdef IPPPP_NORMAL_NO_BUILD_WARNINGS
out_length += (IPPPP_PPPOE_TAG_HSIZE + tag_length);
#else
out_length = (Ip_u16)(out_length + (IPPPP_PPPOE_TAG_HSIZE + tag_length));
#endif
}
break;
case IPPPP_PPPOE_TAG_End_Of_List:
if (tag_length != 0)
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: PPPoE PADX End_Of_List tag had non-zero length (%d) [eth %ld]",
tag_length, ethif->ifindex);
goto leave;
}
goto breakout;
default:
/* ignore unknown tags for future backwards compability. */
break;
}
in_length -= tag_length;
tagp += (IPPPP_PPPOE_TAG_HSIZE + tag_length);
}
breakout:
err_status = 0;
if (service_ok == IP_FALSE)
{
ipppp_log(IPCOM_LOG_INFO,
ethif, IP_NULL, "<ippppoe> :: ignored - missing/unknown Service_Name tag(s) [eth %ld]",
ethif->ifindex);
/* Reply with a PADS containing Service-Name-Error.
err_status = -1;
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_TAG_Service_Name_Error);
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, 0);
*/
goto leave;
}
switch (pppoe_hdr->code)
{
case IPPPP_PPPOE_HDR_CODE_PADI:
{
/* Send PADO */
char *ac_name;
Ip_size_t ac_name_len;
/* Add AC_Name tag for PADO packet reply */
ac_name_len = sizeof(ipppp.buf);
ac_name = ipcom_sysvar_get("ipppp.pppoe.ac_name", ipppp.buf, &ac_name_len);
if (ac_name == IP_NULL || ac_name_len < 1)
{
ipcom_strcpy(ipppp.buf, "UNDEFINED");
ac_name_len = 9;
}
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_TAG_AC_Name);
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, ac_name_len);
ipcom_strcpy((char *)reply_pppoe_hdr->payload + out_length, ipppp.buf);
out_length = (Ip_u16)(out_length + ac_name_len);
/* Add cookie code to protect vs DOS attacks */
#ifdef IPPPP_PPPOE_USE_MD5
#ifdef OPENSSL_FIPS
if (!FIPS_mode())
{
#endif
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_TAG_AC_Cookie);
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, MD5_DIGEST_LENGTH);
ipppp_pppoe_set_cookie(reply_pppoe_hdr->payload + out_length, eth_hdr->eth_src);
out_length = (Ip_u16)(out_length + MD5_DIGEST_LENGTH);
#ifdef OPENSSL_FIPS
}
else
{
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_TAG_AC_Cookie);
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_NON_ALGORITHM_LENGTH); out_length += IPPPP_PPPOE_NON_ALGORITHM_LENGTH;
}
#endif
#endif /* IPPPP_PPPOE_USE_MD5 */
reply_pppoe_hdr->code = IPPPP_PPPOE_HDR_CODE_PADO;
}
break;
case IPPPP_PPPOE_HDR_CODE_PADR:
/* Send PADS */
if (cookie_ok == IP_FALSE)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: PPPoE PADR - missing or illegal cookie [eth %ld]",
ethif->ifindex);
goto leave;
}
/* Check action and correct code for PADOs. */
if (err_status == 0)
{
/* Create PPPoE server interface */
netif = ipppp_pppoe_if_create_server(ethif, eth_hdr, reply_pppoe_hdr);
if (netif == IP_NULL)
{
ipppp_log(IPCOM_LOG_ERR,
ethif, IP_NULL, "<ippppoe> :: failed to attach PPPoE session [totses %ld] [numifses %ld] [eth %ld]",
ipppp.pppoe.num_sessions, ethif_eth->pppoe_num_sessions, ethif->ifindex);
goto leave;
}
ipppp_log(IPCOM_LOG_INFO,
ethif, IP_NULL, "<ippppoe> :: attaching PPPoE [ses %d] [eth %d] [numifses %d]",
netif->ifindex, ethif->ifindex, ethif_eth->pppoe_num_sessions);
err_status = 1;
}
reply_pppoe_hdr->code = IPPPP_PPPOE_HDR_CODE_PADS;
break;
case IPPPP_PPPOE_HDR_CODE_PADO:
case IPPPP_PPPOE_HDR_CODE_PADS:
/* Received PADO/PADS - PPPoE in client mode */
netif = ipppp_pppoe_find_netif(ethif->ifindex);
if (netif == IP_NULL || netif->type != IP_IFT_PPPOE)
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: received PPPoE PADO/PADS packet with missing PPP interface [eth %ld]",
ethif->ifindex);
goto leave;
}
pppif = netif->plink;
if (pppoe_hdr->code == IPPPP_PPPOE_HDR_CODE_PADO)
{
/* Send PADR */
reply_pppoe_hdr->code = IPPPP_PPPOE_HDR_CODE_PADR;
/* Remember the peer Ethernet address so we dont connect to wrong peer */
ipcom_memcpy(pppif->pppoe_peer_eth_addr, eth_hdr->eth_src, IPPPP_ETH_ADDR_SIZE);
}
else
{
/* Check Ethernet source address (must match). */
if (ipcom_memcmp(eth_hdr->eth_src, pppif->pppoe_peer_eth_addr, 6) != 0)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: PADS - Ethernet source address mismatch (ignoring PADS) [in %s] [ses %ld] [eth %ld]",
ipppp_pppoe_ascii_addr(eth_hdr->eth_src),
netif->ifindex, ethif->ifindex);
goto leave;
}
/* Save peer session_id */
pppif->pppoe_peer_session_id_n = (Ip_u16)session_id;
#ifdef IPPPP_USE_PPPMP
/* Time to open up a new link. Find which link index is available */
if (IP_BIT_ISSET(pppif->pppflags, IPPPP_PPPIFFLAG_NEG_MP))
{
Ipppp_link * trylink;
int link_index = -1;
int i;
for (i = 0; i < pppif->data.mp.mp_links; i++)
{
trylink = &pppif->link[i];
if(IP_BIT_ISFALSE(trylink->data.flags, IPPPP_LINKFLAG_UP))
{
link_index = i;
break;
}
}
if (link_index < 0)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: %s: no link available",
netif->name);
goto leave;
}
netif->link_index = link_index;
}
/* Store this session id for this link */
link = &pppif->link[netif->link_index];
link->data.pppoe_session_id = session_id;
#endif /* IPPPP_USE_PPPMP */
/* One more session. */
ipppp.pppoe.num_sessions++;
ethif_eth->pppoe_num_sessions++;
/* Received PADS -> start the PPPoE Interface. */
IPSTACK_TIMEOUT_CANCEL(ethif_eth->pppoe_tmo_handle);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_LOCK, IP_NULL);
(void)netif->link_ioevent(netif, IP_EIOXUP, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
goto leave;
}
break;
default:
IP_PANIC();
break;
}
/* Add optional End-of-List for backwards compatibility. */
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, IPPPP_PPPOE_TAG_End_Of_List);
IPPPP_PPPOE_TAG_SET16(reply_pppoe_hdr->payload, out_length, 0);
/* Ethernet header. */
ipnet_eth_add_hdr(reply_pkt,
(void *)ethif,
eth_hdr->eth_src,
ethif->link_addr,
ip_htons(IPPPP_PPPOE_MAC_DIS));
/* PPPoE header. */
reply_pppoe_hdr->ver_type = IPPPP_PPPOE_HDR_VERTYPE;
reply_pppoe_hdr->length = ip_htons(out_length);
ipcom_pkt_push_back(reply_pkt, out_length);
/* Write the PAD[O|S] reply. */
ipppp_pppoe_padx_print(ethif, reply_pppoe_hdr, IP_FALSE, (Ip_s32)ethif->ifindex);
(void)ipcom_ppp_ioevent(ethif, IPPPP_EIOXOUTPUT_IF, reply_pkt);
reply_pkt = IP_NULL;
if (err_status == 1)
{
/* Just sent a PADS -> start the PPPoE Interface. */
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_LOCK, IP_NULL);
(void)ipppp_ioctl(netif, IP_SIOCXOPEN, IP_NULL);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
}
goto leave;
}
case IPPPP_PPPOE_HDR_CODE_PADT: /* PPPoE Active Discovery Terminate packet */
if (pppoe_hdr->session_id == 0xffff)
{
ipppp_log(IPCOM_LOG_WARNING,
ethif, IP_NULL, "<ippppoe> :: reserved PPPoE PADR session_id 0xffff [eth %ld]",
ethif->ifindex);
goto leave;
}
sessionidul = (unsigned long)session_id;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)sessionidul);
netif = (Ipcom_netif *)ioretul;
if (netif == IP_NULL || netif->type != IP_IFT_PPPOE)
{
/* If the peer session id fails check if client interface */
ifindexul = (unsigned long)ethif_eth->pppoe_ppp_ifindex;
ioretul = (unsigned long)ipcom_ppp_ioevent(IP_NULL, IPPPP_EIOXINDEXTONETIF, (void *)ifindexul);
netif = (Ipcom_netif *)ioretul;
if (netif == IP_NULL || netif->type != IP_IFT_PPPOE)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: PPPoE PADT with unknown session-id(%d) [in %s] [eth %ld]",
session_id,
ipppp_pppoe_ascii_addr(eth_hdr->eth_src),
ethif->ifindex);
goto leave;
}
}
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_LOCK, IP_NULL);
pppif = netif->plink;
/* Check Ethernet source address (must match). */
if (ipcom_memcmp(eth_hdr->eth_src, pppif->pppoe_peer_eth_addr, 6) != 0)
{
ipppp_log(IPCOM_LOG_NOTICE,
ethif, IP_NULL, "<ippppoe> :: PADT - Ethernet source address mismatch (ignoring PADT) [in %s] [ses %ld] [eth %ld]",
ipppp_pppoe_ascii_addr(eth_hdr->eth_src),
netif->ifindex, ethif->ifindex);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
goto leave;
}
if (IP_BIT_ISSET(netif->flags, IP_IFF_RUNNING))
{
#ifdef IPPPP_USE_PPPMP
Ipppp_link * this_link;
int link_index;
#endif
/* Stop the PPPoE interface. */
ipppp_log(IPCOM_LOG_INFO, ethif, IP_NULL, "<ippppoe> :: stopping PPPoE [ses %ld] [eth %ld] [numifses %ld]",
netif->ifindex, ethif->ifindex, ethif_eth->pppoe_num_sessions);
#ifdef IPPPP_USE_PPPMP
if ((link_index = ipppp_pppoe_find_link(netif, session_id)) < 0)
{
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL,
"<ippppoe> :: PPPoE session %d does not match an open link.",
session_id);
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
goto leave;
}
/* Stop the interface (make sure the link is actually up before doing this) */
this_link = &pppif->link[link_index];
if (IP_BIT_ISSET(this_link->data.flags, IPPPP_LINKFLAG_UP))
(void)ipppp_ioctl(netif, IP_SIOCXCLOSE, IP_NULL);
#else
(void)ipppp_ioctl(netif, IP_SIOCXCLOSE, IP_NULL);
#endif /* IPPPP_USE_PPPMP */
}
(void)ipcom_ppp_ioevent(netif, IPPPP_EIOXIF_UNLOCK, IP_NULL);
break;
default:
ipppp_log(IPCOM_LOG_WARNING, ethif, IP_NULL, "<ippppoe> :: unknown PPPoE code 0x%x [eth %ld]",
pppoe_hdr->code, ethif->ifindex);
break;
}
leave:
ipcom_pkt_free(pkt);
if (reply_pkt != IP_NULL)
ipcom_pkt_free(reply_pkt);
/* Restore virtual router index */
if (vr != pkt->vr_index)
ipcom_proc_vr_set(vr);
return 0;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#else
int ipppp_pppoe_empty_file;
#endif /* IPPPP_USE_PPPOE */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/