Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 193948
b: refs/heads/master
c: 789a4a2
h: refs/heads/master
v: v3
  • Loading branch information
James Chapman authored and David S. Miller committed Apr 3, 2010
1 parent 5c8695a commit 1fc3c95
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0ad6614048cf722e4d27909665b4846805357f1b
refs/heads/master: 789a4a2c61d843df67988d69e7c3f3a4bca97e8e
115 changes: 105 additions & 10 deletions trunk/net/l2tp/l2tp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,82 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
}
EXPORT_SYMBOL_GPL(l2tp_tunnel_free);

/* Create a socket for the tunnel, if one isn't set up by
* userspace. This is used for static tunnels where there is no
* managing L2TP daemon.
*/
static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp)
{
int err = -EINVAL;
struct sockaddr_in udp_addr;
struct sockaddr_l2tpip ip_addr;
struct socket *sock;

switch (cfg->encap) {
case L2TP_ENCAPTYPE_UDP:
err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
if (err < 0)
goto out;

sock = *sockp;

memset(&udp_addr, 0, sizeof(udp_addr));
udp_addr.sin_family = AF_INET;
udp_addr.sin_addr = cfg->local_ip;
udp_addr.sin_port = htons(cfg->local_udp_port);
err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
if (err < 0)
goto out;

udp_addr.sin_family = AF_INET;
udp_addr.sin_addr = cfg->peer_ip;
udp_addr.sin_port = htons(cfg->peer_udp_port);
err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
if (err < 0)
goto out;

if (!cfg->use_udp_checksums)
sock->sk->sk_no_check = UDP_CSUM_NOXMIT;

break;

case L2TP_ENCAPTYPE_IP:
err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
if (err < 0)
goto out;

sock = *sockp;

memset(&ip_addr, 0, sizeof(ip_addr));
ip_addr.l2tp_family = AF_INET;
ip_addr.l2tp_addr = cfg->local_ip;
ip_addr.l2tp_conn_id = tunnel_id;
err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
if (err < 0)
goto out;

ip_addr.l2tp_family = AF_INET;
ip_addr.l2tp_addr = cfg->peer_ip;
ip_addr.l2tp_conn_id = peer_tunnel_id;
err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
if (err < 0)
goto out;

break;

default:
goto out;
}

out:
if ((err < 0) && sock) {
sock_release(sock);
*sockp = NULL;
}

return err;
}

int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
{
struct l2tp_tunnel *tunnel = NULL;
Expand All @@ -1228,14 +1304,21 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;

/* Get the tunnel socket from the fd, which was opened by
* the userspace L2TP daemon.
* the userspace L2TP daemon. If not specified, create a
* kernel socket.
*/
err = -EBADF;
sock = sockfd_lookup(fd, &err);
if (!sock) {
printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
tunnel_id, fd, err);
goto err;
if (fd < 0) {
err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock);
if (err < 0)
goto err;
} else {
err = -EBADF;
sock = sockfd_lookup(fd, &err);
if (!sock) {
printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
tunnel_id, fd, err);
goto err;
}
}

sk = sock->sk;
Expand Down Expand Up @@ -1329,7 +1412,10 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
if (tunnelp)
*tunnelp = tunnel;

if (sock)
/* If tunnel's socket was created by the kernel, it doesn't
* have a file.
*/
if (sock && sock->file)
sockfd_put(sock);

return err;
Expand All @@ -1341,13 +1427,22 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
{
int err = 0;
struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;

/* Force the tunnel socket to close. This will eventually
* cause the tunnel to be deleted via the normal socket close
* mechanisms when userspace closes the tunnel socket.
*/
if ((tunnel->sock != NULL) && (tunnel->sock->sk_socket != NULL))
err = inet_shutdown(tunnel->sock->sk_socket, 2);
if (sock != NULL) {
err = inet_shutdown(sock, 2);

/* If the tunnel's socket was created by the kernel,
* close the socket here since the socket was not
* created by userspace.
*/
if (sock->file == NULL)
err = inet_release(sock);
}

return err;
}
Expand Down
7 changes: 7 additions & 0 deletions trunk/net/l2tp/l2tp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ struct l2tp_tunnel_cfg {
int debug; /* bitmask of debug message
* categories */
enum l2tp_encap_type encap;

/* Used only for kernel-created sockets */
struct in_addr local_ip;
struct in_addr peer_ip;
u16 local_udp_port;
u16 peer_udp_port;
int use_udp_checksums:1;
};

struct l2tp_tunnel {
Expand Down
18 changes: 14 additions & 4 deletions trunk/net/l2tp/l2tp_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,21 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
}
cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);

if (!info->attrs[L2TP_ATTR_FD]) {
ret = -EINVAL;
goto out;
fd = -1;
if (info->attrs[L2TP_ATTR_FD]) {
fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
} else {
if (info->attrs[L2TP_ATTR_IP_SADDR])
cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
if (info->attrs[L2TP_ATTR_IP_DADDR])
cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
if (info->attrs[L2TP_ATTR_UDP_SPORT])
cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
if (info->attrs[L2TP_ATTR_UDP_DPORT])
cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
if (info->attrs[L2TP_ATTR_UDP_CSUM])
cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
}
fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);

if (info->attrs[L2TP_ATTR_DEBUG])
cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
Expand Down

0 comments on commit 1fc3c95

Please sign in to comment.