975 lines
30 KiB
C
975 lines
30 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_example_v3.c,v $ $Revision: 1.13.10.4 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/config/ipl2tp_example_v3.c,v $
|
|
* $Author: jren $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_clib2.h"
|
|
#include "ipcom_err.h"
|
|
#include "ipcom_ipd.h"
|
|
#include "ipcom_os.h"
|
|
#include "ipcom_shell.h"
|
|
#include "ipcom_sock2.h"
|
|
#include "ipcom_syslog.h"
|
|
#include "ipcom_type.h"
|
|
#include "ipcom_hash.h"
|
|
#include "ipcom_sysvar.h"
|
|
#include "ipcom_netif.h"
|
|
#include "ipcom_strlib.h"
|
|
|
|
#include "ipl2tp_h.h"
|
|
#include "ipl2tp_api.h"
|
|
#include "ipl2tp_api_tunnel.h"
|
|
#include "ipl2tp_api_session.h"
|
|
#include "ipl2tp_attr.h"
|
|
#include "ipl2tp_cmd.h"
|
|
#include "ipl2tp_example.h"
|
|
#include "ipl2tp_example_v3.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipl2tp_v3_circuit
|
|
{
|
|
char *name;
|
|
char *intf;
|
|
Ip_u32 ifnum;
|
|
int pw_type;
|
|
int vlan_tag;
|
|
}
|
|
Ipl2tp_v3_circuit_t;
|
|
|
|
typedef struct Ipl2tp_v3_ethernet_circuit
|
|
{
|
|
Ipl2tp_example_session_t session;
|
|
Ipl2tp_example_fd_entry_t *fd_eth;
|
|
}
|
|
Ipl2tp_v3_ethernet_circuit_t;
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_eth_data_cb
|
|
*===========================================================================
|
|
* Description: Data callback.
|
|
* Parameters: user_data - User callback data.
|
|
* buffer - Original data buffer.
|
|
* payload - Payload pointer in data buffer.
|
|
* length - Length of payload.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_example_session_eth_data_output(void *user_data,
|
|
Ipl2tp_key *key,
|
|
void *buffer,
|
|
void *payload,
|
|
Ip_u16 length)
|
|
{
|
|
Ipl2tp_v3_ethernet_circuit_t *session = user_data;
|
|
|
|
IPL2TP_UNUSED(key);
|
|
IPL2TP_UNUSED(buffer);
|
|
|
|
/* Do the write */
|
|
if (session != IP_NULL)
|
|
{
|
|
struct Ip_sockaddr_ll to_ll;
|
|
Ipl2tp_v3_circuit_t *circuit = session->session.circuit;
|
|
|
|
/* Modify the frame */
|
|
if (circuit->pw_type == IPL2TP_ATTR_PW_TYPE_ETHERNET_VLAN &&
|
|
circuit->vlan_tag != 0)
|
|
{
|
|
Ip_u8 *frame = payload;
|
|
Ip_u16 vid = IP_GET_HTONS(frame + 14);
|
|
|
|
vid = (Ip_u16)(vid & 0xf000);
|
|
vid = (Ip_u16)(vid | (Ip_u16)(circuit->vlan_tag & 0x0fff));
|
|
IP_SET_HTONS(frame + 14, vid);
|
|
}
|
|
|
|
ipcom_memset(&to_ll, 0, sizeof(to_ll));
|
|
to_ll.sll_len = (Ip_u8)sizeof(to_ll);
|
|
to_ll.sll_family = IP_AF_PACKET;
|
|
to_ll.sll_ifindex = circuit->ifnum;
|
|
|
|
if (ipcom_sendto(session->fd_eth->fd, payload, length, 0,
|
|
(struct Ip_sockaddr *)&to_ll, sizeof(to_ll)) < 0)
|
|
{
|
|
IPCOM_LOG0(ERR, "IPL2TPv3: Error in ipcom send");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipl2tp_example_session_eth_data_input(Ipl2tp_example_fd_entry_t *entry,
|
|
void *buffer,
|
|
void *data,
|
|
Ip_size_t size)
|
|
{
|
|
Ip_ptrdiff_t offset = (Ip_u8 *)data - (Ip_u8 *)buffer;
|
|
|
|
/* Get the eth session ID */
|
|
Ipl2tp_v3_ethernet_circuit_t *session = entry->ptr;
|
|
|
|
/* Done */
|
|
ipl2tp_api_session_ethernet_input(&session->session.key,
|
|
data,
|
|
(int)size,
|
|
(int)offset,
|
|
0,
|
|
IP_TRUE);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_check_eth_interface
|
|
*===========================================================================
|
|
* Description: Determine if interface is currently in use by another circuit
|
|
* Parameters: key: session key of sessio to be compared against
|
|
* intf: name of interface
|
|
* Returns: 1 if the interface is currently in use by another session
|
|
* 0 otherwise
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipl2tp_example_session_check_eth_interface(Ipl2tp_key * key, char * intf)
|
|
{
|
|
Ipl2tp_status status;
|
|
Ipl2tp_key this_tkey, next_tkey;
|
|
Ipl2tp_key this_skey, next_skey;
|
|
Ipl2tp_v3_circuit_t *circuit;
|
|
Ipl2tp_v3_ethernet_circuit_t *session;
|
|
|
|
if ((intf == IP_NULL) || (ipcom_strlen(intf) == 0))
|
|
return (0);
|
|
|
|
/* Get the first tunnel, if there is one */
|
|
this_tkey.ident = 0;
|
|
this_tkey.version = IPL2TP_VERSION_L2TPV3;
|
|
if ((status = ipl2tp_api_tunnel_next(&this_tkey, &next_tkey)) != IPL2TP_STATUS_OK)
|
|
return (0);
|
|
|
|
/* Go through all tunnels */
|
|
while (status == IPL2TP_STATUS_OK)
|
|
{
|
|
/* If status is OK, next_tkey.ident must be non-zero */
|
|
this_tkey.ident = next_tkey.ident;
|
|
|
|
/* Get the first session if there is one */
|
|
if ((status = ipl2tp_api_session_next(&this_tkey, IP_NULL, &next_skey)) != IPL2TP_STATUS_OK)
|
|
continue;
|
|
|
|
/* Go through all sessions in this tunnel */
|
|
while (status == IPL2TP_STATUS_OK)
|
|
{
|
|
/* If status is OK, next_skey.ident must be non-zero, so use it */
|
|
this_skey.ident = next_skey.ident;
|
|
this_skey.version = next_skey.version;
|
|
|
|
/* Check the version - this only applies to version 3 */
|
|
if (this_skey.version != IPL2TP_VERSION_L2TPV3)
|
|
continue;
|
|
|
|
/* Check for a match, if the session is different */
|
|
if (this_skey.ident != key->ident)
|
|
{
|
|
session = ipcom_hash_get(ipl2tp_example_sessions, &this_skey);
|
|
if (session == IP_NULL)
|
|
continue;
|
|
|
|
/* Check the interface name */
|
|
circuit = (Ipl2tp_v3_circuit_t *)session->session.circuit;
|
|
if (ipcom_strcmp(circuit->intf, intf) == 0)
|
|
return (1);
|
|
}
|
|
|
|
/* Get the next session, if there is one */
|
|
status = ipl2tp_api_session_next(&this_tkey, &this_skey, &next_skey);
|
|
}
|
|
|
|
/* Get the next tunnel if there is one */
|
|
status = ipl2tp_api_tunnel_next(&this_tkey, &next_tkey);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_eth_destroy
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_example_session_eth_destroy(Ipl2tp_key *key)
|
|
{
|
|
Ipl2tp_v3_ethernet_circuit_t *session = ipcom_hash_get(ipl2tp_example_sessions, key);
|
|
|
|
if (session != IP_NULL)
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
Ipl2tp_v3_circuit_t *circuit = session->session.circuit;
|
|
|
|
if (ipl2tp_example_session_check_eth_interface(key, circuit->intf) == 0)
|
|
{
|
|
IPCOM_LOG1(DEBUG, "Interface %s has no other users", circuit->intf);
|
|
|
|
/* OK to turn off promisc mode */
|
|
ipcom_memset(&ifreq, 0, sizeof(struct Ip_ifreq));
|
|
ipcom_strncpy(ifreq.ifr_name, circuit->intf, IP_IFNAMSIZ - 1);
|
|
|
|
if (ipcom_socketioctl(session->fd_eth->fd, IP_SIOCGIFFLAGS, &ifreq) < 0)
|
|
IPCOM_LOG1(ERR,
|
|
"IPL2TPv3: failed to get interface flags: %s",
|
|
ipcom_strerror(ipcom_errno));
|
|
else
|
|
{
|
|
IP_BIT_CLR(ifreq.ip_ifr_flags, IP_IFF_PROMISC);
|
|
if (ipcom_socketioctl(session->fd_eth->fd, IP_SIOCSIFFLAGS, &ifreq) < 0)
|
|
IPCOM_LOG1(ERR,
|
|
"IPL2TPv3: failed to set interface flags: %s",
|
|
ipcom_strerror(ipcom_errno));
|
|
}
|
|
}
|
|
else
|
|
IPCOM_LOG1(DEBUG, "Interface %s does have other users", circuit->intf);
|
|
|
|
/* Remove the object */
|
|
ipcom_hash_remove(ipl2tp_example_sessions, session);
|
|
|
|
/* Remove the socket */
|
|
session->fd_eth->data = IP_NULL;
|
|
session->fd_eth = IP_NULL;
|
|
|
|
/* Free the session */
|
|
ipcom_free(session->session.circuit);
|
|
ipcom_free(session);
|
|
|
|
/* Set the user data */
|
|
if (ipl2tp_attr_pappend(&attr,
|
|
IPL2TP_SATTR_SET_USER_DATA,
|
|
IP_NULL) == IPL2TP_STATUS_OK)
|
|
{
|
|
ipl2tp_api_session_attribute_set(key, attr);
|
|
ipl2tp_attr_delete(&attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_eth_create
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_v3_ethernet_circuit_t *
|
|
ipl2tp_example_session_eth_create(Ipl2tp_v3_circuit_t *circuit,
|
|
Ipl2tp_key *key)
|
|
{
|
|
Ipl2tp_v3_ethernet_circuit_t *session;
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
struct Ip_ifreq ifreq;
|
|
Ipl2tp_callback cb;
|
|
|
|
session = ipcom_calloc(1, sizeof(*session));
|
|
if (session == IP_NULL)
|
|
goto fail;
|
|
|
|
ipcom_memcpy(&session->session.key, key, sizeof(*key));
|
|
session->session.circuit = circuit;
|
|
session->fd_eth = ipcom_malloc(sizeof(*session->fd_eth));
|
|
if (session->fd_eth == IP_NULL)
|
|
goto fail;
|
|
|
|
/* Create socket for catching packets destined to proxied MNs */
|
|
session->fd_eth->fd = ipcom_socket(IP_AF_PACKET, IP_SOCK_RAW, 0);
|
|
if (session->fd_eth->fd == IP_INVALID_SOCKET)
|
|
goto fail;
|
|
|
|
/* Bind raw socket to device */
|
|
if (ipcom_setsockopt(session->fd_eth->fd, IP_SOL_SOCKET, IP_SO_BINDTODEVICE,
|
|
circuit->intf, IP_IFNAMSIZ) == IP_SOCKERR)
|
|
{
|
|
ipcom_socketclose(session->fd_eth->fd);
|
|
goto fail;
|
|
}
|
|
|
|
ipcom_memset(&ifreq, 0, sizeof(struct Ip_ifreq));
|
|
ipcom_if_indextoname(circuit->ifnum, ifreq.ifr_name);
|
|
|
|
if (ipcom_socketioctl(session->fd_eth->fd, IP_SIOCGIFFLAGS, &ifreq) < 0)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"IPL2TPv3: failed to get interface flags: %s",
|
|
ipcom_strerror(ipcom_errno));
|
|
goto fail;
|
|
}
|
|
IP_BIT_SET(ifreq.ip_ifr_flags, IP_IFF_PROMISC);
|
|
if (ipcom_socketioctl(session->fd_eth->fd, IP_SIOCSIFFLAGS, &ifreq) < 0)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"IPL2TPv3: failed to set interface flags: %s",
|
|
ipcom_strerror(ipcom_errno));
|
|
goto fail;
|
|
}
|
|
|
|
session->fd_eth->ptr = session;
|
|
session->fd_eth->data = ipl2tp_example_session_eth_data_input;
|
|
|
|
if (ipcom_hash_add(ipl2tp_example_sessions, session) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "IPL2TPv3: failed to add session");
|
|
goto fail;
|
|
}
|
|
|
|
ipcom_list_insert_last(&ipl2tp_example_fds, &session->fd_eth->next);
|
|
|
|
/* Set the user data */
|
|
if (ipl2tp_attr_pappend(&attr,
|
|
IPL2TP_SATTR_SET_USER_DATA,
|
|
session) != IPL2TP_STATUS_OK)
|
|
{
|
|
IPCOM_LOG0(ERR, "IPL2TPv3: failed to set sesion user data");
|
|
goto fail;
|
|
}
|
|
|
|
/* Set the data callback */
|
|
cb.eth_callback = (Ipl2tp_eth_callback)ipl2tp_example_session_eth_data_output;
|
|
|
|
if (ipl2tp_attr_pappend(&attr,
|
|
IPL2TP_SATTR_SET_DATA_CALLBACK,
|
|
(void *)cb.voidptr) != IPL2TP_STATUS_OK ||
|
|
ipl2tp_attr_iappend(&attr,
|
|
IPL2TP_SATTR_SET_LOCAL_CIRCUIT_STATUS,
|
|
IPL2TP_MIB_UP) != IPL2TP_STATUS_OK)
|
|
{
|
|
IPCOM_LOG0(WARNING, "IPL2TPv3: failed to set attributes");
|
|
}
|
|
|
|
ipl2tp_api_session_attribute_set(key, attr);
|
|
ipl2tp_attr_delete(&attr);
|
|
|
|
return session;
|
|
|
|
fail:
|
|
if (session)
|
|
{
|
|
if (session->fd_eth)
|
|
ipcom_free(session->fd_eth);
|
|
ipcom_free(session);
|
|
}
|
|
ipcom_free(circuit);
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_to_link
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_v3_circuit_t *
|
|
ipl2tp_example_session_to_circuit(Ipl2tp_key *key,
|
|
int type)
|
|
{
|
|
Ipl2tp_v3_circuit_t *circuit;
|
|
Ipl2tp_attrobj replies = IP_NULL;
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
Ipl2tp_attr a;
|
|
Ip_u32 id;
|
|
char buf[128];
|
|
char *ctype;
|
|
int i;
|
|
int argc;
|
|
char **argv = IP_NULL;
|
|
|
|
|
|
|
|
ipl2tp_api_session_attribute_query(key,
|
|
IPL2TP_SATTR_GET_REMOTE_END_ID,
|
|
&replies);
|
|
if ((a = ipl2tp_attr_first(replies)) == IP_NULL)
|
|
return IP_NULL;
|
|
if (ipl2tp_attr_length(a) != 4)
|
|
return IP_NULL;
|
|
|
|
/* Get the router ID */
|
|
id = IP_GET_NTOHL(ipl2tp_attr_vdata(a));
|
|
ipl2tp_attr_delete(&replies);
|
|
|
|
/* Parse the circuit */
|
|
circuit = ipcom_calloc(1, sizeof(*circuit));
|
|
|
|
if(circuit == IP_NULL)
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* */
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.circuit.%ld.name", id);
|
|
if ((circuit->name = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) == IP_NULL)
|
|
goto fail;
|
|
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.circuit.%ld.interface", id);
|
|
if ((circuit->intf = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) == IP_NULL)
|
|
goto fail;
|
|
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.circuit.%ld.attributes", id);
|
|
if ((ctype = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) == IP_NULL)
|
|
{
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.circuit.any.attributes");
|
|
if ((ctype = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) == IP_NULL)
|
|
goto fail;
|
|
}
|
|
|
|
/* Got the argument vector; time to explode it */
|
|
if (ipcom_parse_argstr(ctype, (int *)&argc, &argv) != 0)
|
|
{
|
|
ipcom_free(ctype);
|
|
goto fail;
|
|
}
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
char *value;
|
|
Ipl2tp_attr_info *info;
|
|
|
|
/**/
|
|
if ((info = ipl2tp_api_attribute_find(ipl2tp_session_tags, argv[i], &value)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"L2TP: circuit %s: Invalid attribute %s",
|
|
circuit->name, argv[i]);
|
|
continue;
|
|
}
|
|
|
|
if (ipl2tp_api_attribute_parse(&attr,info,&value) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG3(ERR,
|
|
"L2TP: circuit %s: Invalid attribute %s and value %s",
|
|
circuit->name, argv[i], value);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ipl2tp_api_session_attribute_set(key,attr);
|
|
ipl2tp_attr_delete(&attr);
|
|
ipcom_free(argv);
|
|
ipcom_free(ctype);
|
|
|
|
|
|
/* Retrieve the pseudowire type of the session */
|
|
ipl2tp_api_session_attribute_query(key,
|
|
IPL2TP_SATTR_GET_PSEUDOWIRE_TYPE,
|
|
&replies);
|
|
|
|
if((a = ipl2tp_attr_first(replies)) == IP_NULL)
|
|
{
|
|
ipl2tp_attr_delete(&replies);
|
|
goto fail;
|
|
}
|
|
|
|
/* Does it match? */
|
|
circuit->pw_type = ipl2tp_attr_idata(a);
|
|
ipl2tp_attr_delete(&replies);
|
|
|
|
if (circuit->pw_type != type)
|
|
{
|
|
IPCOM_LOG3(ERR,
|
|
"L2TP: circuit %s: Invalid pseudowire %u vs %u",
|
|
circuit->name,
|
|
circuit->pw_type,
|
|
type);
|
|
goto fail;
|
|
}
|
|
|
|
/* No interface */
|
|
if ((circuit->ifnum = ipcom_if_nametoindex(circuit->intf)) == 0)
|
|
goto fail;
|
|
|
|
/* VLAN tag */
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.circuit.%ld.vlan", id);
|
|
circuit->vlan_tag = ipcom_sysvar_get_as_int0(buf, 0);
|
|
|
|
return circuit;
|
|
|
|
fail:
|
|
if (circuit->name != IP_NULL)
|
|
ipcom_free(circuit->name);
|
|
if (circuit->intf != IP_NULL)
|
|
ipcom_free(circuit->intf);
|
|
ipcom_free(circuit);
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_eth_setup
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_v3_ethernet_circuit_t *
|
|
ipl2tp_example_session_eth_setup(Ipl2tp_key *key,
|
|
int type)
|
|
{
|
|
Ipl2tp_v3_circuit_t *circuit;
|
|
|
|
/* Destroy any previous sessions */
|
|
ipl2tp_example_session_eth_destroy(key);
|
|
|
|
/* Setup this end of the tunnel */
|
|
if ((circuit = ipl2tp_example_session_to_circuit(key, type)) == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
/* Create the session */
|
|
return ipl2tp_example_session_eth_create(circuit, key);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_session_eth_status
|
|
*===========================================================================
|
|
* Description: Session status callback.
|
|
* Parameters: user_data - User callback data.
|
|
* key - Session ID.
|
|
* status - Pointer to status info.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipl2tp_example_session_eth_status(void *user_data,
|
|
Ipl2tp_key *key,
|
|
Ipl2tp_result *result,
|
|
int type)
|
|
{
|
|
Ipl2tp_v3_ethernet_circuit_t *session = user_data;
|
|
|
|
|
|
switch (result->status)
|
|
{
|
|
case IPL2TP_STATUS_OK:
|
|
switch (result->result_code)
|
|
{
|
|
case IPL2TP_OUTGOING_REQUEST:
|
|
{
|
|
/* Setup */
|
|
if ((session = ipl2tp_example_session_eth_setup(key, type)) == IP_NULL)
|
|
return IPL2TP_STATUS_BADID;
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"IPL2TPv3: SESSION (IPL2TP_OUTGOING_REQUEST) session[%s] v%d %d %s",
|
|
((Ipl2tp_v3_circuit_t *)session->session.circuit)->name,
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key));
|
|
break;
|
|
}
|
|
case IPL2TP_OUTGOING_REPLY:
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"IPL2TPv3: SESSION (IPL2TP_OUTGOING_REPLY) v%d %d %s",
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key));
|
|
ipl2tp_api_session_outgoing_established(key, 0, 0, "");
|
|
break;
|
|
}
|
|
case IPL2TP_OUTGOING_ESTABLISHED:
|
|
/* */
|
|
if (session == IP_NULL)
|
|
{
|
|
/* Setup */
|
|
if ((session = ipl2tp_example_session_eth_setup(key, type)) == IP_NULL)
|
|
return IPL2TP_STATUS_BADID;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"IPL2TPv3: SESSION (IPL2TP_OUTGOING_ESTABLISHED) session[%s] v%d %d %s",
|
|
((Ipl2tp_v3_circuit_t *)session->session.circuit)->name,
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key));
|
|
break;
|
|
|
|
case IPL2TP_INCOMING_REQUEST:
|
|
/* Destroy any previous sessions */
|
|
/* Setup */
|
|
if ((session = ipl2tp_example_session_eth_setup(key, type)) == IP_NULL)
|
|
return IPL2TP_STATUS_BADID;
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"IPL2TPv3: SESSION (IPL2TP_INCOMING_REQUEST) session[%s] v%d %d %s",
|
|
((Ipl2tp_v3_circuit_t *)session->session.circuit)->name,
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key));
|
|
|
|
ipl2tp_api_session_incoming_established(key, 0, 0, "");
|
|
break;
|
|
|
|
case IPL2TP_INCOMING_ESTABLISHED:
|
|
/* */
|
|
if (session == IP_NULL)
|
|
{
|
|
/* Setup */
|
|
if ((session = ipl2tp_example_session_eth_setup(key, type)) == IP_NULL)
|
|
return IPL2TP_STATUS_BADID;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG,
|
|
"IPL2TPv3: SESSION (IPL2TP_INCOMING_ESTABLISHED) session[%s] v%d %d %s",
|
|
((Ipl2tp_v3_circuit_t *)session->session.circuit)->name,
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IPCOM_LOG6(DEBUG,
|
|
"IPL2TPv3: SESSION (%u) Session[%s] v%d %d %s closed with status %s",
|
|
(int)result->status,
|
|
session? ((Ipl2tp_v3_circuit_t *)session->session.circuit)->name : "<invalid>",
|
|
key->version, key->ident,
|
|
ipl2tp_api_session_type(key),
|
|
ipl2tp_api_errname(result->status));
|
|
ipl2tp_example_session_eth_destroy(key);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_tunnel_auth
|
|
*===========================================================================
|
|
* Description: Set the tunnel auth if available.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_example_tunnel_auth(Ipl2tp_key *key,
|
|
Ip_u32 rID,
|
|
const char *peer)
|
|
{
|
|
char buf[128];
|
|
char *ctype;
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
int argc;
|
|
char **argv = IP_NULL;
|
|
int i;
|
|
|
|
do
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"L2TP: Verifying attributes for %ld@%s",
|
|
rID, peer);
|
|
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.control.%ld.attributes", rID);
|
|
if ((ctype = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) != IP_NULL)
|
|
break;
|
|
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.control.%s.attributes", peer);
|
|
if ((ctype = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) != IP_NULL)
|
|
break;
|
|
|
|
ipcom_snprintf(buf, sizeof(buf), "ipl2tp.v3.control.any.attributes");
|
|
if ((ctype = ipcom_sysvar_get(buf, IP_NULL, IP_NULL)) != IP_NULL)
|
|
break;
|
|
|
|
return;
|
|
} while (0);
|
|
|
|
|
|
/* Got the argument vector; time to explode it */
|
|
if (ipcom_parse_argstr(ctype, (int *)&argc, &argv) != 0)
|
|
{
|
|
ipcom_free(ctype);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
char *value;
|
|
Ipl2tp_attr_info *info;
|
|
|
|
/**/
|
|
if ((info = ipl2tp_api_attribute_find(ipl2tp_tunnel_tags, argv[i], &value)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"L2TP: tunnel: Invalid attribute %s",
|
|
argv[i]);
|
|
continue;
|
|
}
|
|
|
|
if (ipl2tp_api_attribute_parse(&attr,info,&value) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"L2TP: Invalid attribute %s and value %s",
|
|
argv[i], value);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ipl2tp_api_tunnel_attribute_set(key,attr);
|
|
ipl2tp_attr_delete(&attr);
|
|
ipcom_free(argv);
|
|
ipcom_free(ctype);
|
|
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_sstatus_v3
|
|
*===========================================================================
|
|
* Description: Session status callback.
|
|
* Parameters: user_data - User callback data.
|
|
* key - Session ID.
|
|
* status - Pointer to status info.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipl2tp_example_sstatus_v3(void *user_data,
|
|
Ipl2tp_key *key,
|
|
Ipl2tp_result *result)
|
|
{
|
|
int type;
|
|
Ipl2tp_attrobj replies = IP_NULL;
|
|
Ipl2tp_attr a;
|
|
|
|
ipl2tp_api_session_attribute_query(key,
|
|
IPL2TP_SATTR_GET_PSEUDOWIRE_TYPE,
|
|
&replies);
|
|
|
|
if((a = ipl2tp_attr_first(replies)) == IP_NULL)
|
|
{
|
|
ipl2tp_attr_delete(&replies);
|
|
return IPL2TP_STATUS_BADAVP;
|
|
}
|
|
|
|
type = ipl2tp_attr_idata(a);
|
|
ipl2tp_attr_delete(&replies);
|
|
|
|
/* ETHERNET pseudowire type */
|
|
if (type == IPL2TP_ATTR_PW_TYPE_ETHERNET ||
|
|
type == IPL2TP_ATTR_PW_TYPE_ETHERNET_VLAN)
|
|
{
|
|
/* */
|
|
return ipl2tp_example_session_eth_status(user_data, key, result, type);
|
|
}
|
|
|
|
|
|
return IPL2TP_STATUS_BADPW;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_example_tstatus_v3
|
|
*===========================================================================
|
|
* Description: Tunnel status callback.
|
|
* Parameters: user_data - User callback data.
|
|
* key - Tunnel ID.
|
|
* status - Pointer to status info.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipl2tp_example_tstatus_v3(void *user_data,
|
|
Ipl2tp_key *key,
|
|
Ipl2tp_result *result)
|
|
{
|
|
Ipl2tp_attrobj replies = IP_NULL;
|
|
Ipl2tp_attrobj attr = IP_NULL;
|
|
Ipl2tp_attr a;
|
|
Ip_u32 rID;
|
|
const char *peer;
|
|
|
|
IPL2TP_UNUSED(user_data);
|
|
|
|
/* Get the remote info */
|
|
ipl2tp_attr_add_query(&attr, IPL2TP_TATTR_GET_REMOTE_ROUTER_ID);
|
|
ipl2tp_attr_add_query(&attr, IPL2TP_TATTR_GET_l2tpTunnelStatsRemoteHostName);
|
|
|
|
ipl2tp_api_tunnel_attribute_get(key, attr, &replies);
|
|
ipl2tp_attr_delete(&attr);
|
|
|
|
/* Get the router ID */
|
|
a = ipl2tp_attr_first(replies);
|
|
if(a == IP_NULL)
|
|
{
|
|
ipl2tp_attr_delete(&replies);
|
|
return 0;
|
|
}
|
|
|
|
rID = ipl2tp_attr_idata(a);
|
|
|
|
/* Get the remote host name */
|
|
a = ipl2tp_attr_next(a);
|
|
peer = ipl2tp_attr_strdata(a);
|
|
|
|
switch (result->status)
|
|
{
|
|
case IPL2TP_STATUS_OK:
|
|
switch (result->result_code)
|
|
{
|
|
case IPL2TP_OUTGOING_AUTHENTICATION:
|
|
{
|
|
/* Allocate an attribute object */
|
|
IPCOM_LOG3(DEBUG,
|
|
"IPL2TPv3: TUNNEL (IPL2TP_OUTGOING_AUTHENTICATION) v%d %d requested by '%s'",
|
|
key->version, key->ident,
|
|
peer);
|
|
|
|
ipl2tp_example_tunnel_auth(key, rID, peer);
|
|
|
|
|
|
/* We've installed the authentication data required,
|
|
* do continue the tunnel processing and attempt to establish */
|
|
ipl2tp_api_tunnel_authentication_established(key);
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_OUTGOING_REQUEST:
|
|
{
|
|
IPCOM_LOG3(DEBUG,
|
|
"IPL2TPv3: TUNNEL (IPL2TP_OUTGOING_REQUEST) v%d %d from '%s'",
|
|
key->version, key->ident,
|
|
peer);
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_OUTGOING_ESTABLISHED:
|
|
IPCOM_LOG2(DEBUG,
|
|
"IPL2TPv3: TUNNEL (IPL2TP_OUTGOING_ESTABLISHED) v%d %d opened",
|
|
key->version, key->ident);
|
|
break;
|
|
|
|
case IPL2TP_INCOMING_ESTABLISHED:
|
|
IPCOM_LOG2(DEBUG,
|
|
"IPL2TPv3: TUNNEL (IPL2TP_INCOMING_ESTABLISHED) v%d %d opened",
|
|
key->version, key->ident);
|
|
break;
|
|
}
|
|
break;
|
|
case IPL2TP_STATUS_NEGOTIATION:
|
|
IPCOM_LOG2(DEBUG,
|
|
"IPL2TPv3: TUNNEL (IPL2TP_STATUS_NEGOTIATION) v%d %d closed obsoleted by version negotiation",
|
|
key->version, key->ident);
|
|
break;
|
|
|
|
default:
|
|
IPCOM_LOG4(DEBUG,
|
|
"IPL2TPv3: TUNNEL (%u) v%d %d closed with status %s",
|
|
(int)result->status,
|
|
key->version, key->ident,
|
|
ipl2tp_api_errname(result->status));
|
|
break;
|
|
}
|
|
|
|
ipl2tp_attr_delete(&replies);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|