Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 1 | /* drivers/net/pppopns.c |
| 2 | * |
| 3 | * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637) |
| 4 | * |
| 5 | * Copyright (C) 2009 Google, Inc. |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 6 | * |
| 7 | * This software is licensed under the terms of the GNU General Public |
| 8 | * License version 2, as published by the Free Software Foundation, and |
| 9 | * may be copied, distributed, and modified under those terms. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | */ |
| 16 | |
| 17 | /* This driver handles PPTP data packets between a RAW socket and a PPP channel. |
| 18 | * The socket is created in the kernel space and connected to the same address |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 19 | * of the control socket. Outgoing packets are always sent with sequences but |
| 20 | * without acknowledgements. Incoming packets with sequences are reordered |
| 21 | * within a sliding window of one second. Currently reordering only happens when |
| 22 | * a packet is received. It is done for simplicity since no additional locks or |
| 23 | * threads are required. This driver should work on both IPv4 and IPv6. */ |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 24 | |
| 25 | #include <linux/module.h> |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 26 | #include <linux/jiffies.h> |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 27 | #include <linux/workqueue.h> |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 28 | #include <linux/skbuff.h> |
| 29 | #include <linux/file.h> |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 30 | #include <linux/netdevice.h> |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 31 | #include <linux/net.h> |
| 32 | #include <linux/ppp_defs.h> |
| 33 | #include <linux/if.h> |
| 34 | #include <linux/if_ppp.h> |
| 35 | #include <linux/if_pppox.h> |
| 36 | #include <linux/ppp_channel.h> |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 37 | #include <asm/uaccess.h> |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 38 | |
| 39 | #define GRE_HEADER_SIZE 8 |
| 40 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 41 | #define PPTP_GRE_BITS htons(0x2001) |
| 42 | #define PPTP_GRE_BITS_MASK htons(0xEF7F) |
| 43 | #define PPTP_GRE_SEQ_BIT htons(0x1000) |
| 44 | #define PPTP_GRE_ACK_BIT htons(0x0080) |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 45 | #define PPTP_GRE_TYPE htons(0x880B) |
| 46 | |
| 47 | #define PPP_ADDR 0xFF |
| 48 | #define PPP_CTRL 0x03 |
| 49 | |
| 50 | struct header { |
| 51 | __u16 bits; |
| 52 | __u16 type; |
| 53 | __u16 length; |
| 54 | __u16 call; |
| 55 | __u32 sequence; |
| 56 | } __attribute__((packed)); |
| 57 | |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 58 | struct meta { |
| 59 | __u32 sequence; |
| 60 | __u32 timestamp; |
| 61 | }; |
| 62 | |
| 63 | static inline struct meta *skb_meta(struct sk_buff *skb) |
| 64 | { |
| 65 | return (struct meta *)skb->cb; |
| 66 | } |
| 67 | |
| 68 | /******************************************************************************/ |
| 69 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 70 | static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb) |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 71 | { |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 72 | struct sock *sk = (struct sock *)sk_raw->sk_user_data; |
| 73 | struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns; |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 74 | struct meta *meta = skb_meta(skb); |
| 75 | __u32 now = jiffies; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 76 | struct header *hdr; |
| 77 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 78 | /* Skip transport header */ |
| 79 | skb_pull(skb, skb_transport_header(skb) - skb->data); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 80 | |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 81 | /* Drop the packet if GRE header is missing. */ |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 82 | if (skb->len < GRE_HEADER_SIZE) |
| 83 | goto drop; |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 84 | hdr = (struct header *)skb->data; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 85 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 86 | /* Check the header. */ |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 87 | if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local || |
| 88 | (hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS) |
| 89 | goto drop; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 90 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 91 | /* Skip all fields including optional ones. */ |
| 92 | if (!skb_pull(skb, GRE_HEADER_SIZE + |
| 93 | (hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) + |
| 94 | (hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0))) |
| 95 | goto drop; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 96 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 97 | /* Check the length. */ |
| 98 | if (skb->len != ntohs(hdr->length)) |
| 99 | goto drop; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 100 | |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 101 | /* Check the sequence if it is present. */ |
| 102 | if (hdr->bits & PPTP_GRE_SEQ_BIT) { |
| 103 | meta->sequence = ntohl(hdr->sequence); |
| 104 | if ((__s32)(meta->sequence - opt->recv_sequence) < 0) |
| 105 | goto drop; |
| 106 | } |
| 107 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 108 | /* Skip PPP address and control if they are present. */ |
| 109 | if (skb->len >= 2 && skb->data[0] == PPP_ADDR && |
| 110 | skb->data[1] == PPP_CTRL) |
| 111 | skb_pull(skb, 2); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 112 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 113 | /* Fix PPP protocol if it is compressed. */ |
| 114 | if (skb->len >= 1 && skb->data[0] & 1) |
| 115 | skb_push(skb, 1)[0] = 0; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 116 | |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 117 | /* Drop the packet if PPP protocol is missing. */ |
| 118 | if (skb->len < 2) |
| 119 | goto drop; |
| 120 | |
| 121 | /* Perform reordering if sequencing is enabled. */ |
| 122 | if (hdr->bits & PPTP_GRE_SEQ_BIT) { |
| 123 | struct sk_buff *skb1; |
| 124 | |
| 125 | /* Insert the packet into receive queue in order. */ |
| 126 | skb_set_owner_r(skb, sk); |
| 127 | skb_queue_walk(&sk->sk_receive_queue, skb1) { |
| 128 | struct meta *meta1 = skb_meta(skb1); |
| 129 | __s32 order = meta->sequence - meta1->sequence; |
| 130 | if (order == 0) |
| 131 | goto drop; |
| 132 | if (order < 0) { |
| 133 | meta->timestamp = meta1->timestamp; |
| 134 | skb_insert(skb1, skb, &sk->sk_receive_queue); |
| 135 | skb = NULL; |
| 136 | break; |
| 137 | } |
| 138 | } |
| 139 | if (skb) { |
| 140 | meta->timestamp = now; |
| 141 | skb_queue_tail(&sk->sk_receive_queue, skb); |
| 142 | } |
| 143 | |
| 144 | /* Remove packets from receive queue as long as |
| 145 | * 1. the receive buffer is full, |
| 146 | * 2. they are queued longer than one second, or |
| 147 | * 3. there are no missing packets before them. */ |
| 148 | skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) { |
| 149 | meta = skb_meta(skb); |
| 150 | if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && |
| 151 | now - meta->timestamp < HZ && |
| 152 | meta->sequence != opt->recv_sequence) |
| 153 | break; |
| 154 | skb_unlink(skb, &sk->sk_receive_queue); |
| 155 | opt->recv_sequence = meta->sequence + 1; |
| 156 | skb_orphan(skb); |
| 157 | ppp_input(&pppox_sk(sk)->chan, skb); |
| 158 | } |
| 159 | return NET_RX_SUCCESS; |
| 160 | } |
| 161 | |
| 162 | /* Flush receive queue if sequencing is disabled. */ |
| 163 | skb_queue_purge(&sk->sk_receive_queue); |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 164 | skb_orphan(skb); |
| 165 | ppp_input(&pppox_sk(sk)->chan, skb); |
| 166 | return NET_RX_SUCCESS; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 167 | drop: |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 168 | kfree_skb(skb); |
| 169 | return NET_RX_DROP; |
| 170 | } |
| 171 | |
Jon Medhurst | 07597f4 | 2015-08-19 13:43:16 +0100 | [diff] [blame] | 172 | static void pppopns_recv(struct sock *sk_raw) |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 173 | { |
| 174 | struct sk_buff *skb; |
| 175 | while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) { |
| 176 | sock_hold(sk_raw); |
| 177 | sk_receive_skb(sk_raw, skb, 0); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | static struct sk_buff_head delivery_queue; |
| 182 | |
| 183 | static void pppopns_xmit_core(struct work_struct *delivery_work) |
| 184 | { |
| 185 | mm_segment_t old_fs = get_fs(); |
| 186 | struct sk_buff *skb; |
| 187 | |
| 188 | set_fs(KERNEL_DS); |
| 189 | while ((skb = skb_dequeue(&delivery_queue))) { |
| 190 | struct sock *sk_raw = skb->sk; |
| 191 | struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; |
Guenter Roeck | 4bb5643 | 2016-03-01 09:44:17 -0800 | [diff] [blame] | 192 | struct msghdr msg = { 0 }; |
| 193 | |
| 194 | iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, |
| 195 | skb->len); |
Amit Pundir | 697cabc | 2015-12-08 18:26:39 +0530 | [diff] [blame] | 196 | sk_raw->sk_prot->sendmsg(sk_raw, &msg, skb->len); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 197 | kfree_skb(skb); |
| 198 | } |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 199 | set_fs(old_fs); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 200 | } |
| 201 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 202 | static DECLARE_WORK(delivery_work, pppopns_xmit_core); |
| 203 | |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 204 | static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb) |
| 205 | { |
| 206 | struct sock *sk_raw = (struct sock *)chan->private; |
| 207 | struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 208 | struct header *hdr; |
| 209 | __u16 length; |
| 210 | |
| 211 | /* Install PPP address and control. */ |
| 212 | skb_push(skb, 2); |
| 213 | skb->data[0] = PPP_ADDR; |
| 214 | skb->data[1] = PPP_CTRL; |
| 215 | length = skb->len; |
| 216 | |
| 217 | /* Install PPTP GRE header. */ |
| 218 | hdr = (struct header *)skb_push(skb, 12); |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 219 | hdr->bits = PPTP_GRE_BITS | PPTP_GRE_SEQ_BIT; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 220 | hdr->type = PPTP_GRE_TYPE; |
| 221 | hdr->length = htons(length); |
| 222 | hdr->call = opt->remote; |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 223 | hdr->sequence = htonl(opt->xmit_sequence); |
| 224 | opt->xmit_sequence++; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 225 | |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 226 | /* Now send the packet via the delivery queue. */ |
| 227 | skb_set_owner_w(skb, sk_raw); |
| 228 | skb_queue_tail(&delivery_queue, skb); |
| 229 | schedule_work(&delivery_work); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 230 | return 1; |
| 231 | } |
| 232 | |
| 233 | /******************************************************************************/ |
| 234 | |
| 235 | static struct ppp_channel_ops pppopns_channel_ops = { |
| 236 | .start_xmit = pppopns_xmit, |
| 237 | }; |
| 238 | |
| 239 | static int pppopns_connect(struct socket *sock, struct sockaddr *useraddr, |
| 240 | int addrlen, int flags) |
| 241 | { |
| 242 | struct sock *sk = sock->sk; |
| 243 | struct pppox_sock *po = pppox_sk(sk); |
| 244 | struct sockaddr_pppopns *addr = (struct sockaddr_pppopns *)useraddr; |
| 245 | struct sockaddr_storage ss; |
| 246 | struct socket *sock_tcp = NULL; |
| 247 | struct socket *sock_raw = NULL; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 248 | struct sock *sk_tcp; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 249 | struct sock *sk_raw; |
| 250 | int error; |
| 251 | |
| 252 | if (addrlen != sizeof(struct sockaddr_pppopns)) |
| 253 | return -EINVAL; |
| 254 | |
| 255 | lock_sock(sk); |
| 256 | error = -EALREADY; |
| 257 | if (sk->sk_state != PPPOX_NONE) |
| 258 | goto out; |
| 259 | |
| 260 | sock_tcp = sockfd_lookup(addr->tcp_socket, &error); |
| 261 | if (!sock_tcp) |
| 262 | goto out; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 263 | sk_tcp = sock_tcp->sk; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 264 | error = -EPROTONOSUPPORT; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 265 | if (sk_tcp->sk_protocol != IPPROTO_TCP) |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 266 | goto out; |
| 267 | addrlen = sizeof(struct sockaddr_storage); |
| 268 | error = kernel_getpeername(sock_tcp, (struct sockaddr *)&ss, &addrlen); |
| 269 | if (error) |
| 270 | goto out; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 271 | if (!sk_tcp->sk_bound_dev_if) { |
| 272 | struct dst_entry *dst = sk_dst_get(sk_tcp); |
| 273 | error = -ENODEV; |
| 274 | if (!dst) |
| 275 | goto out; |
| 276 | sk_tcp->sk_bound_dev_if = dst->dev->ifindex; |
| 277 | dst_release(dst); |
| 278 | } |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 279 | |
| 280 | error = sock_create(ss.ss_family, SOCK_RAW, IPPROTO_GRE, &sock_raw); |
| 281 | if (error) |
| 282 | goto out; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 283 | sk_raw = sock_raw->sk; |
| 284 | sk_raw->sk_bound_dev_if = sk_tcp->sk_bound_dev_if; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 285 | error = kernel_connect(sock_raw, (struct sockaddr *)&ss, addrlen, 0); |
| 286 | if (error) |
| 287 | goto out; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 288 | |
| 289 | po->chan.hdrlen = 14; |
| 290 | po->chan.private = sk_raw; |
| 291 | po->chan.ops = &pppopns_channel_ops; |
JP Abgrall | e770a83 | 2012-09-20 16:34:10 -0700 | [diff] [blame] | 292 | po->chan.mtu = PPP_MRU - 80; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 293 | po->proto.pns.local = addr->local; |
| 294 | po->proto.pns.remote = addr->remote; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 295 | po->proto.pns.data_ready = sk_raw->sk_data_ready; |
| 296 | po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 297 | |
| 298 | error = ppp_register_channel(&po->chan); |
| 299 | if (error) |
| 300 | goto out; |
| 301 | |
| 302 | sk->sk_state = PPPOX_CONNECTED; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 303 | lock_sock(sk_raw); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 304 | sk_raw->sk_data_ready = pppopns_recv; |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 305 | sk_raw->sk_backlog_rcv = pppopns_recv_core; |
| 306 | sk_raw->sk_user_data = sk; |
| 307 | release_sock(sk_raw); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 308 | out: |
| 309 | if (sock_tcp) |
| 310 | sockfd_put(sock_tcp); |
| 311 | if (error && sock_raw) |
| 312 | sock_release(sock_raw); |
| 313 | release_sock(sk); |
| 314 | return error; |
| 315 | } |
| 316 | |
| 317 | static int pppopns_release(struct socket *sock) |
| 318 | { |
| 319 | struct sock *sk = sock->sk; |
| 320 | |
| 321 | if (!sk) |
| 322 | return 0; |
| 323 | |
| 324 | lock_sock(sk); |
| 325 | if (sock_flag(sk, SOCK_DEAD)) { |
| 326 | release_sock(sk); |
| 327 | return -EBADF; |
| 328 | } |
| 329 | |
| 330 | if (sk->sk_state != PPPOX_NONE) { |
| 331 | struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private; |
| 332 | lock_sock(sk_raw); |
Chia-chi Yeh | 8d75590 | 2011-04-15 15:22:09 -0700 | [diff] [blame] | 333 | skb_queue_purge(&sk->sk_receive_queue); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 334 | pppox_unbind_sock(sk); |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 335 | sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready; |
| 336 | sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv; |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 337 | sk_raw->sk_user_data = NULL; |
| 338 | release_sock(sk_raw); |
| 339 | sock_release(sk_raw->sk_socket); |
| 340 | } |
| 341 | |
| 342 | sock_orphan(sk); |
| 343 | sock->sk = NULL; |
| 344 | release_sock(sk); |
| 345 | sock_put(sk); |
| 346 | return 0; |
| 347 | } |
| 348 | |
| 349 | /******************************************************************************/ |
| 350 | |
| 351 | static struct proto pppopns_proto = { |
| 352 | .name = "PPPOPNS", |
| 353 | .owner = THIS_MODULE, |
| 354 | .obj_size = sizeof(struct pppox_sock), |
| 355 | }; |
| 356 | |
| 357 | static struct proto_ops pppopns_proto_ops = { |
| 358 | .family = PF_PPPOX, |
| 359 | .owner = THIS_MODULE, |
| 360 | .release = pppopns_release, |
| 361 | .bind = sock_no_bind, |
| 362 | .connect = pppopns_connect, |
| 363 | .socketpair = sock_no_socketpair, |
| 364 | .accept = sock_no_accept, |
| 365 | .getname = sock_no_getname, |
| 366 | .poll = sock_no_poll, |
| 367 | .ioctl = pppox_ioctl, |
| 368 | .listen = sock_no_listen, |
| 369 | .shutdown = sock_no_shutdown, |
| 370 | .setsockopt = sock_no_setsockopt, |
| 371 | .getsockopt = sock_no_getsockopt, |
| 372 | .sendmsg = sock_no_sendmsg, |
| 373 | .recvmsg = sock_no_recvmsg, |
| 374 | .mmap = sock_no_mmap, |
| 375 | }; |
| 376 | |
Amit Pundir | 38fcb60 | 2015-12-08 12:47:01 +0530 | [diff] [blame] | 377 | static int pppopns_create(struct net *net, struct socket *sock, int kern) |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 378 | { |
| 379 | struct sock *sk; |
| 380 | |
Amit Pundir | 38fcb60 | 2015-12-08 12:47:01 +0530 | [diff] [blame] | 381 | sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppopns_proto, kern); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 382 | if (!sk) |
| 383 | return -ENOMEM; |
| 384 | |
| 385 | sock_init_data(sock, sk); |
| 386 | sock->state = SS_UNCONNECTED; |
| 387 | sock->ops = &pppopns_proto_ops; |
| 388 | sk->sk_protocol = PX_PROTO_OPNS; |
| 389 | sk->sk_state = PPPOX_NONE; |
| 390 | return 0; |
| 391 | } |
| 392 | |
| 393 | /******************************************************************************/ |
| 394 | |
| 395 | static struct pppox_proto pppopns_pppox_proto = { |
| 396 | .create = pppopns_create, |
| 397 | .owner = THIS_MODULE, |
| 398 | }; |
| 399 | |
| 400 | static int __init pppopns_init(void) |
| 401 | { |
| 402 | int error; |
| 403 | |
| 404 | error = proto_register(&pppopns_proto, 0); |
| 405 | if (error) |
| 406 | return error; |
| 407 | |
| 408 | error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto); |
| 409 | if (error) |
| 410 | proto_unregister(&pppopns_proto); |
Chia-chi Yeh | eb7bc27 | 2009-06-13 02:29:04 +0800 | [diff] [blame] | 411 | else |
| 412 | skb_queue_head_init(&delivery_queue); |
Chia-chi Yeh | 69e8c02 | 2009-06-12 01:09:30 +0800 | [diff] [blame] | 413 | return error; |
| 414 | } |
| 415 | |
| 416 | static void __exit pppopns_exit(void) |
| 417 | { |
| 418 | unregister_pppox_proto(PX_PROTO_OPNS); |
| 419 | proto_unregister(&pppopns_proto); |
| 420 | } |
| 421 | |
| 422 | module_init(pppopns_init); |
| 423 | module_exit(pppopns_exit); |
| 424 | |
| 425 | MODULE_DESCRIPTION("PPP on PPTP Network Server (PPPoPNS)"); |
| 426 | MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>"); |
| 427 | MODULE_LICENSE("GPL"); |