diff options
-rw-r--r-- | include/linux/l2tp.h | 125 | ||||
-rw-r--r-- | net/l2tp/Makefile | 1 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.c | 61 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 34 | ||||
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 830 | ||||
-rw-r--r-- | net/l2tp/l2tp_ppp.c | 162 |
6 files changed, 1169 insertions, 44 deletions
diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h index deff7bca4e05..4bdb31df8e72 100644 --- a/include/linux/l2tp.h +++ b/include/linux/l2tp.h | |||
@@ -11,6 +11,8 @@ | |||
11 | #ifdef __KERNEL__ | 11 | #ifdef __KERNEL__ |
12 | #include <linux/socket.h> | 12 | #include <linux/socket.h> |
13 | #include <linux/in.h> | 13 | #include <linux/in.h> |
14 | #else | ||
15 | #include <netinet/in.h> | ||
14 | #endif | 16 | #endif |
15 | 17 | ||
16 | #define IPPROTO_L2TP 115 | 18 | #define IPPROTO_L2TP 115 |
@@ -21,6 +23,7 @@ | |||
21 | * @l2tp_addr: protocol specific address information | 23 | * @l2tp_addr: protocol specific address information |
22 | * @l2tp_conn_id: connection id of tunnel | 24 | * @l2tp_conn_id: connection id of tunnel |
23 | */ | 25 | */ |
26 | #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ | ||
24 | struct sockaddr_l2tpip { | 27 | struct sockaddr_l2tpip { |
25 | /* The first fields must match struct sockaddr_in */ | 28 | /* The first fields must match struct sockaddr_in */ |
26 | sa_family_t l2tp_family; /* AF_INET */ | 29 | sa_family_t l2tp_family; /* AF_INET */ |
@@ -35,4 +38,126 @@ struct sockaddr_l2tpip { | |||
35 | sizeof(__u32)]; | 38 | sizeof(__u32)]; |
36 | }; | 39 | }; |
37 | 40 | ||
41 | /***************************************************************************** | ||
42 | * NETLINK_GENERIC netlink family. | ||
43 | *****************************************************************************/ | ||
44 | |||
45 | /* | ||
46 | * Commands. | ||
47 | * Valid TLVs of each command are:- | ||
48 | * TUNNEL_CREATE - CONN_ID, pw_type, netns, ifname, ipinfo, udpinfo, udpcsum, vlanid | ||
49 | * TUNNEL_DELETE - CONN_ID | ||
50 | * TUNNEL_MODIFY - CONN_ID, udpcsum | ||
51 | * TUNNEL_GETSTATS - CONN_ID, (stats) | ||
52 | * TUNNEL_GET - CONN_ID, (...) | ||
53 | * SESSION_CREATE - SESSION_ID, PW_TYPE, offset, data_seq, cookie, peer_cookie, offset, l2spec | ||
54 | * SESSION_DELETE - SESSION_ID | ||
55 | * SESSION_MODIFY - SESSION_ID, data_seq | ||
56 | * SESSION_GET - SESSION_ID, (...) | ||
57 | * SESSION_GETSTATS - SESSION_ID, (stats) | ||
58 | * | ||
59 | */ | ||
60 | enum { | ||
61 | L2TP_CMD_NOOP, | ||
62 | L2TP_CMD_TUNNEL_CREATE, | ||
63 | L2TP_CMD_TUNNEL_DELETE, | ||
64 | L2TP_CMD_TUNNEL_MODIFY, | ||
65 | L2TP_CMD_TUNNEL_GET, | ||
66 | L2TP_CMD_SESSION_CREATE, | ||
67 | L2TP_CMD_SESSION_DELETE, | ||
68 | L2TP_CMD_SESSION_MODIFY, | ||
69 | L2TP_CMD_SESSION_GET, | ||
70 | __L2TP_CMD_MAX, | ||
71 | }; | ||
72 | |||
73 | #define L2TP_CMD_MAX (__L2TP_CMD_MAX - 1) | ||
74 | |||
75 | /* | ||
76 | * ATTR types defined for L2TP | ||
77 | */ | ||
78 | enum { | ||
79 | L2TP_ATTR_NONE, /* no data */ | ||
80 | L2TP_ATTR_PW_TYPE, /* u16, enum l2tp_pwtype */ | ||
81 | L2TP_ATTR_ENCAP_TYPE, /* u16, enum l2tp_encap_type */ | ||
82 | L2TP_ATTR_OFFSET, /* u16 */ | ||
83 | L2TP_ATTR_DATA_SEQ, /* u16 */ | ||
84 | L2TP_ATTR_L2SPEC_TYPE, /* u8, enum l2tp_l2spec_type */ | ||
85 | L2TP_ATTR_L2SPEC_LEN, /* u8, enum l2tp_l2spec_type */ | ||
86 | L2TP_ATTR_PROTO_VERSION, /* u8 */ | ||
87 | L2TP_ATTR_IFNAME, /* string */ | ||
88 | L2TP_ATTR_CONN_ID, /* u32 */ | ||
89 | L2TP_ATTR_PEER_CONN_ID, /* u32 */ | ||
90 | L2TP_ATTR_SESSION_ID, /* u32 */ | ||
91 | L2TP_ATTR_PEER_SESSION_ID, /* u32 */ | ||
92 | L2TP_ATTR_UDP_CSUM, /* u8 */ | ||
93 | L2TP_ATTR_VLAN_ID, /* u16 */ | ||
94 | L2TP_ATTR_COOKIE, /* 0, 4 or 8 bytes */ | ||
95 | L2TP_ATTR_PEER_COOKIE, /* 0, 4 or 8 bytes */ | ||
96 | L2TP_ATTR_DEBUG, /* u32 */ | ||
97 | L2TP_ATTR_RECV_SEQ, /* u8 */ | ||
98 | L2TP_ATTR_SEND_SEQ, /* u8 */ | ||
99 | L2TP_ATTR_LNS_MODE, /* u8 */ | ||
100 | L2TP_ATTR_USING_IPSEC, /* u8 */ | ||
101 | L2TP_ATTR_RECV_TIMEOUT, /* msec */ | ||
102 | L2TP_ATTR_FD, /* int */ | ||
103 | L2TP_ATTR_IP_SADDR, /* u32 */ | ||
104 | L2TP_ATTR_IP_DADDR, /* u32 */ | ||
105 | L2TP_ATTR_UDP_SPORT, /* u16 */ | ||
106 | L2TP_ATTR_UDP_DPORT, /* u16 */ | ||
107 | L2TP_ATTR_MTU, /* u16 */ | ||
108 | L2TP_ATTR_MRU, /* u16 */ | ||
109 | L2TP_ATTR_STATS, /* nested */ | ||
110 | __L2TP_ATTR_MAX, | ||
111 | }; | ||
112 | |||
113 | #define L2TP_ATTR_MAX (__L2TP_ATTR_MAX - 1) | ||
114 | |||
115 | /* Nested in L2TP_ATTR_STATS */ | ||
116 | enum { | ||
117 | L2TP_ATTR_STATS_NONE, /* no data */ | ||
118 | L2TP_ATTR_TX_PACKETS, /* u64 */ | ||
119 | L2TP_ATTR_TX_BYTES, /* u64 */ | ||
120 | L2TP_ATTR_TX_ERRORS, /* u64 */ | ||
121 | L2TP_ATTR_RX_PACKETS, /* u64 */ | ||
122 | L2TP_ATTR_RX_BYTES, /* u64 */ | ||
123 | L2TP_ATTR_RX_SEQ_DISCARDS, /* u64 */ | ||
124 | L2TP_ATTR_RX_OOS_PACKETS, /* u64 */ | ||
125 | L2TP_ATTR_RX_ERRORS, /* u64 */ | ||
126 | __L2TP_ATTR_STATS_MAX, | ||
127 | }; | ||
128 | |||
129 | #define L2TP_ATTR_STATS_MAX (__L2TP_ATTR_STATS_MAX - 1) | ||
130 | |||
131 | enum l2tp_pwtype { | ||
132 | L2TP_PWTYPE_NONE = 0x0000, | ||
133 | L2TP_PWTYPE_ETH_VLAN = 0x0004, | ||
134 | L2TP_PWTYPE_ETH = 0x0005, | ||
135 | L2TP_PWTYPE_PPP = 0x0007, | ||
136 | L2TP_PWTYPE_PPP_AC = 0x0008, | ||
137 | L2TP_PWTYPE_IP = 0x000b, | ||
138 | __L2TP_PWTYPE_MAX | ||
139 | }; | ||
140 | |||
141 | enum l2tp_l2spec_type { | ||
142 | L2TP_L2SPECTYPE_NONE, | ||
143 | L2TP_L2SPECTYPE_DEFAULT, | ||
144 | }; | ||
145 | |||
146 | enum l2tp_encap_type { | ||
147 | L2TP_ENCAPTYPE_UDP, | ||
148 | L2TP_ENCAPTYPE_IP, | ||
149 | }; | ||
150 | |||
151 | enum l2tp_seqmode { | ||
152 | L2TP_SEQ_NONE = 0, | ||
153 | L2TP_SEQ_IP = 1, | ||
154 | L2TP_SEQ_ALL = 2, | ||
155 | }; | ||
156 | |||
157 | /* | ||
158 | * NETLINK_GENERIC related info | ||
159 | */ | ||
160 | #define L2TP_GENL_NAME "l2tp" | ||
161 | #define L2TP_GENL_VERSION 0x1 | ||
162 | |||
38 | #endif | 163 | #endif |
diff --git a/net/l2tp/Makefile b/net/l2tp/Makefile index ef28b16f7d6a..2c4a14b673ab 100644 --- a/net/l2tp/Makefile +++ b/net/l2tp/Makefile | |||
@@ -7,3 +7,4 @@ obj-$(CONFIG_L2TP) += l2tp_core.o | |||
7 | # Build l2tp as modules if L2TP is M | 7 | # Build l2tp as modules if L2TP is M |
8 | obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_PPPOL2TP)) += l2tp_ppp.o | 8 | obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_PPPOL2TP)) += l2tp_ppp.o |
9 | obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o | 9 | obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o |
10 | obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_V3)) += l2tp_netlink.o | ||
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 1739d04367e4..fbd1f2119fe9 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <net/dst.h> | 49 | #include <net/dst.h> |
50 | #include <net/ip.h> | 50 | #include <net/ip.h> |
51 | #include <net/udp.h> | 51 | #include <net/udp.h> |
52 | #include <net/inet_common.h> | ||
52 | #include <net/xfrm.h> | 53 | #include <net/xfrm.h> |
53 | #include <net/protocol.h> | 54 | #include <net/protocol.h> |
54 | 55 | ||
@@ -214,6 +215,32 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | |||
214 | } | 215 | } |
215 | EXPORT_SYMBOL_GPL(l2tp_session_find_nth); | 216 | EXPORT_SYMBOL_GPL(l2tp_session_find_nth); |
216 | 217 | ||
218 | /* Lookup a session by interface name. | ||
219 | * This is very inefficient but is only used by management interfaces. | ||
220 | */ | ||
221 | struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | ||
222 | { | ||
223 | struct l2tp_net *pn = l2tp_pernet(net); | ||
224 | int hash; | ||
225 | struct hlist_node *walk; | ||
226 | struct l2tp_session *session; | ||
227 | |||
228 | read_lock_bh(&pn->l2tp_session_hlist_lock); | ||
229 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { | ||
230 | hlist_for_each_entry(session, walk, &pn->l2tp_session_hlist[hash], global_hlist) { | ||
231 | if (!strcmp(session->ifname, ifname)) { | ||
232 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
233 | return session; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
239 | |||
240 | return NULL; | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname); | ||
243 | |||
217 | /* Lookup a tunnel by id | 244 | /* Lookup a tunnel by id |
218 | */ | 245 | */ |
219 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id) | 246 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id) |
@@ -758,7 +785,7 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |||
758 | 785 | ||
759 | /* Find the session context */ | 786 | /* Find the session context */ |
760 | session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); | 787 | session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); |
761 | if (!session) { | 788 | if (!session || !session->recv_skb) { |
762 | /* Not found? Pass to userspace to deal with */ | 789 | /* Not found? Pass to userspace to deal with */ |
763 | PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | 790 | PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, |
764 | "%s: no session found (%u/%u). Passing up.\n", | 791 | "%s: no session found (%u/%u). Passing up.\n", |
@@ -1305,6 +1332,23 @@ err: | |||
1305 | } | 1332 | } |
1306 | EXPORT_SYMBOL_GPL(l2tp_tunnel_create); | 1333 | EXPORT_SYMBOL_GPL(l2tp_tunnel_create); |
1307 | 1334 | ||
1335 | /* This function is used by the netlink TUNNEL_DELETE command. | ||
1336 | */ | ||
1337 | int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) | ||
1338 | { | ||
1339 | int err = 0; | ||
1340 | |||
1341 | /* Force the tunnel socket to close. This will eventually | ||
1342 | * cause the tunnel to be deleted via the normal socket close | ||
1343 | * mechanisms when userspace closes the tunnel socket. | ||
1344 | */ | ||
1345 | if ((tunnel->sock != NULL) && (tunnel->sock->sk_socket != NULL)) | ||
1346 | err = inet_shutdown(tunnel->sock->sk_socket, 2); | ||
1347 | |||
1348 | return err; | ||
1349 | } | ||
1350 | EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); | ||
1351 | |||
1308 | /* Really kill the session. | 1352 | /* Really kill the session. |
1309 | */ | 1353 | */ |
1310 | void l2tp_session_free(struct l2tp_session *session) | 1354 | void l2tp_session_free(struct l2tp_session *session) |
@@ -1349,6 +1393,21 @@ void l2tp_session_free(struct l2tp_session *session) | |||
1349 | } | 1393 | } |
1350 | EXPORT_SYMBOL_GPL(l2tp_session_free); | 1394 | EXPORT_SYMBOL_GPL(l2tp_session_free); |
1351 | 1395 | ||
1396 | /* This function is used by the netlink SESSION_DELETE command and by | ||
1397 | pseudowire modules. | ||
1398 | */ | ||
1399 | int l2tp_session_delete(struct l2tp_session *session) | ||
1400 | { | ||
1401 | if (session->session_close != NULL) | ||
1402 | (*session->session_close)(session); | ||
1403 | |||
1404 | l2tp_session_dec_refcount(session); | ||
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | EXPORT_SYMBOL_GPL(l2tp_session_delete); | ||
1409 | |||
1410 | |||
1352 | /* We come here whenever a session's send_seq, cookie_len or | 1411 | /* We come here whenever a session's send_seq, cookie_len or |
1353 | * l2specific_len parameters are set. | 1412 | * l2specific_len parameters are set. |
1354 | */ | 1413 | */ |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index d2395984645e..2974d9ade167 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -33,26 +33,6 @@ enum { | |||
33 | L2TP_MSG_DATA = (1 << 3), /* data packets */ | 33 | L2TP_MSG_DATA = (1 << 3), /* data packets */ |
34 | }; | 34 | }; |
35 | 35 | ||
36 | enum l2tp_pwtype { | ||
37 | L2TP_PWTYPE_NONE = 0x0000, | ||
38 | L2TP_PWTYPE_ETH_VLAN = 0x0004, | ||
39 | L2TP_PWTYPE_ETH = 0x0005, | ||
40 | L2TP_PWTYPE_PPP = 0x0007, | ||
41 | L2TP_PWTYPE_PPP_AC = 0x0008, | ||
42 | L2TP_PWTYPE_IP = 0x000b, | ||
43 | __L2TP_PWTYPE_MAX | ||
44 | }; | ||
45 | |||
46 | enum l2tp_l2spec_type { | ||
47 | L2TP_L2SPECTYPE_NONE, | ||
48 | L2TP_L2SPECTYPE_DEFAULT, | ||
49 | }; | ||
50 | |||
51 | enum l2tp_encap_type { | ||
52 | L2TP_ENCAPTYPE_UDP, | ||
53 | L2TP_ENCAPTYPE_IP, | ||
54 | }; | ||
55 | |||
56 | struct sk_buff; | 36 | struct sk_buff; |
57 | 37 | ||
58 | struct l2tp_stats { | 38 | struct l2tp_stats { |
@@ -87,6 +67,7 @@ struct l2tp_session_cfg { | |||
87 | * control of LNS. */ | 67 | * control of LNS. */ |
88 | int debug; /* bitmask of debug message | 68 | int debug; /* bitmask of debug message |
89 | * categories */ | 69 | * categories */ |
70 | u16 vlan_id; /* VLAN pseudowire only */ | ||
90 | u16 offset; /* offset to payload */ | 71 | u16 offset; /* offset to payload */ |
91 | u16 l2specific_len; /* Layer 2 specific length */ | 72 | u16 l2specific_len; /* Layer 2 specific length */ |
92 | u16 l2specific_type; /* Layer 2 specific type */ | 73 | u16 l2specific_type; /* Layer 2 specific type */ |
@@ -98,6 +79,7 @@ struct l2tp_session_cfg { | |||
98 | * (in jiffies) */ | 79 | * (in jiffies) */ |
99 | int mtu; | 80 | int mtu; |
100 | int mru; | 81 | int mru; |
82 | char *ifname; | ||
101 | }; | 83 | }; |
102 | 84 | ||
103 | struct l2tp_session { | 85 | struct l2tp_session { |
@@ -124,6 +106,7 @@ struct l2tp_session { | |||
124 | atomic_t ref_count; | 106 | atomic_t ref_count; |
125 | 107 | ||
126 | char name[32]; /* for logging */ | 108 | char name[32]; /* for logging */ |
109 | char ifname[IFNAMSIZ]; | ||
127 | unsigned data_seq:2; /* data sequencing level | 110 | unsigned data_seq:2; /* data sequencing level |
128 | * 0 => none, 1 => IP only, | 111 | * 0 => none, 1 => IP only, |
129 | * 2 => all | 112 | * 2 => all |
@@ -192,6 +175,11 @@ struct l2tp_tunnel { | |||
192 | uint8_t priv[0]; /* private data */ | 175 | uint8_t priv[0]; /* private data */ |
193 | }; | 176 | }; |
194 | 177 | ||
178 | struct l2tp_nl_cmd_ops { | ||
179 | int (*session_create)(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); | ||
180 | int (*session_delete)(struct l2tp_session *session); | ||
181 | }; | ||
182 | |||
195 | static inline void *l2tp_tunnel_priv(struct l2tp_tunnel *tunnel) | 183 | static inline void *l2tp_tunnel_priv(struct l2tp_tunnel *tunnel) |
196 | { | 184 | { |
197 | return &tunnel->priv[0]; | 185 | return &tunnel->priv[0]; |
@@ -224,11 +212,14 @@ out: | |||
224 | 212 | ||
225 | extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); | 213 | extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); |
226 | extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); | 214 | extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); |
215 | extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); | ||
227 | extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); | 216 | extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); |
228 | extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); | 217 | extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); |
229 | 218 | ||
230 | extern 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); | 219 | extern 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); |
220 | extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); | ||
231 | extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); | 221 | extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); |
222 | extern int l2tp_session_delete(struct l2tp_session *session); | ||
232 | extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); | 223 | extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); |
233 | extern void l2tp_session_free(struct l2tp_session *session); | 224 | extern void l2tp_session_free(struct l2tp_session *session); |
234 | extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); | 225 | extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); |
@@ -241,6 +232,9 @@ extern void l2tp_tunnel_destruct(struct sock *sk); | |||
241 | extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); | 232 | extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); |
242 | extern void l2tp_session_set_header_len(struct l2tp_session *session, int version); | 233 | extern void l2tp_session_set_header_len(struct l2tp_session *session, int version); |
243 | 234 | ||
235 | extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops); | ||
236 | extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); | ||
237 | |||
244 | /* Tunnel reference counts. Incremented per session that is added to | 238 | /* Tunnel reference counts. Incremented per session that is added to |
245 | * the tunnel. | 239 | * the tunnel. |
246 | */ | 240 | */ |
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c new file mode 100644 index 000000000000..3d0f7f6f7488 --- /dev/null +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -0,0 +1,830 @@ | |||
1 | /* | ||
2 | * L2TP netlink layer, for management | ||
3 | * | ||
4 | * Copyright (c) 2008,2009,2010 Katalix Systems Ltd | ||
5 | * | ||
6 | * Partly based on the IrDA nelink implementation | ||
7 | * (see net/irda/irnetlink.c) which is: | ||
8 | * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org> | ||
9 | * which is in turn partly based on the wireless netlink code: | ||
10 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <net/sock.h> | ||
18 | #include <net/genetlink.h> | ||
19 | #include <net/udp.h> | ||
20 | #include <linux/in.h> | ||
21 | #include <linux/udp.h> | ||
22 | #include <linux/socket.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <net/net_namespace.h> | ||
26 | |||
27 | #include <linux/l2tp.h> | ||
28 | |||
29 | #include "l2tp_core.h" | ||
30 | |||
31 | |||
32 | static struct genl_family l2tp_nl_family = { | ||
33 | .id = GENL_ID_GENERATE, | ||
34 | .name = L2TP_GENL_NAME, | ||
35 | .version = L2TP_GENL_VERSION, | ||
36 | .hdrsize = 0, | ||
37 | .maxattr = L2TP_ATTR_MAX, | ||
38 | }; | ||
39 | |||
40 | /* Accessed under genl lock */ | ||
41 | static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX]; | ||
42 | |||
43 | static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info) | ||
44 | { | ||
45 | u32 tunnel_id; | ||
46 | u32 session_id; | ||
47 | char *ifname; | ||
48 | struct l2tp_tunnel *tunnel; | ||
49 | struct l2tp_session *session = NULL; | ||
50 | struct net *net = genl_info_net(info); | ||
51 | |||
52 | if (info->attrs[L2TP_ATTR_IFNAME]) { | ||
53 | ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); | ||
54 | session = l2tp_session_find_by_ifname(net, ifname); | ||
55 | } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) && | ||
56 | (info->attrs[L2TP_ATTR_CONN_ID])) { | ||
57 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
58 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); | ||
59 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
60 | if (tunnel) | ||
61 | session = l2tp_session_find(net, tunnel, session_id); | ||
62 | } | ||
63 | |||
64 | return session; | ||
65 | } | ||
66 | |||
67 | static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) | ||
68 | { | ||
69 | struct sk_buff *msg; | ||
70 | void *hdr; | ||
71 | int ret = -ENOBUFS; | ||
72 | |||
73 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
74 | if (!msg) { | ||
75 | ret = -ENOMEM; | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | ||
80 | &l2tp_nl_family, 0, L2TP_CMD_NOOP); | ||
81 | if (IS_ERR(hdr)) { | ||
82 | ret = PTR_ERR(hdr); | ||
83 | goto err_out; | ||
84 | } | ||
85 | |||
86 | genlmsg_end(msg, hdr); | ||
87 | |||
88 | return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); | ||
89 | |||
90 | err_out: | ||
91 | nlmsg_free(msg); | ||
92 | |||
93 | out: | ||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info) | ||
98 | { | ||
99 | u32 tunnel_id; | ||
100 | u32 peer_tunnel_id; | ||
101 | int proto_version; | ||
102 | int fd; | ||
103 | int ret = 0; | ||
104 | struct l2tp_tunnel_cfg cfg = { 0, }; | ||
105 | struct l2tp_tunnel *tunnel; | ||
106 | struct net *net = genl_info_net(info); | ||
107 | |||
108 | if (!info->attrs[L2TP_ATTR_CONN_ID]) { | ||
109 | ret = -EINVAL; | ||
110 | goto out; | ||
111 | } | ||
112 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
113 | |||
114 | if (!info->attrs[L2TP_ATTR_PEER_CONN_ID]) { | ||
115 | ret = -EINVAL; | ||
116 | goto out; | ||
117 | } | ||
118 | peer_tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_CONN_ID]); | ||
119 | |||
120 | if (!info->attrs[L2TP_ATTR_PROTO_VERSION]) { | ||
121 | ret = -EINVAL; | ||
122 | goto out; | ||
123 | } | ||
124 | proto_version = nla_get_u8(info->attrs[L2TP_ATTR_PROTO_VERSION]); | ||
125 | |||
126 | if (!info->attrs[L2TP_ATTR_ENCAP_TYPE]) { | ||
127 | ret = -EINVAL; | ||
128 | goto out; | ||
129 | } | ||
130 | cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]); | ||
131 | |||
132 | if (!info->attrs[L2TP_ATTR_FD]) { | ||
133 | ret = -EINVAL; | ||
134 | goto out; | ||
135 | } | ||
136 | fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]); | ||
137 | |||
138 | if (info->attrs[L2TP_ATTR_DEBUG]) | ||
139 | cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]); | ||
140 | |||
141 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
142 | if (tunnel != NULL) { | ||
143 | ret = -EEXIST; | ||
144 | goto out; | ||
145 | } | ||
146 | |||
147 | ret = -EINVAL; | ||
148 | switch (cfg.encap) { | ||
149 | case L2TP_ENCAPTYPE_UDP: | ||
150 | case L2TP_ENCAPTYPE_IP: | ||
151 | ret = l2tp_tunnel_create(net, fd, proto_version, tunnel_id, | ||
152 | peer_tunnel_id, &cfg, &tunnel); | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | out: | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info) | ||
161 | { | ||
162 | struct l2tp_tunnel *tunnel; | ||
163 | u32 tunnel_id; | ||
164 | int ret = 0; | ||
165 | struct net *net = genl_info_net(info); | ||
166 | |||
167 | if (!info->attrs[L2TP_ATTR_CONN_ID]) { | ||
168 | ret = -EINVAL; | ||
169 | goto out; | ||
170 | } | ||
171 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
172 | |||
173 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
174 | if (tunnel == NULL) { | ||
175 | ret = -ENODEV; | ||
176 | goto out; | ||
177 | } | ||
178 | |||
179 | (void) l2tp_tunnel_delete(tunnel); | ||
180 | |||
181 | out: | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info) | ||
186 | { | ||
187 | struct l2tp_tunnel *tunnel; | ||
188 | u32 tunnel_id; | ||
189 | int ret = 0; | ||
190 | struct net *net = genl_info_net(info); | ||
191 | |||
192 | if (!info->attrs[L2TP_ATTR_CONN_ID]) { | ||
193 | ret = -EINVAL; | ||
194 | goto out; | ||
195 | } | ||
196 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
197 | |||
198 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
199 | if (tunnel == NULL) { | ||
200 | ret = -ENODEV; | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | if (info->attrs[L2TP_ATTR_DEBUG]) | ||
205 | tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]); | ||
206 | |||
207 | out: | ||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, | ||
212 | struct l2tp_tunnel *tunnel) | ||
213 | { | ||
214 | void *hdr; | ||
215 | struct nlattr *nest; | ||
216 | struct sock *sk = NULL; | ||
217 | struct inet_sock *inet; | ||
218 | |||
219 | hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, | ||
220 | L2TP_CMD_TUNNEL_GET); | ||
221 | if (IS_ERR(hdr)) | ||
222 | return PTR_ERR(hdr); | ||
223 | |||
224 | NLA_PUT_U8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version); | ||
225 | NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id); | ||
226 | NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id); | ||
227 | NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, tunnel->debug); | ||
228 | NLA_PUT_U16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap); | ||
229 | |||
230 | nest = nla_nest_start(skb, L2TP_ATTR_STATS); | ||
231 | if (nest == NULL) | ||
232 | goto nla_put_failure; | ||
233 | |||
234 | NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets); | ||
235 | NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes); | ||
236 | NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors); | ||
237 | NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets); | ||
238 | NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes); | ||
239 | NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, tunnel->stats.rx_seq_discards); | ||
240 | NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, tunnel->stats.rx_oos_packets); | ||
241 | NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors); | ||
242 | nla_nest_end(skb, nest); | ||
243 | |||
244 | sk = tunnel->sock; | ||
245 | if (!sk) | ||
246 | goto out; | ||
247 | |||
248 | inet = inet_sk(sk); | ||
249 | |||
250 | switch (tunnel->encap) { | ||
251 | case L2TP_ENCAPTYPE_UDP: | ||
252 | NLA_PUT_U16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)); | ||
253 | NLA_PUT_U16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)); | ||
254 | NLA_PUT_U8(skb, L2TP_ATTR_UDP_CSUM, (sk->sk_no_check != UDP_CSUM_NOXMIT)); | ||
255 | /* NOBREAK */ | ||
256 | case L2TP_ENCAPTYPE_IP: | ||
257 | NLA_PUT_BE32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr); | ||
258 | NLA_PUT_BE32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr); | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | out: | ||
263 | return genlmsg_end(skb, hdr); | ||
264 | |||
265 | nla_put_failure: | ||
266 | genlmsg_cancel(skb, hdr); | ||
267 | return -1; | ||
268 | } | ||
269 | |||
270 | static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info) | ||
271 | { | ||
272 | struct l2tp_tunnel *tunnel; | ||
273 | struct sk_buff *msg; | ||
274 | u32 tunnel_id; | ||
275 | int ret = -ENOBUFS; | ||
276 | struct net *net = genl_info_net(info); | ||
277 | |||
278 | if (!info->attrs[L2TP_ATTR_CONN_ID]) { | ||
279 | ret = -EINVAL; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
284 | |||
285 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
286 | if (tunnel == NULL) { | ||
287 | ret = -ENODEV; | ||
288 | goto out; | ||
289 | } | ||
290 | |||
291 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
292 | if (!msg) { | ||
293 | ret = -ENOMEM; | ||
294 | goto out; | ||
295 | } | ||
296 | |||
297 | ret = l2tp_nl_tunnel_send(msg, info->snd_pid, info->snd_seq, | ||
298 | NLM_F_ACK, tunnel); | ||
299 | if (ret < 0) | ||
300 | goto err_out; | ||
301 | |||
302 | return genlmsg_unicast(net, msg, info->snd_pid); | ||
303 | |||
304 | err_out: | ||
305 | nlmsg_free(msg); | ||
306 | |||
307 | out: | ||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
312 | { | ||
313 | int ti = cb->args[0]; | ||
314 | struct l2tp_tunnel *tunnel; | ||
315 | struct net *net = sock_net(skb->sk); | ||
316 | |||
317 | for (;;) { | ||
318 | tunnel = l2tp_tunnel_find_nth(net, ti); | ||
319 | if (tunnel == NULL) | ||
320 | goto out; | ||
321 | |||
322 | if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).pid, | ||
323 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
324 | tunnel) <= 0) | ||
325 | goto out; | ||
326 | |||
327 | ti++; | ||
328 | } | ||
329 | |||
330 | out: | ||
331 | cb->args[0] = ti; | ||
332 | |||
333 | return skb->len; | ||
334 | } | ||
335 | |||
336 | static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *info) | ||
337 | { | ||
338 | u32 tunnel_id = 0; | ||
339 | u32 session_id; | ||
340 | u32 peer_session_id; | ||
341 | int ret = 0; | ||
342 | struct l2tp_tunnel *tunnel; | ||
343 | struct l2tp_session *session; | ||
344 | struct l2tp_session_cfg cfg = { 0, }; | ||
345 | struct net *net = genl_info_net(info); | ||
346 | |||
347 | if (!info->attrs[L2TP_ATTR_CONN_ID]) { | ||
348 | ret = -EINVAL; | ||
349 | goto out; | ||
350 | } | ||
351 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | ||
352 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
353 | if (!tunnel) { | ||
354 | ret = -ENODEV; | ||
355 | goto out; | ||
356 | } | ||
357 | |||
358 | if (!info->attrs[L2TP_ATTR_SESSION_ID]) { | ||
359 | ret = -EINVAL; | ||
360 | goto out; | ||
361 | } | ||
362 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); | ||
363 | session = l2tp_session_find(net, tunnel, session_id); | ||
364 | if (session) { | ||
365 | ret = -EEXIST; | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) { | ||
370 | ret = -EINVAL; | ||
371 | goto out; | ||
372 | } | ||
373 | peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]); | ||
374 | |||
375 | if (!info->attrs[L2TP_ATTR_PW_TYPE]) { | ||
376 | ret = -EINVAL; | ||
377 | goto out; | ||
378 | } | ||
379 | cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]); | ||
380 | if (cfg.pw_type >= __L2TP_PWTYPE_MAX) { | ||
381 | ret = -EINVAL; | ||
382 | goto out; | ||
383 | } | ||
384 | |||
385 | if (tunnel->version > 2) { | ||
386 | if (info->attrs[L2TP_ATTR_OFFSET]) | ||
387 | cfg.offset = nla_get_u16(info->attrs[L2TP_ATTR_OFFSET]); | ||
388 | |||
389 | if (info->attrs[L2TP_ATTR_DATA_SEQ]) | ||
390 | cfg.data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]); | ||
391 | |||
392 | cfg.l2specific_type = L2TP_L2SPECTYPE_DEFAULT; | ||
393 | if (info->attrs[L2TP_ATTR_L2SPEC_TYPE]) | ||
394 | cfg.l2specific_type = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_TYPE]); | ||
395 | |||
396 | cfg.l2specific_len = 4; | ||
397 | if (info->attrs[L2TP_ATTR_L2SPEC_LEN]) | ||
398 | cfg.l2specific_len = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_LEN]); | ||
399 | |||
400 | if (info->attrs[L2TP_ATTR_COOKIE]) { | ||
401 | u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]); | ||
402 | if (len > 8) { | ||
403 | ret = -EINVAL; | ||
404 | goto out; | ||
405 | } | ||
406 | cfg.cookie_len = len; | ||
407 | memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len); | ||
408 | } | ||
409 | if (info->attrs[L2TP_ATTR_PEER_COOKIE]) { | ||
410 | u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]); | ||
411 | if (len > 8) { | ||
412 | ret = -EINVAL; | ||
413 | goto out; | ||
414 | } | ||
415 | cfg.peer_cookie_len = len; | ||
416 | memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len); | ||
417 | } | ||
418 | if (info->attrs[L2TP_ATTR_IFNAME]) | ||
419 | cfg.ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); | ||
420 | |||
421 | if (info->attrs[L2TP_ATTR_VLAN_ID]) | ||
422 | cfg.vlan_id = nla_get_u16(info->attrs[L2TP_ATTR_VLAN_ID]); | ||
423 | } | ||
424 | |||
425 | if (info->attrs[L2TP_ATTR_DEBUG]) | ||
426 | cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]); | ||
427 | |||
428 | if (info->attrs[L2TP_ATTR_RECV_SEQ]) | ||
429 | cfg.recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]); | ||
430 | |||
431 | if (info->attrs[L2TP_ATTR_SEND_SEQ]) | ||
432 | cfg.send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]); | ||
433 | |||
434 | if (info->attrs[L2TP_ATTR_LNS_MODE]) | ||
435 | cfg.lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]); | ||
436 | |||
437 | if (info->attrs[L2TP_ATTR_RECV_TIMEOUT]) | ||
438 | cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]); | ||
439 | |||
440 | if (info->attrs[L2TP_ATTR_MTU]) | ||
441 | cfg.mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]); | ||
442 | |||
443 | if (info->attrs[L2TP_ATTR_MRU]) | ||
444 | cfg.mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]); | ||
445 | |||
446 | if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) || | ||
447 | (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) { | ||
448 | ret = -EPROTONOSUPPORT; | ||
449 | goto out; | ||
450 | } | ||
451 | |||
452 | /* Check that pseudowire-specific params are present */ | ||
453 | switch (cfg.pw_type) { | ||
454 | case L2TP_PWTYPE_NONE: | ||
455 | break; | ||
456 | case L2TP_PWTYPE_ETH_VLAN: | ||
457 | if (!info->attrs[L2TP_ATTR_VLAN_ID]) { | ||
458 | ret = -EINVAL; | ||
459 | goto out; | ||
460 | } | ||
461 | break; | ||
462 | case L2TP_PWTYPE_ETH: | ||
463 | break; | ||
464 | case L2TP_PWTYPE_PPP: | ||
465 | case L2TP_PWTYPE_PPP_AC: | ||
466 | break; | ||
467 | case L2TP_PWTYPE_IP: | ||
468 | default: | ||
469 | ret = -EPROTONOSUPPORT; | ||
470 | break; | ||
471 | } | ||
472 | |||
473 | ret = -EPROTONOSUPPORT; | ||
474 | if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create) | ||
475 | ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id, | ||
476 | session_id, peer_session_id, &cfg); | ||
477 | |||
478 | out: | ||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *info) | ||
483 | { | ||
484 | int ret = 0; | ||
485 | struct l2tp_session *session; | ||
486 | u16 pw_type; | ||
487 | |||
488 | session = l2tp_nl_session_find(info); | ||
489 | if (session == NULL) { | ||
490 | ret = -ENODEV; | ||
491 | goto out; | ||
492 | } | ||
493 | |||
494 | pw_type = session->pwtype; | ||
495 | if (pw_type < __L2TP_PWTYPE_MAX) | ||
496 | if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete) | ||
497 | ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session); | ||
498 | |||
499 | out: | ||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *info) | ||
504 | { | ||
505 | int ret = 0; | ||
506 | struct l2tp_session *session; | ||
507 | |||
508 | session = l2tp_nl_session_find(info); | ||
509 | if (session == NULL) { | ||
510 | ret = -ENODEV; | ||
511 | goto out; | ||
512 | } | ||
513 | |||
514 | if (info->attrs[L2TP_ATTR_DEBUG]) | ||
515 | session->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]); | ||
516 | |||
517 | if (info->attrs[L2TP_ATTR_DATA_SEQ]) | ||
518 | session->data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]); | ||
519 | |||
520 | if (info->attrs[L2TP_ATTR_RECV_SEQ]) | ||
521 | session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]); | ||
522 | |||
523 | if (info->attrs[L2TP_ATTR_SEND_SEQ]) | ||
524 | session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]); | ||
525 | |||
526 | if (info->attrs[L2TP_ATTR_LNS_MODE]) | ||
527 | session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]); | ||
528 | |||
529 | if (info->attrs[L2TP_ATTR_RECV_TIMEOUT]) | ||
530 | session->reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]); | ||
531 | |||
532 | if (info->attrs[L2TP_ATTR_MTU]) | ||
533 | session->mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]); | ||
534 | |||
535 | if (info->attrs[L2TP_ATTR_MRU]) | ||
536 | session->mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]); | ||
537 | |||
538 | out: | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, | ||
543 | struct l2tp_session *session) | ||
544 | { | ||
545 | void *hdr; | ||
546 | struct nlattr *nest; | ||
547 | struct l2tp_tunnel *tunnel = session->tunnel; | ||
548 | struct sock *sk = NULL; | ||
549 | |||
550 | sk = tunnel->sock; | ||
551 | |||
552 | hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET); | ||
553 | if (IS_ERR(hdr)) | ||
554 | return PTR_ERR(hdr); | ||
555 | |||
556 | NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id); | ||
557 | NLA_PUT_U32(skb, L2TP_ATTR_SESSION_ID, session->session_id); | ||
558 | NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id); | ||
559 | NLA_PUT_U32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id); | ||
560 | NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, session->debug); | ||
561 | NLA_PUT_U16(skb, L2TP_ATTR_PW_TYPE, session->pwtype); | ||
562 | NLA_PUT_U16(skb, L2TP_ATTR_MTU, session->mtu); | ||
563 | if (session->mru) | ||
564 | NLA_PUT_U16(skb, L2TP_ATTR_MRU, session->mru); | ||
565 | |||
566 | if (session->ifname && session->ifname[0]) | ||
567 | NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname); | ||
568 | if (session->cookie_len) | ||
569 | NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]); | ||
570 | if (session->peer_cookie_len) | ||
571 | NLA_PUT(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, &session->peer_cookie[0]); | ||
572 | NLA_PUT_U8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq); | ||
573 | NLA_PUT_U8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq); | ||
574 | NLA_PUT_U8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode); | ||
575 | #ifdef CONFIG_XFRM | ||
576 | if ((sk) && (sk->sk_policy[0] || sk->sk_policy[1])) | ||
577 | NLA_PUT_U8(skb, L2TP_ATTR_USING_IPSEC, 1); | ||
578 | #endif | ||
579 | if (session->reorder_timeout) | ||
580 | NLA_PUT_MSECS(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout); | ||
581 | |||
582 | nest = nla_nest_start(skb, L2TP_ATTR_STATS); | ||
583 | if (nest == NULL) | ||
584 | goto nla_put_failure; | ||
585 | NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets); | ||
586 | NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes); | ||
587 | NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors); | ||
588 | NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets); | ||
589 | NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes); | ||
590 | NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, session->stats.rx_seq_discards); | ||
591 | NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, session->stats.rx_oos_packets); | ||
592 | NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors); | ||
593 | nla_nest_end(skb, nest); | ||
594 | |||
595 | return genlmsg_end(skb, hdr); | ||
596 | |||
597 | nla_put_failure: | ||
598 | genlmsg_cancel(skb, hdr); | ||
599 | return -1; | ||
600 | } | ||
601 | |||
602 | static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info) | ||
603 | { | ||
604 | struct l2tp_session *session; | ||
605 | struct sk_buff *msg; | ||
606 | int ret; | ||
607 | |||
608 | session = l2tp_nl_session_find(info); | ||
609 | if (session == NULL) { | ||
610 | ret = -ENODEV; | ||
611 | goto out; | ||
612 | } | ||
613 | |||
614 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
615 | if (!msg) { | ||
616 | ret = -ENOMEM; | ||
617 | goto out; | ||
618 | } | ||
619 | |||
620 | ret = l2tp_nl_session_send(msg, info->snd_pid, info->snd_seq, | ||
621 | 0, session); | ||
622 | if (ret < 0) | ||
623 | goto err_out; | ||
624 | |||
625 | return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); | ||
626 | |||
627 | err_out: | ||
628 | nlmsg_free(msg); | ||
629 | |||
630 | out: | ||
631 | return ret; | ||
632 | } | ||
633 | |||
634 | static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
635 | { | ||
636 | struct net *net = sock_net(skb->sk); | ||
637 | struct l2tp_session *session; | ||
638 | struct l2tp_tunnel *tunnel = NULL; | ||
639 | int ti = cb->args[0]; | ||
640 | int si = cb->args[1]; | ||
641 | |||
642 | for (;;) { | ||
643 | if (tunnel == NULL) { | ||
644 | tunnel = l2tp_tunnel_find_nth(net, ti); | ||
645 | if (tunnel == NULL) | ||
646 | goto out; | ||
647 | } | ||
648 | |||
649 | session = l2tp_session_find_nth(tunnel, si); | ||
650 | if (session == NULL) { | ||
651 | ti++; | ||
652 | tunnel = NULL; | ||
653 | si = 0; | ||
654 | continue; | ||
655 | } | ||
656 | |||
657 | if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).pid, | ||
658 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
659 | session) <= 0) | ||
660 | break; | ||
661 | |||
662 | si++; | ||
663 | } | ||
664 | |||
665 | out: | ||
666 | cb->args[0] = ti; | ||
667 | cb->args[1] = si; | ||
668 | |||
669 | return skb->len; | ||
670 | } | ||
671 | |||
672 | static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = { | ||
673 | [L2TP_ATTR_NONE] = { .type = NLA_UNSPEC, }, | ||
674 | [L2TP_ATTR_PW_TYPE] = { .type = NLA_U16, }, | ||
675 | [L2TP_ATTR_ENCAP_TYPE] = { .type = NLA_U16, }, | ||
676 | [L2TP_ATTR_OFFSET] = { .type = NLA_U16, }, | ||
677 | [L2TP_ATTR_DATA_SEQ] = { .type = NLA_U8, }, | ||
678 | [L2TP_ATTR_L2SPEC_TYPE] = { .type = NLA_U8, }, | ||
679 | [L2TP_ATTR_L2SPEC_LEN] = { .type = NLA_U8, }, | ||
680 | [L2TP_ATTR_PROTO_VERSION] = { .type = NLA_U8, }, | ||
681 | [L2TP_ATTR_CONN_ID] = { .type = NLA_U32, }, | ||
682 | [L2TP_ATTR_PEER_CONN_ID] = { .type = NLA_U32, }, | ||
683 | [L2TP_ATTR_SESSION_ID] = { .type = NLA_U32, }, | ||
684 | [L2TP_ATTR_PEER_SESSION_ID] = { .type = NLA_U32, }, | ||
685 | [L2TP_ATTR_UDP_CSUM] = { .type = NLA_U8, }, | ||
686 | [L2TP_ATTR_VLAN_ID] = { .type = NLA_U16, }, | ||
687 | [L2TP_ATTR_DEBUG] = { .type = NLA_U32, }, | ||
688 | [L2TP_ATTR_RECV_SEQ] = { .type = NLA_U8, }, | ||
689 | [L2TP_ATTR_SEND_SEQ] = { .type = NLA_U8, }, | ||
690 | [L2TP_ATTR_LNS_MODE] = { .type = NLA_U8, }, | ||
691 | [L2TP_ATTR_USING_IPSEC] = { .type = NLA_U8, }, | ||
692 | [L2TP_ATTR_RECV_TIMEOUT] = { .type = NLA_MSECS, }, | ||
693 | [L2TP_ATTR_FD] = { .type = NLA_U32, }, | ||
694 | [L2TP_ATTR_IP_SADDR] = { .type = NLA_U32, }, | ||
695 | [L2TP_ATTR_IP_DADDR] = { .type = NLA_U32, }, | ||
696 | [L2TP_ATTR_UDP_SPORT] = { .type = NLA_U16, }, | ||
697 | [L2TP_ATTR_UDP_DPORT] = { .type = NLA_U16, }, | ||
698 | [L2TP_ATTR_MTU] = { .type = NLA_U16, }, | ||
699 | [L2TP_ATTR_MRU] = { .type = NLA_U16, }, | ||
700 | [L2TP_ATTR_STATS] = { .type = NLA_NESTED, }, | ||
701 | [L2TP_ATTR_IFNAME] = { | ||
702 | .type = NLA_NUL_STRING, | ||
703 | .len = IFNAMSIZ - 1, | ||
704 | }, | ||
705 | [L2TP_ATTR_COOKIE] = { | ||
706 | .type = NLA_BINARY, | ||
707 | .len = 8, | ||
708 | }, | ||
709 | [L2TP_ATTR_PEER_COOKIE] = { | ||
710 | .type = NLA_BINARY, | ||
711 | .len = 8, | ||
712 | }, | ||
713 | }; | ||
714 | |||
715 | static struct genl_ops l2tp_nl_ops[] = { | ||
716 | { | ||
717 | .cmd = L2TP_CMD_NOOP, | ||
718 | .doit = l2tp_nl_cmd_noop, | ||
719 | .policy = l2tp_nl_policy, | ||
720 | /* can be retrieved by unprivileged users */ | ||
721 | }, | ||
722 | { | ||
723 | .cmd = L2TP_CMD_TUNNEL_CREATE, | ||
724 | .doit = l2tp_nl_cmd_tunnel_create, | ||
725 | .policy = l2tp_nl_policy, | ||
726 | .flags = GENL_ADMIN_PERM, | ||
727 | }, | ||
728 | { | ||
729 | .cmd = L2TP_CMD_TUNNEL_DELETE, | ||
730 | .doit = l2tp_nl_cmd_tunnel_delete, | ||
731 | .policy = l2tp_nl_policy, | ||
732 | .flags = GENL_ADMIN_PERM, | ||
733 | }, | ||
734 | { | ||
735 | .cmd = L2TP_CMD_TUNNEL_MODIFY, | ||
736 | .doit = l2tp_nl_cmd_tunnel_modify, | ||
737 | .policy = l2tp_nl_policy, | ||
738 | .flags = GENL_ADMIN_PERM, | ||
739 | }, | ||
740 | { | ||
741 | .cmd = L2TP_CMD_TUNNEL_GET, | ||
742 | .doit = l2tp_nl_cmd_tunnel_get, | ||
743 | .dumpit = l2tp_nl_cmd_tunnel_dump, | ||
744 | .policy = l2tp_nl_policy, | ||
745 | .flags = GENL_ADMIN_PERM, | ||
746 | }, | ||
747 | { | ||
748 | .cmd = L2TP_CMD_SESSION_CREATE, | ||
749 | .doit = l2tp_nl_cmd_session_create, | ||
750 | .policy = l2tp_nl_policy, | ||
751 | .flags = GENL_ADMIN_PERM, | ||
752 | }, | ||
753 | { | ||
754 | .cmd = L2TP_CMD_SESSION_DELETE, | ||
755 | .doit = l2tp_nl_cmd_session_delete, | ||
756 | .policy = l2tp_nl_policy, | ||
757 | .flags = GENL_ADMIN_PERM, | ||
758 | }, | ||
759 | { | ||
760 | .cmd = L2TP_CMD_SESSION_MODIFY, | ||
761 | .doit = l2tp_nl_cmd_session_modify, | ||
762 | .policy = l2tp_nl_policy, | ||
763 | .flags = GENL_ADMIN_PERM, | ||
764 | }, | ||
765 | { | ||
766 | .cmd = L2TP_CMD_SESSION_GET, | ||
767 | .doit = l2tp_nl_cmd_session_get, | ||
768 | .dumpit = l2tp_nl_cmd_session_dump, | ||
769 | .policy = l2tp_nl_policy, | ||
770 | .flags = GENL_ADMIN_PERM, | ||
771 | }, | ||
772 | }; | ||
773 | |||
774 | int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops) | ||
775 | { | ||
776 | int ret; | ||
777 | |||
778 | ret = -EINVAL; | ||
779 | if (pw_type >= __L2TP_PWTYPE_MAX) | ||
780 | goto err; | ||
781 | |||
782 | genl_lock(); | ||
783 | ret = -EBUSY; | ||
784 | if (l2tp_nl_cmd_ops[pw_type]) | ||
785 | goto out; | ||
786 | |||
787 | l2tp_nl_cmd_ops[pw_type] = ops; | ||
788 | |||
789 | out: | ||
790 | genl_unlock(); | ||
791 | err: | ||
792 | return 0; | ||
793 | } | ||
794 | EXPORT_SYMBOL_GPL(l2tp_nl_register_ops); | ||
795 | |||
796 | void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type) | ||
797 | { | ||
798 | if (pw_type < __L2TP_PWTYPE_MAX) { | ||
799 | genl_lock(); | ||
800 | l2tp_nl_cmd_ops[pw_type] = NULL; | ||
801 | genl_unlock(); | ||
802 | } | ||
803 | } | ||
804 | EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops); | ||
805 | |||
806 | static int l2tp_nl_init(void) | ||
807 | { | ||
808 | int err; | ||
809 | |||
810 | printk(KERN_INFO "L2TP netlink interface\n"); | ||
811 | err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops, | ||
812 | ARRAY_SIZE(l2tp_nl_ops)); | ||
813 | |||
814 | return err; | ||
815 | } | ||
816 | |||
817 | static void l2tp_nl_cleanup(void) | ||
818 | { | ||
819 | genl_unregister_family(&l2tp_nl_family); | ||
820 | } | ||
821 | |||
822 | module_init(l2tp_nl_init); | ||
823 | module_exit(l2tp_nl_cleanup); | ||
824 | |||
825 | MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); | ||
826 | MODULE_DESCRIPTION("L2TP netlink"); | ||
827 | MODULE_LICENSE("GPL"); | ||
828 | MODULE_VERSION("1.0"); | ||
829 | MODULE_ALIAS("net-pf-" __stringify(PF_NETLINK) "-proto-" \ | ||
830 | __stringify(NETLINK_GENERIC) "-type-" "l2tp") | ||
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 63fc62baeeb9..d64f081f2b1c 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
@@ -87,6 +87,7 @@ | |||
87 | #include <linux/hash.h> | 87 | #include <linux/hash.h> |
88 | #include <linux/sort.h> | 88 | #include <linux/sort.h> |
89 | #include <linux/proc_fs.h> | 89 | #include <linux/proc_fs.h> |
90 | #include <linux/l2tp.h> | ||
90 | #include <linux/nsproxy.h> | 91 | #include <linux/nsproxy.h> |
91 | #include <net/net_namespace.h> | 92 | #include <net/net_namespace.h> |
92 | #include <net/netns/generic.h> | 93 | #include <net/netns/generic.h> |
@@ -656,17 +657,23 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
656 | if (tunnel_id == 0) | 657 | if (tunnel_id == 0) |
657 | goto end; | 658 | goto end; |
658 | 659 | ||
660 | tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id); | ||
661 | |||
659 | /* Special case: create tunnel context if session_id and | 662 | /* Special case: create tunnel context if session_id and |
660 | * peer_session_id is 0. Otherwise look up tunnel using supplied | 663 | * peer_session_id is 0. Otherwise look up tunnel using supplied |
661 | * tunnel id. | 664 | * tunnel id. |
662 | */ | 665 | */ |
663 | if ((session_id == 0) && (peer_session_id == 0)) { | 666 | if ((session_id == 0) && (peer_session_id == 0)) { |
664 | error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, NULL, &tunnel); | 667 | if (tunnel == NULL) { |
665 | if (error < 0) | 668 | struct l2tp_tunnel_cfg tcfg = { |
666 | goto end; | 669 | .encap = L2TP_ENCAPTYPE_UDP, |
670 | .debug = 0, | ||
671 | }; | ||
672 | error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel); | ||
673 | if (error < 0) | ||
674 | goto end; | ||
675 | } | ||
667 | } else { | 676 | } else { |
668 | tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id); | ||
669 | |||
670 | /* Error if we can't find the tunnel */ | 677 | /* Error if we can't find the tunnel */ |
671 | error = -ENOENT; | 678 | error = -ENOENT; |
672 | if (tunnel == NULL) | 679 | if (tunnel == NULL) |
@@ -680,28 +687,46 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
680 | if (tunnel->recv_payload_hook == NULL) | 687 | if (tunnel->recv_payload_hook == NULL) |
681 | tunnel->recv_payload_hook = pppol2tp_recv_payload_hook; | 688 | tunnel->recv_payload_hook = pppol2tp_recv_payload_hook; |
682 | 689 | ||
683 | /* Check that this session doesn't already exist */ | 690 | if (tunnel->peer_tunnel_id == 0) { |
684 | error = -EEXIST; | 691 | if (ver == 2) |
685 | session = l2tp_session_find(sock_net(sk), tunnel, session_id); | 692 | tunnel->peer_tunnel_id = sp->pppol2tp.d_tunnel; |
686 | if (session != NULL) | 693 | else |
687 | goto end; | 694 | tunnel->peer_tunnel_id = sp3->pppol2tp.d_tunnel; |
688 | 695 | } | |
689 | /* Default MTU values. */ | ||
690 | if (cfg.mtu == 0) | ||
691 | cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; | ||
692 | if (cfg.mru == 0) | ||
693 | cfg.mru = cfg.mtu; | ||
694 | cfg.debug = tunnel->debug; | ||
695 | 696 | ||
696 | /* Allocate and initialize a new session context. */ | 697 | /* Create session if it doesn't already exist. We handle the |
697 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 698 | * case where a session was previously created by the netlink |
698 | tunnel, session_id, | 699 | * interface by checking that the session doesn't already have |
699 | peer_session_id, &cfg); | 700 | * a socket and its tunnel socket are what we expect. If any |
701 | * of those checks fail, return EEXIST to the caller. | ||
702 | */ | ||
703 | session = l2tp_session_find(sock_net(sk), tunnel, session_id); | ||
700 | if (session == NULL) { | 704 | if (session == NULL) { |
701 | error = -ENOMEM; | 705 | /* Default MTU must allow space for UDP/L2TP/PPP |
702 | goto end; | 706 | * headers. |
707 | */ | ||
708 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; | ||
709 | |||
710 | /* Allocate and initialize a new session context. */ | ||
711 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | ||
712 | tunnel, session_id, | ||
713 | peer_session_id, &cfg); | ||
714 | if (session == NULL) { | ||
715 | error = -ENOMEM; | ||
716 | goto end; | ||
717 | } | ||
718 | } else { | ||
719 | ps = l2tp_session_priv(session); | ||
720 | error = -EEXIST; | ||
721 | if (ps->sock != NULL) | ||
722 | goto end; | ||
723 | |||
724 | /* consistency checks */ | ||
725 | if (ps->tunnel_sock != tunnel->sock) | ||
726 | goto end; | ||
703 | } | 727 | } |
704 | 728 | ||
729 | /* Associate session with its PPPoL2TP socket */ | ||
705 | ps = l2tp_session_priv(session); | 730 | ps = l2tp_session_priv(session); |
706 | ps->owner = current->pid; | 731 | ps->owner = current->pid; |
707 | ps->sock = sk; | 732 | ps->sock = sk; |
@@ -764,6 +789,74 @@ end: | |||
764 | return error; | 789 | return error; |
765 | } | 790 | } |
766 | 791 | ||
792 | #ifdef CONFIG_L2TP_V3 | ||
793 | |||
794 | /* Called when creating sessions via the netlink interface. | ||
795 | */ | ||
796 | static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | ||
797 | { | ||
798 | int error; | ||
799 | struct l2tp_tunnel *tunnel; | ||
800 | struct l2tp_session *session; | ||
801 | struct pppol2tp_session *ps; | ||
802 | |||
803 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
804 | |||
805 | /* Error if we can't find the tunnel */ | ||
806 | error = -ENOENT; | ||
807 | if (tunnel == NULL) | ||
808 | goto out; | ||
809 | |||
810 | /* Error if tunnel socket is not prepped */ | ||
811 | if (tunnel->sock == NULL) | ||
812 | goto out; | ||
813 | |||
814 | /* Check that this session doesn't already exist */ | ||
815 | error = -EEXIST; | ||
816 | session = l2tp_session_find(net, tunnel, session_id); | ||
817 | if (session != NULL) | ||
818 | goto out; | ||
819 | |||
820 | /* Default MTU values. */ | ||
821 | if (cfg->mtu == 0) | ||
822 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; | ||
823 | if (cfg->mru == 0) | ||
824 | cfg->mru = cfg->mtu; | ||
825 | |||
826 | /* Allocate and initialize a new session context. */ | ||
827 | error = -ENOMEM; | ||
828 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | ||
829 | tunnel, session_id, | ||
830 | peer_session_id, cfg); | ||
831 | if (session == NULL) | ||
832 | goto out; | ||
833 | |||
834 | ps = l2tp_session_priv(session); | ||
835 | ps->tunnel_sock = tunnel->sock; | ||
836 | |||
837 | PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, | ||
838 | "%s: created\n", session->name); | ||
839 | |||
840 | error = 0; | ||
841 | |||
842 | out: | ||
843 | return error; | ||
844 | } | ||
845 | |||
846 | /* Called when deleting sessions via the netlink interface. | ||
847 | */ | ||
848 | static int pppol2tp_session_delete(struct l2tp_session *session) | ||
849 | { | ||
850 | struct pppol2tp_session *ps = l2tp_session_priv(session); | ||
851 | |||
852 | if (ps->sock == NULL) | ||
853 | l2tp_session_dec_refcount(session); | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | #endif /* CONFIG_L2TP_V3 */ | ||
859 | |||
767 | /* getname() support. | 860 | /* getname() support. |
768 | */ | 861 | */ |
769 | static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, | 862 | static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, |
@@ -1660,6 +1753,15 @@ static struct pppox_proto pppol2tp_proto = { | |||
1660 | .ioctl = pppol2tp_ioctl | 1753 | .ioctl = pppol2tp_ioctl |
1661 | }; | 1754 | }; |
1662 | 1755 | ||
1756 | #ifdef CONFIG_L2TP_V3 | ||
1757 | |||
1758 | static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = { | ||
1759 | .session_create = pppol2tp_session_create, | ||
1760 | .session_delete = pppol2tp_session_delete, | ||
1761 | }; | ||
1762 | |||
1763 | #endif /* CONFIG_L2TP_V3 */ | ||
1764 | |||
1663 | static int __init pppol2tp_init(void) | 1765 | static int __init pppol2tp_init(void) |
1664 | { | 1766 | { |
1665 | int err; | 1767 | int err; |
@@ -1676,11 +1778,22 @@ static int __init pppol2tp_init(void) | |||
1676 | if (err) | 1778 | if (err) |
1677 | goto out_unregister_pppol2tp_proto; | 1779 | goto out_unregister_pppol2tp_proto; |
1678 | 1780 | ||
1781 | #ifdef CONFIG_L2TP_V3 | ||
1782 | err = l2tp_nl_register_ops(L2TP_PWTYPE_PPP, &pppol2tp_nl_cmd_ops); | ||
1783 | if (err) | ||
1784 | goto out_unregister_pppox; | ||
1785 | #endif | ||
1786 | |||
1679 | printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", | 1787 | printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", |
1680 | PPPOL2TP_DRV_VERSION); | 1788 | PPPOL2TP_DRV_VERSION); |
1681 | 1789 | ||
1682 | out: | 1790 | out: |
1683 | return err; | 1791 | return err; |
1792 | |||
1793 | #ifdef CONFIG_L2TP_V3 | ||
1794 | out_unregister_pppox: | ||
1795 | unregister_pppox_proto(PX_PROTO_OL2TP); | ||
1796 | #endif | ||
1684 | out_unregister_pppol2tp_proto: | 1797 | out_unregister_pppol2tp_proto: |
1685 | proto_unregister(&pppol2tp_sk_proto); | 1798 | proto_unregister(&pppol2tp_sk_proto); |
1686 | out_unregister_pppol2tp_pernet: | 1799 | out_unregister_pppol2tp_pernet: |
@@ -1690,6 +1803,9 @@ out_unregister_pppol2tp_pernet: | |||
1690 | 1803 | ||
1691 | static void __exit pppol2tp_exit(void) | 1804 | static void __exit pppol2tp_exit(void) |
1692 | { | 1805 | { |
1806 | #ifdef CONFIG_L2TP_V3 | ||
1807 | l2tp_nl_unregister_ops(L2TP_PWTYPE_PPP); | ||
1808 | #endif | ||
1693 | unregister_pppox_proto(PX_PROTO_OL2TP); | 1809 | unregister_pppox_proto(PX_PROTO_OL2TP); |
1694 | proto_unregister(&pppol2tp_sk_proto); | 1810 | proto_unregister(&pppol2tp_sk_proto); |
1695 | unregister_pernet_device(&pppol2tp_net_ops); | 1811 | unregister_pernet_device(&pppol2tp_net_ops); |