aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/l2tp/l2tp_core.c115
-rw-r--r--net/l2tp/l2tp_core.h7
-rw-r--r--net/l2tp/l2tp_netlink.c18
3 files changed, 126 insertions, 14 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 473cf2d63905..13ed85baf4e9 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1218,6 +1218,82 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
1218} 1218}
1219EXPORT_SYMBOL_GPL(l2tp_tunnel_free); 1219EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
1220 1220
1221/* Create a socket for the tunnel, if one isn't set up by
1222 * userspace. This is used for static tunnels where there is no
1223 * managing L2TP daemon.
1224 */
1225static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp)
1226{
1227 int err = -EINVAL;
1228 struct sockaddr_in udp_addr;
1229 struct sockaddr_l2tpip ip_addr;
1230 struct socket *sock;
1231
1232 switch (cfg->encap) {
1233 case L2TP_ENCAPTYPE_UDP:
1234 err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
1235 if (err < 0)
1236 goto out;
1237
1238 sock = *sockp;
1239
1240 memset(&udp_addr, 0, sizeof(udp_addr));
1241 udp_addr.sin_family = AF_INET;
1242 udp_addr.sin_addr = cfg->local_ip;
1243 udp_addr.sin_port = htons(cfg->local_udp_port);
1244 err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
1245 if (err < 0)
1246 goto out;
1247
1248 udp_addr.sin_family = AF_INET;
1249 udp_addr.sin_addr = cfg->peer_ip;
1250 udp_addr.sin_port = htons(cfg->peer_udp_port);
1251 err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
1252 if (err < 0)
1253 goto out;
1254
1255 if (!cfg->use_udp_checksums)
1256 sock->sk->sk_no_check = UDP_CSUM_NOXMIT;
1257
1258 break;
1259
1260 case L2TP_ENCAPTYPE_IP:
1261 err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
1262 if (err < 0)
1263 goto out;
1264
1265 sock = *sockp;
1266
1267 memset(&ip_addr, 0, sizeof(ip_addr));
1268 ip_addr.l2tp_family = AF_INET;
1269 ip_addr.l2tp_addr = cfg->local_ip;
1270 ip_addr.l2tp_conn_id = tunnel_id;
1271 err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
1272 if (err < 0)
1273 goto out;
1274
1275 ip_addr.l2tp_family = AF_INET;
1276 ip_addr.l2tp_addr = cfg->peer_ip;
1277 ip_addr.l2tp_conn_id = peer_tunnel_id;
1278 err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
1279 if (err < 0)
1280 goto out;
1281
1282 break;
1283
1284 default:
1285 goto out;
1286 }
1287
1288out:
1289 if ((err < 0) && sock) {
1290 sock_release(sock);
1291 *sockp = NULL;
1292 }
1293
1294 return err;
1295}
1296
1221int 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) 1297int 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)
1222{ 1298{
1223 struct l2tp_tunnel *tunnel = NULL; 1299 struct l2tp_tunnel *tunnel = NULL;
@@ -1228,14 +1304,21 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
1228 enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; 1304 enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
1229 1305
1230 /* Get the tunnel socket from the fd, which was opened by 1306 /* Get the tunnel socket from the fd, which was opened by
1231 * the userspace L2TP daemon. 1307 * the userspace L2TP daemon. If not specified, create a
1308 * kernel socket.
1232 */ 1309 */
1233 err = -EBADF; 1310 if (fd < 0) {
1234 sock = sockfd_lookup(fd, &err); 1311 err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock);
1235 if (!sock) { 1312 if (err < 0)
1236 printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n", 1313 goto err;
1237 tunnel_id, fd, err); 1314 } else {
1238 goto err; 1315 err = -EBADF;
1316 sock = sockfd_lookup(fd, &err);
1317 if (!sock) {
1318 printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
1319 tunnel_id, fd, err);
1320 goto err;
1321 }
1239 } 1322 }
1240 1323
1241 sk = sock->sk; 1324 sk = sock->sk;
@@ -1329,7 +1412,10 @@ err:
1329 if (tunnelp) 1412 if (tunnelp)
1330 *tunnelp = tunnel; 1413 *tunnelp = tunnel;
1331 1414
1332 if (sock) 1415 /* If tunnel's socket was created by the kernel, it doesn't
1416 * have a file.
1417 */
1418 if (sock && sock->file)
1333 sockfd_put(sock); 1419 sockfd_put(sock);
1334 1420
1335 return err; 1421 return err;
@@ -1341,13 +1427,22 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
1341int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) 1427int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
1342{ 1428{
1343 int err = 0; 1429 int err = 0;
1430 struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;
1344 1431
1345 /* Force the tunnel socket to close. This will eventually 1432 /* Force the tunnel socket to close. This will eventually
1346 * cause the tunnel to be deleted via the normal socket close 1433 * cause the tunnel to be deleted via the normal socket close
1347 * mechanisms when userspace closes the tunnel socket. 1434 * mechanisms when userspace closes the tunnel socket.
1348 */ 1435 */
1349 if ((tunnel->sock != NULL) && (tunnel->sock->sk_socket != NULL)) 1436 if (sock != NULL) {
1350 err = inet_shutdown(tunnel->sock->sk_socket, 2); 1437 err = inet_shutdown(sock, 2);
1438
1439 /* If the tunnel's socket was created by the kernel,
1440 * close the socket here since the socket was not
1441 * created by userspace.
1442 */
1443 if (sock->file == NULL)
1444 err = inet_release(sock);
1445 }
1351 1446
1352 return err; 1447 return err;
1353} 1448}
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 571335530c6f..a961c77e0867 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -146,6 +146,13 @@ struct l2tp_tunnel_cfg {
146 int debug; /* bitmask of debug message 146 int debug; /* bitmask of debug message
147 * categories */ 147 * categories */
148 enum l2tp_encap_type encap; 148 enum l2tp_encap_type encap;
149
150 /* Used only for kernel-created sockets */
151 struct in_addr local_ip;
152 struct in_addr peer_ip;
153 u16 local_udp_port;
154 u16 peer_udp_port;
155 int use_udp_checksums:1;
149}; 156};
150 157
151struct l2tp_tunnel { 158struct l2tp_tunnel {
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 3d0f7f6f7488..12341a6cc70e 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -129,11 +129,21 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
129 } 129 }
130 cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]); 130 cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
131 131
132 if (!info->attrs[L2TP_ATTR_FD]) { 132 fd = -1;
133 ret = -EINVAL; 133 if (info->attrs[L2TP_ATTR_FD]) {
134 goto out; 134 fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
135 } else {
136 if (info->attrs[L2TP_ATTR_IP_SADDR])
137 cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
138 if (info->attrs[L2TP_ATTR_IP_DADDR])
139 cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
140 if (info->attrs[L2TP_ATTR_UDP_SPORT])
141 cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
142 if (info->attrs[L2TP_ATTR_UDP_DPORT])
143 cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
144 if (info->attrs[L2TP_ATTR_UDP_CSUM])
145 cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
135 } 146 }
136 fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
137 147
138 if (info->attrs[L2TP_ATTR_DEBUG]) 148 if (info->attrs[L2TP_ATTR_DEBUG])
139 cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]); 149 cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);