diff options
Diffstat (limited to 'net/l2tp')
-rw-r--r-- | net/l2tp/l2tp_core.c | 115 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 7 | ||||
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 18 |
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 | } |
1219 | EXPORT_SYMBOL_GPL(l2tp_tunnel_free); | 1219 | EXPORT_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 | */ | ||
1225 | static 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 | |||
1288 | out: | ||
1289 | if ((err < 0) && sock) { | ||
1290 | sock_release(sock); | ||
1291 | *sockp = NULL; | ||
1292 | } | ||
1293 | |||
1294 | return err; | ||
1295 | } | ||
1296 | |||
1221 | 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) | 1297 | 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) |
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); | |||
1341 | int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) | 1427 | int 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 | ||
151 | struct l2tp_tunnel { | 158 | struct 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]); |