/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 : "", 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 **************************************************************************** */