/* $OpenBSD: print-l2tp.c,v 1.3 2007/10/07 16:41:05 deraadt Exp $ */ /* * Copyright (c) 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * L2TP support contributed by Motonori Shindo (mshindo@ascend.co.jp) */ #ifndef lint static const char rcsid[] = "@(#) $Id: print-l2tp.c,v 1.3 2007/10/07 16:41:05 deraadt Exp $"; #endif #include <sys/types.h> #include <sys/param.h> #include <stdio.h> #include "l2tp.h" #include "interface.h" static char tstr[] = " [|l2tp]"; #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static u_char *l2tp_message_type_string[] = { "RESERVED_0", /* 0 Reserved */ "SCCRQ", /* 1 Start-Control-Connection-Request */ "SCCRP", /* 2 Start-Control-Connection-Reply */ "SCCCN", /* 3 Start-Control-Connection-Connected */ "StopCCN", /* 4 Stop-Control-Connection-Notification */ "RESERVED_5", /* 5 Reserved */ "HELLO", /* 6 Hello */ "OCRQ", /* 7 Outgoing-Call-Request */ "OCRP", /* 8 Outgoing-Call-Reply */ "OCCN", /* 9 Outgoing-Call-Connected */ "ICRQ", /* 10 Incoming-Call-Request */ "ICRP", /* 11 Incoming-Call-Reply */ "ICCN", /* 12 Incoming-Call-Connected */ "RESERVED_13", /* 13 Reserved */ "CDN", /* 14 Call-Disconnect-Notify */ "WEN", /* 15 WAN-Error-Notify */ "SLI" /* 16 Set-Link-Info */ #define L2TP_MAX_MSGTYPE_INDEX 17 }; static void l2tp_msgtype_print(const u_char *dat, u_int length); static void l2tp_result_code_print(const u_char *dat, u_int length); static void l2tp_proto_ver_print(const u_char *dat, u_int length); static void l2tp_framing_cap_print(const u_char *dat, u_int length); static void l2tp_bearer_cap_print(const u_char *dat, u_int length); static void l2tp_tie_breaker_print(const u_char *dat, u_int length); static void l2tp_firm_ver_print(const u_char *dat, u_int length); static void l2tp_host_name_print(const u_char *dat, u_int length); static void l2tp_vendor_name_print(const u_char *dat, u_int length); static void l2tp_assnd_tun_id_print(const u_char *dat, u_int length); static void l2tp_recv_win_size_print(const u_char *dat, u_int length); static void l2tp_challenge_print(const u_char *dat, u_int length); static void l2tp_q931_cc_print(const u_char *dat, u_int length); static void l2tp_challenge_resp_print(const u_char *dat, u_int length); static void l2tp_assnd_sess_id_print(const u_char *dat, u_int length); static void l2tp_call_ser_num_print(const u_char *dat, u_int length); static void l2tp_minimum_bps_print(const u_char *dat, u_int length); static void l2tp_maximum_bps_print(const u_char *dat, u_int length); static void l2tp_bearer_type_print(const u_char *dat, u_int length); static void l2tp_framing_type_print(const u_char *dat, u_int length); static void l2tp_packet_proc_delay_print(const u_char *dat, u_int length); static void l2tp_called_number_print(const u_char *dat, u_int length); static void l2tp_calling_number_print(const u_char *dat, u_int length); static void l2tp_sub_address_print(const u_char *dat, u_int length); static void l2tp_tx_conn_speed_print(const u_char *dat, u_int length); static void l2tp_phy_channel_id_print(const u_char *dat, u_int length); static void l2tp_ini_recv_lcp_print(const u_char *dat, u_int length); static void l2tp_last_sent_lcp_print(const u_char *dat, u_int length); static void l2tp_last_recv_lcp_print(const u_char *dat, u_int length); static void l2tp_proxy_auth_type_print(const u_char *dat, u_int length); static void l2tp_proxy_auth_name_print(const u_char *dat, u_int length); static void l2tp_proxy_auth_chal_print(const u_char *dat, u_int length); static void l2tp_proxy_auth_id_print(const u_char *dat, u_int length); static void l2tp_proxy_auth_resp_print(const u_char *dat, u_int length); static void l2tp_call_errors_print(const u_char *dat, u_int length); static void l2tp_accm_print(const u_char *dat, u_int length); static void l2tp_random_vector_print(const u_char *dat, u_int length); static void l2tp_private_grp_id_print(const u_char *dat, u_int length); static void l2tp_rx_conn_speed_print(const u_char *dat, u_int length); static void l2tp_seq_required_print(const u_char *dat, u_int length); static void l2tp_avp_print(const u_char *dat, u_int length); static struct l2tp_avp_vec l2tp_avp[] = { {"MSGTYPE", l2tp_msgtype_print}, /* 0 Message Type */ {"RESULT_CODE", l2tp_result_code_print}, /* 1 Result Code */ {"PROTO_VER", l2tp_proto_ver_print}, /* 2 Protocol Version */ {"FRAMING_CAP", l2tp_framing_cap_print}, /* 3 Framing Capabilities */ {"BEARER_CAP", l2tp_bearer_cap_print}, /* 4 Bearer Capabilities */ {"TIE_BREAKER", l2tp_tie_breaker_print}, /* 5 Tie Breaker */ {"FIRM_VER", l2tp_firm_ver_print}, /* 6 Firmware Revision */ {"HOST_NAME", l2tp_host_name_print}, /* 7 Host Name */ {"VENDOR_NAME", l2tp_vendor_name_print}, /* 8 Vendor Name */ {"ASSND_TUN_ID", l2tp_assnd_tun_id_print}, /* 9 Assigned Tunnel ID */ {"RECV_WIN_SIZE", l2tp_recv_win_size_print}, /* 10 Receive Window Size */ {"CHALLENGE", l2tp_challenge_print}, /* 11 Challenge */ {"Q931_CC", l2tp_q931_cc_print}, /* 12 Q.931 Cause Code */ {"CHALLENGE_RESP", l2tp_challenge_resp_print},/* 13 Challenge Response */ {"ASSND_SESS_ID", l2tp_assnd_sess_id_print}, /* 14 Assigned Session ID */ {"CALL_SER_NUM", l2tp_call_ser_num_print}, /* 15 Call Serial Number */ {"MINIMUM_BPS", l2tp_minimum_bps_print},/* 16 Minimum BPS */ {"MAXIMUM_BPS", l2tp_maximum_bps_print}, /* 17 Maximum BPS */ {"BEARER_TYPE", l2tp_bearer_type_print},/* 18 Bearer Type */ {"FRAMING_TYPE", l2tp_framing_type_print}, /* 19 Framing Type */ {"PACKET_PROC_DELAY", l2tp_packet_proc_delay_print}, /* 20 Packet Processing Delay (OBSOLETE) */ {"CALLED_NUMBER", l2tp_called_number_print}, /* 21 Called Number */ {"CALLING_NUMBER", l2tp_calling_number_print},/* 22 Calling Number */ {"SUB_ADDRESS", l2tp_sub_address_print},/* 23 Sub-Address */ {"TX_CONN_SPEED", l2tp_tx_conn_speed_print}, /* 24 (Tx) Connect Speed */ {"PHY_CHANNEL_ID", l2tp_phy_channel_id_print},/* 25 Physical Channel ID */ {"INI_RECV_LCP", l2tp_ini_recv_lcp_print}, /* 26 Initial Received LCP CONFREQ */ {"LAST_SENT_LCP", l2tp_last_sent_lcp_print}, /* 27 Last Sent LCP CONFREQ */ {"LAST_RECV_LCP", l2tp_last_recv_lcp_print}, /* 28 Last Received LCP CONFREQ */ {"PROXY_AUTH_TYPE", l2tp_proxy_auth_type_print},/* 29 Proxy Authen Type */ {"PROXY_AUTH_NAME", l2tp_proxy_auth_name_print},/* 30 Proxy Authen Name */ {"PROXY_AUTH_CHAL", l2tp_proxy_auth_chal_print},/* 31 Proxy Authen Challenge */ {"PROXY_AUTH_ID", l2tp_proxy_auth_id_print}, /* 32 Proxy Authen ID */ {"PROXY_AUTH_RESP", l2tp_proxy_auth_resp_print},/* 33 Proxy Authen Response */ {"CALL_ERRORS", l2tp_call_errors_print}, /* 34 Call Errors */ {"ACCM", l2tp_accm_print}, /* 35 ACCM */ {"RANDOM_VECTOR", l2tp_random_vector_print}, /* 36 Random Vector */ {"PRIVATE_GRP_ID", l2tp_private_grp_id_print},/* 37 Private Group ID */ {"RX_CONN_SPEED", l2tp_rx_conn_speed_print}, /* 38 (Rx) Connect Speed */ {"SEQ_REQUIRED", l2tp_seq_required_print}, /* 39 Sequencing Required */ #define L2TP_MAX_AVP_INDEX 40 }; #if 0 static char *l2tp_result_code_StopCCN[] = { "Reserved", "General request to clear control connection", "General error--Error Code indicates the problem", "Control channel already exists", "Requester is not authorized to establish a control channel", "The protocol version of the requester is not supported", "Requester is being shut down", "Finite State Machine error" #define L2TP_MAX_RESULT_CODE_STOPCC_INDEX 8 }; #endif #if 0 static char *l2tp_result_code_CDN[] = { "Reserved", "Call disconnected due to loss of carrier", "Call disconnected for the reason indicated in error code", "Call disconnected for administrative reasons", "Call failed due to lack of appropriate facilities being " \ "available (temporary condition)", "Call failed due to lack of appropriate facilities being " \ "available (permanent condition)", "Invalid destination", "Call failed due to no carrier detected", "Call failed due to detection of a busy signal", "Call failed due to lack of a dial tone", "Call was not established within time allotted by LAC", "Call was connected but no appropriate framing was detected" #define L2TP_MAX_RESULT_CODE_CDN_INDEX 12 }; #endif #if 0 static char *l2tp_error_code_general[] = { "No general error", "No control connection exists yet for this LAC-LNS pair", "Length is wrong", "One of the field values was out of range or " \ "reserved field was non-zero" "Insufficient resources to handle this operation now", "The Session ID is invalid in this context", "A generic vendor-specific error occurred in the LAC", "Try another" #define L2TP_MAX_ERROR_CODE_GENERAL_INDEX 8 }; #endif /******************************/ /* generic print out routines */ /******************************/ static void print_string(const u_char *dat, u_int length) { int i; for (i=0; i<length; i++) { printf("%c", *dat++); } } static void print_octets(const u_char *dat, u_int length) { int i; for (i=0; i<length; i++) { printf("%02x", *dat++); } } static void print_short(const u_short *dat) { printf("%u", ntohs(*dat)); } static void print_int(const u_int *dat) { printf("%lu", (u_long)ntohl(*dat)); } /**********************************/ /* AVP-specific print out routines*/ /**********************************/ static void l2tp_msgtype_print(const u_char *dat, u_int length) { u_short *ptr = (u_short *)dat; if (ntohs(*ptr) < L2TP_MAX_MSGTYPE_INDEX) { printf("%s", l2tp_message_type_string[ntohs(*ptr)]); } } static void l2tp_result_code_print(const u_char *dat, u_int length) { /* we just print out the result and error code number */ u_short *ptr = (u_short *)dat; if (length == 2) { /* result code */ printf("%d", ntohs(*ptr)); } else if (length == 4) { /* result & error code */ printf("%d/%d", ntohs(*ptr), ntohs(*(ptr+1))); } else if (length > 4) { /* result & error code & msg */ printf("%u/%u ", ntohs(*ptr), ntohs(*(ptr+1))); print_string((u_char *)(ptr+2), length - 4); } } static void l2tp_proto_ver_print(const u_char *dat, u_int length) { printf("%d.%d", *dat, *(dat+1)); } static void l2tp_framing_cap_print(const u_char *dat, u_int length) { u_int *ptr = (u_int *)dat; if (ntohl(*ptr) & L2TP_FRAMING_CAP_ASYNC_MASK) { printf("A"); } if (ntohl(*ptr) & L2TP_FRAMING_CAP_SYNC_MASK) { printf("S"); } } static void l2tp_bearer_cap_print(const u_char *dat, u_int length) { u_int *ptr = (u_int *)dat; if (ntohl(*ptr) & L2TP_BEARER_CAP_ANALOG_MASK) { printf("A"); } if (ntohl(*ptr) & L2TP_BEARER_CAP_DIGITAL_MASK) { printf("D"); } } static void l2tp_tie_breaker_print(const u_char *dat, u_int length) { printf("%lx", *(u_long *)dat); /* XXX */ } static void l2tp_firm_ver_print(const u_char *dat, u_int length) { print_short((u_short *)dat); } static void l2tp_host_name_print(const u_char *dat, u_int length) { print_string(dat, length); } static void l2tp_vendor_name_print(const u_char *dat, u_int length) { print_string(dat, length); } static void l2tp_assnd_tun_id_print(const u_char *dat, u_int length) { print_short((u_short *)dat); } static void l2tp_recv_win_size_print(const u_char *dat, u_int length) { print_short((u_short *)dat); } static void l2tp_challenge_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_q931_cc_print(const u_char *dat, u_int length) { print_short((u_short *)dat); print_short((u_short *)(dat + 2)); if (length > 3) { printf(" "); print_string(dat+3, length-3); } } static void l2tp_challenge_resp_print(const u_char *dat, u_int length) { print_octets(dat, 16); /* XXX length should be 16? */ } static void l2tp_assnd_sess_id_print(const u_char *dat, u_int length) { print_short((u_short *)dat); } static void l2tp_call_ser_num_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_minimum_bps_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_maximum_bps_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_bearer_type_print(const u_char *dat, u_int length) { u_int *ptr = (u_int *)dat; if (ntohl(*ptr) & L2TP_BEARER_TYPE_ANALOG_MASK) { printf("A"); } if (ntohl(*ptr) & L2TP_BEARER_TYPE_DIGITAL_MASK) { printf("D"); } } static void l2tp_framing_type_print(const u_char *dat, u_int length) { u_int *ptr = (u_int *)dat; if (ntohl(*ptr) & L2TP_FRAMING_TYPE_ASYNC_MASK) { printf("A"); } if (ntohl(*ptr) & L2TP_FRAMING_TYPE_SYNC_MASK) { printf("S"); } } static void l2tp_packet_proc_delay_print(const u_char *dat, u_int length) { printf("obsolete"); } static void l2tp_called_number_print(const u_char *dat, u_int length) { print_string(dat, length); } static void l2tp_calling_number_print(const u_char *dat, u_int length) { print_string(dat, length); } static void l2tp_sub_address_print(const u_char *dat, u_int length) { print_string(dat, length); } static void l2tp_tx_conn_speed_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_phy_channel_id_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_ini_recv_lcp_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_last_sent_lcp_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_last_recv_lcp_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_proxy_auth_type_print(const u_char *dat, u_int length) { u_short *ptr = (u_short *)dat; switch (ntohs(*ptr)) { case L2TP_AUTHEN_TYPE_RESERVED: printf("Reserved"); break; case L2TP_AUTHEN_TYPE_TEXTUAL: printf("Textual"); break; case L2TP_AUTHEN_TYPE_CHAP: printf("CHAP"); break; case L2TP_AUTHEN_TYPE_PAP: printf("PAP"); break; case L2TP_AUTHEN_TYPE_NO_AUTH: printf("No Auth"); break; case L2TP_AUTHEN_TYPE_MSCHAP: printf("MS-CHAP"); break; default: printf("unknown"); } } static void l2tp_proxy_auth_name_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_proxy_auth_chal_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_proxy_auth_id_print(const u_char *dat, u_int length) { u_short *ptr = (u_short *)dat; printf("%d", ntohs(*ptr) & L2TP_PROXY_AUTH_ID_MASK); } static void l2tp_proxy_auth_resp_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_call_errors_print(const u_char *dat, u_int length) { struct l2tp_call_errors *ptr = (struct l2tp_call_errors *)dat; printf("CRCErr=%d FrameErr=%d HardOver=%d BufOver=%d ", ptr->crc_errs, ptr->framing_errs, ptr->hardware_overruns, ptr->buffer_overruns); printf("Timeout=%d AlingErr=%d", ptr->timeout_errs, ptr->alignment_errs); } static void l2tp_accm_print(const u_char *dat, u_int length) { struct l2tp_accm *ptr = (struct l2tp_accm *)dat; printf("send=%x recv=%x", ptr->send_accm, ptr->recv_accm); } static void l2tp_random_vector_print(const u_char *dat, u_int length) { print_octets(dat, length); } static void l2tp_private_grp_id_print(const u_char *dat, u_int length) { print_string(dat, length); /* XXX print_octets is more appropriate?? */ } static void l2tp_rx_conn_speed_print(const u_char *dat, u_int length) { print_int((u_int *)dat); } static void l2tp_seq_required_print(const u_char *dat, u_int length) { return; } static void l2tp_avp_print(const u_char *dat, u_int length) { u_int len; const u_short *ptr = (u_short *)dat; int hidden = FALSE; printf(" "); if (length > 0 && (snapend - dat) >= 2) { /* there must be at least two octets for the length to be decoded */ if ((len = (ntohs(*ptr) & L2TP_AVP_HDR_LEN_MASK)) <= (snapend - dat)) { if (ntohs(*ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) { printf("*"); } if (ntohs(*ptr) & L2TP_AVP_HDR_FLAG_HIDDEN) { hidden = TRUE; printf("?"); } } else { printf("|..."); return; } ptr++; if (ntohs(*ptr)) { /* IETF == 0 */ printf("vendor=%04x", ntohs(*ptr)); } ptr++; if (ntohs(*ptr) < L2TP_MAX_AVP_INDEX) { printf("%s", l2tp_avp[ntohs(*ptr)].name); printf("("); if (!hidden && len >= 6) { (l2tp_avp[ntohs(*ptr)].print) ((u_char *)ptr+2, len-6); } else { printf("???"); } printf(")"); } else { printf(" invalid AVP %u", ntohs(*ptr)); } if (length >= len && len > 0) l2tp_avp_print(dat + len, length - len); } else if (length == 0) { return; } else { printf("|..."); } } void l2tp_print(const u_char *dat, u_int length) { const u_short *ptr = (u_short *)dat; u_int cnt = 0; /* total octets consumed */ u_short pad; int flag_t, flag_l, flag_s, flag_o, flag_p; u_short l2tp_len; flag_t = flag_l = flag_s = flag_o = flag_p = FALSE; if (length < 6 || snapend - dat < 6) { /* flag/ver, tunnel_id, session_id must be present for this packet to be properly decoded */ printf("%s", tstr); return; } if ((ntohs(*ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) { printf(" l2tp:"); } else if ((ntohs(*ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2F) { printf(" l2f:"); return; /* nothing to do */ } else { printf(" Unknown Version, neither L2F(1) nor L2TP(2)"); return; /* nothing we can do */ } printf("["); if (ntohs(*ptr) & L2TP_FLAG_TYPE) { flag_t = TRUE; printf("T"); } if (ntohs(*ptr) & L2TP_FLAG_LENGTH) { flag_l = TRUE; printf("L"); } if (ntohs(*ptr) & L2TP_FLAG_SEQUENCE) { flag_s = TRUE; printf("S"); } if (ntohs(*ptr) & L2TP_FLAG_OFFSET) { flag_o = TRUE; printf("O"); } if (ntohs(*ptr) & L2TP_FLAG_PRIORITY) { flag_p = TRUE; printf("P"); } printf("]"); ptr++; cnt += 2; if (flag_l) { l2tp_len = ntohs(*ptr++); /* XXX need to consider truncation ?? */ cnt += 2; } else { l2tp_len = 0; } printf("(%d/", ntohs(*ptr++)); /* Tunnel ID */ printf("%d)", ntohs(*ptr++)); /* Session ID */ cnt += 4; if (flag_s) { printf("Ns=%d,", ntohs(*ptr++)); printf("Nr=%d", ntohs(*ptr++)); cnt += 4; } if (flag_o) { pad = ntohs(*ptr++); (u_char *)ptr += pad; cnt += (2 + pad); } if (flag_t) { if (length - cnt == 0) { printf(" ZLB"); } else { if (length >= cnt) l2tp_avp_print((u_char *)ptr, length - cnt); } } else { #if 0 printf(" {"); ppp_hdlc_print((u_char *)ptr, length - cnt); printf("}"); #else printf("[hdlc|]"); #endif } }