Home | History | Annotate | Line # | Download | only in pppol2tp
      1      1.1  christos /*****************************************************************************
      2      1.1  christos  * Copyright (C) 2006,2007,2008 Katalix Systems Ltd
      3      1.1  christos  *
      4      1.1  christos  * This program is free software; you can redistribute it and/or modify
      5      1.1  christos  * it under the terms of the GNU General Public License as published by
      6      1.1  christos  * the Free Software Foundation; either version 2 of the License, or
      7      1.1  christos  * (at your option) any later version.
      8      1.1  christos  *
      9      1.1  christos  * This program is distributed in the hope that it will be useful,
     10      1.1  christos  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11      1.1  christos  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12      1.1  christos  * GNU General Public License for more details.
     13      1.1  christos  *
     14      1.1  christos  * You should have received a copy of the GNU General Public License
     15      1.1  christos  * along with this program; if not, write to the Free Software
     16      1.1  christos  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     17      1.1  christos  *
     18      1.1  christos  *****************************************************************************/
     19      1.1  christos 
     20      1.1  christos /* pppd plugin for interfacing to openl2tpd */
     21      1.1  christos 
     22      1.1  christos #include <unistd.h>
     23      1.1  christos #include <string.h>
     24      1.1  christos #include <stdlib.h>
     25      1.1  christos #include <errno.h>
     26  1.1.1.3  christos 
     27      1.1  christos #include <sys/stat.h>
     28      1.1  christos #include <net/if.h>
     29      1.1  christos #include <sys/ioctl.h>
     30      1.1  christos #include <sys/socket.h>
     31      1.1  christos #include <sys/un.h>
     32  1.1.1.3  christos #include <sys/time.h>
     33      1.1  christos #include <netinet/in.h>
     34      1.1  christos #include <signal.h>
     35      1.1  christos #include <linux/version.h>
     36      1.1  christos #include <linux/sockios.h>
     37  1.1.1.3  christos #include <stdarg.h>
     38  1.1.1.3  christos #include <stdbool.h>
     39  1.1.1.3  christos #include <stdio.h>
     40  1.1.1.3  christos 
     41  1.1.1.3  christos #include <pppd/pppd.h>
     42  1.1.1.3  christos #include <pppd/options.h>
     43  1.1.1.3  christos #include <pppd/fsm.h>
     44  1.1.1.3  christos #include <pppd/lcp.h>
     45  1.1.1.3  christos #include <pppd/ccp.h>
     46  1.1.1.3  christos #include <pppd/ipcp.h>
     47  1.1.1.3  christos #include <pppd/multilink.h>
     48  1.1.1.3  christos 
     49      1.1  christos 
     50      1.1  christos #ifndef aligned_u64
     51      1.1  christos /* should be defined in sys/types.h */
     52      1.1  christos #define aligned_u64 unsigned long long __attribute__((aligned(8)))
     53      1.1  christos #endif
     54      1.1  christos #include <linux/types.h>
     55      1.1  christos #include <linux/if_ether.h>
     56      1.1  christos #include <linux/ppp_defs.h>
     57      1.1  christos #include <linux/if_pppox.h>
     58      1.1  christos #include <linux/if_pppol2tp.h>
     59      1.1  christos 
     60      1.1  christos #include "l2tp_event.h"
     61      1.1  christos 
     62      1.1  christos extern int pppol2tp_tunnel_id;
     63      1.1  christos extern int pppol2tp_session_id;
     64      1.1  christos 
     65      1.1  christos extern void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
     66      1.1  christos 				       uint32_t send_accm, uint32_t recv_accm);
     67      1.1  christos extern void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up);
     68      1.1  christos 
     69  1.1.1.3  christos const char pppd_version[] = PPPD_VERSION;
     70      1.1  christos 
     71      1.1  christos static int openl2tp_fd = -1;
     72      1.1  christos 
     73      1.1  christos static void (*old_pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
     74      1.1  christos 					   uint32_t send_accm,
     75      1.1  christos 					   uint32_t recv_accm) = NULL;
     76      1.1  christos static void (*old_pppol2tp_ip_updown_hook)(int tunnel_id, int session_id,
     77      1.1  christos 					   int up) = NULL;
     78  1.1.1.3  christos #ifdef PPP_WITH_MULTILINK
     79  1.1.1.3  christos static multilink_join_hook_fn *old_multilink_join_hook = NULL;
     80  1.1.1.3  christos #endif
     81      1.1  christos 
     82      1.1  christos /*****************************************************************************
     83      1.1  christos  * OpenL2TP interface.
     84      1.1  christos  * We send a PPP_ACCM_IND to openl2tpd to report ACCM values and
     85      1.1  christos  * SESSION_PPP_UPDOWN_IND to indicate when the PPP link comes up or
     86      1.1  christos  * goes down.
     87      1.1  christos  *****************************************************************************/
     88      1.1  christos 
     89      1.1  christos static int openl2tp_client_create(void)
     90      1.1  christos {
     91      1.1  christos 	struct sockaddr_un addr;
     92      1.1  christos 	int result;
     93      1.1  christos 
     94      1.1  christos 	if (openl2tp_fd < 0) {
     95      1.1  christos 		openl2tp_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
     96      1.1  christos 		if (openl2tp_fd < 0) {
     97      1.1  christos 			error("openl2tp connection create: %m");
     98      1.1  christos 			return -ENOTCONN;
     99      1.1  christos 		}
    100      1.1  christos 
    101      1.1  christos 		addr.sun_family = AF_UNIX;
    102      1.1  christos 		strcpy(&addr.sun_path[0], OPENL2TP_EVENT_SOCKET_NAME);
    103      1.1  christos 
    104      1.1  christos 		result = connect(openl2tp_fd, (struct sockaddr *) &addr,
    105      1.1  christos 				 sizeof(addr));
    106      1.1  christos 		if (result < 0) {
    107      1.1  christos 			error("openl2tp connection connect: %m");
    108      1.1  christos 			return -ENOTCONN;
    109      1.1  christos 		}
    110      1.1  christos 	}
    111      1.1  christos 
    112      1.1  christos 	return 0;
    113      1.1  christos }
    114      1.1  christos 
    115      1.1  christos static void openl2tp_send_accm_ind(int tunnel_id, int session_id,
    116      1.1  christos 				   uint32_t send_accm, uint32_t recv_accm)
    117      1.1  christos {
    118      1.1  christos 	int result;
    119      1.1  christos 	uint8_t buf[OPENL2TP_MSG_MAX_LEN];
    120      1.1  christos 	struct openl2tp_event_msg *msg = (void *) &buf[0];
    121      1.1  christos 	struct openl2tp_event_tlv *tlv;
    122      1.1  christos 	uint16_t tid = tunnel_id;
    123      1.1  christos 	uint16_t sid = session_id;
    124      1.1  christos 	struct openl2tp_tlv_ppp_accm accm;
    125      1.1  christos 
    126      1.1  christos 	if (openl2tp_fd < 0) {
    127      1.1  christos 		result = openl2tp_client_create();
    128      1.1  christos 		if (result < 0) {
    129      1.1  christos 			goto out;
    130      1.1  christos 		}
    131      1.1  christos 	}
    132      1.1  christos 
    133      1.1  christos 	accm.send_accm = send_accm;
    134      1.1  christos 	accm.recv_accm = recv_accm;
    135      1.1  christos 
    136      1.1  christos 	msg->msg_signature = OPENL2TP_MSG_SIGNATURE;
    137      1.1  christos 	msg->msg_type = OPENL2TP_MSG_TYPE_PPP_ACCM_IND;
    138      1.1  christos 	msg->msg_len = 0;
    139      1.1  christos 
    140      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    141      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_TUNNEL_ID;
    142      1.1  christos 	tlv->tlv_len = sizeof(tid);
    143      1.1  christos 	memcpy(&tlv->tlv_value[0], &tid, tlv->tlv_len);
    144      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    145      1.1  christos 
    146      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    147      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_SESSION_ID;
    148      1.1  christos 	tlv->tlv_len = sizeof(sid);
    149      1.1  christos 	memcpy(&tlv->tlv_value[0], &sid, tlv->tlv_len);
    150      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    151      1.1  christos 
    152      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    153      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_ACCM;
    154      1.1  christos 	tlv->tlv_len = sizeof(accm);
    155      1.1  christos 	memcpy(&tlv->tlv_value[0], &accm, tlv->tlv_len);
    156      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    157      1.1  christos 
    158      1.1  christos 	result = send(openl2tp_fd, msg, sizeof(*msg) + msg->msg_len,
    159      1.1  christos 		      MSG_NOSIGNAL);
    160      1.1  christos 	if (result < 0) {
    161      1.1  christos 		error("openl2tp send: %m");
    162      1.1  christos 	}
    163      1.1  christos 	if (result != (sizeof(*msg) + msg->msg_len)) {
    164      1.1  christos 		warn("openl2tp send: unexpected byte count %d, expected %d",
    165      1.1  christos 		     result, sizeof(msg) + msg->msg_len);
    166      1.1  christos 	}
    167      1.1  christos 	dbglog("openl2tp send: sent PPP_ACCM_IND, %d bytes", result);
    168      1.1  christos 
    169      1.1  christos out:
    170      1.1  christos 	if (old_pppol2tp_send_accm_hook != NULL) {
    171      1.1  christos 		(*old_pppol2tp_send_accm_hook)(tunnel_id, session_id,
    172      1.1  christos 					       send_accm, recv_accm);
    173      1.1  christos 	}
    174      1.1  christos 	return;
    175      1.1  christos }
    176      1.1  christos 
    177      1.1  christos static void openl2tp_ppp_updown_ind(int tunnel_id, int session_id, int up)
    178      1.1  christos {
    179      1.1  christos 	int result;
    180      1.1  christos 	uint8_t buf[OPENL2TP_MSG_MAX_LEN];
    181      1.1  christos 	struct openl2tp_event_msg *msg = (void *) &buf[0];
    182      1.1  christos 	struct openl2tp_event_tlv *tlv;
    183      1.1  christos 	uint16_t tid = tunnel_id;
    184      1.1  christos 	uint16_t sid = session_id;
    185      1.1  christos 	uint8_t state = up;
    186  1.1.1.3  christos 	int unit = 0;
    187  1.1.1.3  christos 	char ifname[MAXNAMELEN];
    188  1.1.1.3  christos 	char user_name[MAXNAMELEN];
    189  1.1.1.3  christos 
    190  1.1.1.3  christos 	unit = ppp_ifunit();
    191  1.1.1.3  christos 	ppp_get_ifname(ifname, sizeof(ifname));
    192      1.1  christos 
    193      1.1  christos 	if (openl2tp_fd < 0) {
    194      1.1  christos 		result = openl2tp_client_create();
    195      1.1  christos 		if (result < 0) {
    196      1.1  christos 			goto out;
    197      1.1  christos 		}
    198      1.1  christos 	}
    199      1.1  christos 
    200  1.1.1.3  christos 	if (!ppp_peer_authname(user_name, sizeof(user_name)))
    201  1.1.1.3  christos 		user_name[0] = '\0';
    202      1.1  christos 
    203      1.1  christos 	msg->msg_signature = OPENL2TP_MSG_SIGNATURE;
    204      1.1  christos 	msg->msg_type = OPENL2TP_MSG_TYPE_PPP_UPDOWN_IND;
    205      1.1  christos 	msg->msg_len = 0;
    206      1.1  christos 
    207      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    208      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_TUNNEL_ID;
    209      1.1  christos 	tlv->tlv_len = sizeof(tid);
    210      1.1  christos 	memcpy(&tlv->tlv_value[0], &tid, tlv->tlv_len);
    211      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    212      1.1  christos 
    213      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    214      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_SESSION_ID;
    215      1.1  christos 	tlv->tlv_len = sizeof(sid);
    216      1.1  christos 	memcpy(&tlv->tlv_value[0], &sid, tlv->tlv_len);
    217      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    218      1.1  christos 
    219      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    220      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_STATE;
    221      1.1  christos 	tlv->tlv_len = sizeof(state);
    222      1.1  christos 	memcpy(&tlv->tlv_value[0], &state, tlv->tlv_len);
    223      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    224      1.1  christos 
    225      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    226      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_UNIT;
    227      1.1  christos 	tlv->tlv_len = sizeof(unit);
    228      1.1  christos 	memcpy(&tlv->tlv_value[0], &unit, tlv->tlv_len);
    229      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    230      1.1  christos 
    231      1.1  christos 	tlv = (void *) &msg->msg_data[msg->msg_len];
    232      1.1  christos 	tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_IFNAME;
    233      1.1  christos 	tlv->tlv_len = strlen(ifname) + 1;
    234      1.1  christos 	memcpy(&tlv->tlv_value[0], ifname, tlv->tlv_len);
    235      1.1  christos 	msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    236      1.1  christos 
    237  1.1.1.3  christos 	if (user_name[0] != '\0') {
    238      1.1  christos 		tlv = (void *) &msg->msg_data[msg->msg_len];
    239      1.1  christos 		tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_USER_NAME;
    240      1.1  christos 		tlv->tlv_len = strlen(user_name) + 1;
    241      1.1  christos 		memcpy(&tlv->tlv_value[0], user_name, tlv->tlv_len);
    242      1.1  christos 		msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
    243      1.1  christos 	}
    244      1.1  christos 
    245      1.1  christos 	result = send(openl2tp_fd, msg, sizeof(*msg) + msg->msg_len,
    246      1.1  christos 		      MSG_NOSIGNAL);
    247      1.1  christos 	if (result < 0) {
    248      1.1  christos 		error("openl2tp send: %m");
    249      1.1  christos 	}
    250      1.1  christos 	if (result != (sizeof(*msg) + msg->msg_len)) {
    251      1.1  christos 		warn("openl2tp send: unexpected byte count %d, expected %d",
    252      1.1  christos 		     result, sizeof(msg) + msg->msg_len);
    253      1.1  christos 	}
    254      1.1  christos 	dbglog("openl2tp send: sent PPP_UPDOWN_IND, %d bytes", result);
    255      1.1  christos 
    256      1.1  christos out:
    257      1.1  christos 	if (old_pppol2tp_ip_updown_hook != NULL) {
    258      1.1  christos 		(*old_pppol2tp_ip_updown_hook)(tunnel_id, session_id, up);
    259      1.1  christos 	}
    260      1.1  christos 
    261      1.1  christos 	return;
    262      1.1  christos }
    263      1.1  christos 
    264      1.1  christos /*****************************************************************************
    265      1.1  christos  * When a multilink interface is created, there are 2 cases to consider.
    266      1.1  christos  *
    267      1.1  christos  * 1. The new interface is the first of a multilink bundle (master).
    268      1.1  christos  * 2. The new interface is being attached to an existing bundle.
    269      1.1  christos  *
    270      1.1  christos  * The first case is handled by existing code because the interface
    271      1.1  christos  * generates ip-up events just like standard interfaces. But in the
    272      1.1  christos  * second case, where the interface is added to an existing ppp
    273      1.1  christos  * bundle, pppd does not do IP negotiation and so as a result, no
    274      1.1  christos  * ip-up event is generated when the interface is created. Since
    275      1.1  christos  * openl2tpd needs the SESSION_PPP_UPDOWN_IND for all interfaces of a
    276      1.1  christos  * PPP bundle, we must fake the event.
    277      1.1  christos  *
    278      1.1  christos  * We use the ip_multilink_join_hook to hear when an interface joins a
    279      1.1  christos  * multilink bundle.
    280      1.1  christos  *****************************************************************************/
    281      1.1  christos 
    282  1.1.1.3  christos #ifdef PPP_WITH_MULTILINK
    283      1.1  christos static void openl2tp_multilink_join_ind(void)
    284      1.1  christos {
    285  1.1.1.3  christos 	if (mp_on() && !mp_master()) {
    286      1.1  christos 		/* send event only if not master */
    287      1.1  christos 		openl2tp_ppp_updown_ind(pppol2tp_tunnel_id,
    288      1.1  christos 					pppol2tp_session_id, 1);
    289      1.1  christos 	}
    290      1.1  christos }
    291  1.1.1.3  christos #endif
    292      1.1  christos 
    293      1.1  christos /*****************************************************************************
    294      1.1  christos  * Application init
    295      1.1  christos  *****************************************************************************/
    296      1.1  christos 
    297      1.1  christos void plugin_init(void)
    298      1.1  christos {
    299      1.1  christos 	old_pppol2tp_send_accm_hook = pppol2tp_send_accm_hook;
    300      1.1  christos 	pppol2tp_send_accm_hook = openl2tp_send_accm_ind;
    301      1.1  christos 
    302      1.1  christos 	old_pppol2tp_ip_updown_hook = pppol2tp_ip_updown_hook;
    303      1.1  christos 	pppol2tp_ip_updown_hook = openl2tp_ppp_updown_ind;
    304      1.1  christos 
    305  1.1.1.3  christos #ifdef PPP_WITH_MULTILINK
    306      1.1  christos 	old_multilink_join_hook = multilink_join_hook;
    307      1.1  christos 	multilink_join_hook = openl2tp_multilink_join_ind;
    308  1.1.1.3  christos #endif
    309      1.1  christos }
    310      1.1  christos 
    311