diff --git a/net/l2tpv3tun/Makefile b/net/l2tpv3tun/Makefile new file mode 100644 index 0000000000..f72d8d4811 --- /dev/null +++ b/net/l2tpv3tun/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (C) 2009-2010 Thomas Heil +# Copyright (C) 2010-2011 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=l2tpv3tun +PKG_VERSION:=0.2 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=ftp://www.openl2tp.org/releases +PKG_MD5SUM:=d3b4a9af652cca9f34d3eea4a7ff6041 + +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/kernel.mk +include $(INCLUDE_DIR)/package.mk + +define Package/l2tpv3tun + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libnl-tiny +ip +kmod-l2tp +kmod-l2tp-ip +kmod-l2tp-eth + TITLE:=Control utility for static L2TP v3 (Pseudowire) tunnels + MAINTAINER:=Thomas Heil + URL:=http://www.openl2tp.org +endef + +define Package/l2tpv3tun/description + The l2tpv3tun utility is a command line frontend for configuring static + L2TP v3 pseudowire tunnels. +endef + +MAKE_FLAGS += \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS) -I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/usr/include/libnl-tiny/" \ + LD="$(TARGET_CC)" \ + LDFLAGS="$(TARGET_LDFLAGS) -L$(STAGING_DIR)/usr/lib/ -lnl-tiny" + +define Package/l2tpv3tun/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/l2tpv3tun $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/lib/network + $(INSTALL_BIN) ./files/l2tp.sh $(1)/lib/network/ +endef + +$(eval $(call BuildPackage,l2tpv3tun)) diff --git a/net/l2tpv3tun/files/l2tp.sh b/net/l2tpv3tun/files/l2tp.sh new file mode 100644 index 0000000000..a3eeb1d331 --- /dev/null +++ b/net/l2tpv3tun/files/l2tp.sh @@ -0,0 +1,213 @@ +# l2tp.sh - L2TPv3 tunnel backend +# Copyright (c) 2010 OpenWrt.org + +l2tp_next_tunnel_id() { + local max=0 + local val + for val in $( + local l + l2tpv3tun show tunnel | while read l; do + case "$l" in + Tunnel*,*encap*) l="${l#Tunnel }"; echo "${l%%,*}";; + esac + done + ); do + [ "$val" -gt "$max" ] && max="$val" + done + echo $((max + 1)) +} + +l2tp_next_session_id() { + local tunnel="$1" + local max=0 + local val + for val in $( + local l + l2tpv3tun show session${tunnel:+ tunnel_id "$tunnel"} | while read l; do + case "$l" in + Session*in*) l="${l#Session }"; echo "${l%% *}";; + esac + done + ); do + [ "$val" -gt "$max" ] && max="$val" + done + echo $((max + 1)) +} + +l2tp_tunnel_exists() { + test -n "$(l2tpv3tun show tunnel tunnel_id "$1" 2>/dev/null)" +} + +l2tp_session_exists() { + test -n "$(l2tpv3tun show session tunnel_id "$1" session_id "$2" 2>/dev/null)" +} + +l2tp_ifname() { + l2tpv3tun show session tunnel_id "$1" session_id "$2" 2>/dev/null | \ + sed -ne 's/^.*interface name: //p' +} + +l2tp_lock() { + lock /var/lock/l2tp-setup +} + +l2tp_unlock() { + lock -u /var/lock/l2tp-setup +} + +l2tp_log() { + logger -t "ifup-l2tp" "$@" +} + + +# Hook into scan_interfaces() to synthesize a .device option +# This is needed for /sbin/ifup to properly dispatch control +# to setup_interface_l2tp() even if no .ifname is set in +# the configuration. +scan_l2tp() { + local dev + config_get dev "$1" device + config_set "$1" device "${dev:+$dev }l2tp-$1" +} + +coldplug_interface_l2tp() { + setup_interface_l2tp "l2tp-$1" "$1" +} + +setup_interface_l2tp() { + local iface="$1" + local cfg="$2" + local link="l2tp-$cfg" + + l2tp_lock + + # prevent recursion + local up="$(uci_get_state network "$cfg" up 0)" + [ "$up" = 0 ] || { + l2tp_unlock + return 0 + } + + local tunnel_id + config_get tunnel_id "$cfg" tunnel_id + [ -n "$tunnel_id" ] || { + tunnel_id="$(l2tp_next_tunnel_id)" + uci_set_state network "$cfg" tunnel_id "$tunnel_id" + l2tp_log "No tunnel ID specified, assuming $tunnel_id" + } + + local peer_tunnel_id + config_get peer_tunnel_id "$cfg" peer_tunnel_id + [ -n "$peer_tunnel_id" ] || { + peer_tunnel_id="$tunnel_id" + uci_set_state network "$cfg" peer_tunnel_id "$peer_tunnel_id" + l2tp_log "No peer tunnel ID specified, assuming $peer_tunnel_id" + } + + local encap + config_get encap "$cfg" encap udp + + local sport dport + [ "$encap" = udp ] && { + config_get sport "$cfg" sport 1701 + config_get dport "$cfg" dport 1701 + } + + local peeraddr + config_get peeraddr "$cfg" peeraddr + [ -z "$peeraddr" ] && config_get peeraddr "$cfg" peer6addr + + local localaddr + case "$peeraddr" in + *:*) config_get localaddr "$cfg" local6addr ;; + *) config_get localaddr "$cfg" localaddr ;; + esac + + [ -n "$localaddr" -a -n "$peeraddr" ] || { + l2tp_log "Missing local or peer address for tunnel $cfg - skipping" + return 1 + } + + ( + while ! l2tp_tunnel_exists "$tunnel_id"; do + [ -n "$sport" ] && l2tpv3tun show tunnel 2>/dev/null | grep -q "ports: $sport/" && { + l2tp_log "There already is a tunnel with src port $sport - skipping" + l2tp_unlock + return 1 + } + + l2tpv3tun add tunnel tunnel_id "$tunnel_id" peer_tunnel_id "$peer_tunnel_id" \ + encap "$encap" local "$localaddr" remote "$peeraddr" \ + ${sport:+udp_sport "$sport"} ${dport:+udp_dport "$dport"} + + # Wait for tunnel + sleep 1 + done + + + local session_id + config_get session_id "$cfg" session_id + [ -n "$session_id" ] || { + session_id="$(l2tp_next_session_id "$tunnel_id")" + uci_set_state network "$cfg" session_id "$session_id" + l2tp_log "No session ID specified, assuming $session_id" + } + + local peer_session_id + config_get peer_session_id "$cfg" peer_session_id + [ -n "$peer_session_id" ] || { + peer_session_id="$session_id" + uci_set_state network "$cfg" peer_session_id "$peer_session_id" + l2tp_log "No peer session ID specified, assuming $peer_session_id" + } + + + while ! l2tp_session_exists "$tunnel_id" "$session_id"; do + l2tpv3tun add session ifname "$link" tunnel_id "$tunnel_id" \ + session_id "$session_id" peer_session_id "$peer_session_id" + + # Wait for session + sleep 1 + done + + + local dev + config_get dev "$cfg" device + + local ifn + config_get ifn "$cfg" ifname + + uci_set_state network "$cfg" ifname "${ifn:-$dev}" + uci_set_state network "$cfg" device "$dev" + + local mtu + config_get mtu "$cfg" mtu 1462 + + local ttl + config_get ttl "$cfg" ttl + + ip link set mtu "$mtu" ${ttl:+ ttl "$ttl"} dev "$link" + + # IP setup inherited from proto static + prepare_interface "$link" "$cfg" + setup_interface_static "${ifn:-$dev}" "$cfg" + + ip link set up dev "$link" + + uci_set_state network "$cfg" up 1 + l2tp_unlock + ) & +} + +stop_interface_l2tp() { + local cfg="$1" + local link="l2tp-$cfg" + + local tunnel=$(uci_get_state network "$cfg" tunnel_id) + local session=$(uci_get_state network "$cfg" session_id) + + [ -n "$tunnel" ] && [ -n "$session" ] && { + l2tpv3tun del session tunnel_id "$tunnel" session_id "$session" + l2tpv3tun del tunnel tunnel_id "$tunnel" + } +} diff --git a/net/l2tpv3tun/patches/010-custom_ifname.patch b/net/l2tpv3tun/patches/010-custom_ifname.patch new file mode 100644 index 0000000000..14a085f7a2 --- /dev/null +++ b/net/l2tpv3tun/patches/010-custom_ifname.patch @@ -0,0 +1,20 @@ +--- a/main.c ++++ b/main.c +@@ -560,6 +560,7 @@ static void usage(void) + fprintf(stderr, " session_id ID peer_session_id ID\n"); + fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"); + fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n"); ++ fprintf(stderr, " [ ifname IFNAME ]\n"); + fprintf(stderr, " %s del tunnel tunnel_id ID\n", L2TP_CMD_ROOT); + fprintf(stderr, " %s del session tunnel_id ID session_id ID\n", L2TP_CMD_ROOT); + fprintf(stderr, " %s show tunnel [ tunnel_id ID ]\n", L2TP_CMD_ROOT); +@@ -671,6 +672,9 @@ static int parse_args(int argc, char **a + p->peer_cookie_len = slen / 2; + if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0) + invarg("cookie must be a hex string\n", *argv); ++ } else if (strcmp(*argv, "ifname") == 0) { ++ NEXT_ARG(); ++ p->ifname = *argv; + } else if (strcmp(*argv, "tunnel") == 0) { + p->tunnel = 1; + } else if (strcmp(*argv, "session") == 0) { diff --git a/net/l2tpv3tun/patches/100-nl_handle_alloc.patch b/net/l2tpv3tun/patches/100-nl_handle_alloc.patch new file mode 100644 index 0000000000..f245468b0e --- /dev/null +++ b/net/l2tpv3tun/patches/100-nl_handle_alloc.patch @@ -0,0 +1,23 @@ +--- a/main.c ++++ b/main.c +@@ -100,7 +100,7 @@ struct l2tp_data { + }; + + /* netlink socket */ +-static struct nl_handle *nl_sock; ++static struct nl_sock *nl_sock; + static int nl_family; + + /***************************************************************************** +@@ -788,9 +788,9 @@ static int do_show(int argc, char **argv + + int do_ipl2tp(int argc, char **argv) + { +- nl_sock = nl_handle_alloc(); ++ nl_sock = nl_socket_alloc(); + if (!nl_sock) { +- perror("nl_handle_alloc"); ++ perror("nl_socket_alloc"); + return 1; + } +