149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh/* drivers/net/pppolac.c 249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * 349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661) 449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * 549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * Copyright (C) 2009 Google, Inc. 649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * 749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * This software is licensed under the terms of the GNU General Public 849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * License version 2, as published by the Free Software Foundation, and 949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * may be copied, distributed, and modified under those terms. 1049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * 1149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * This program is distributed in the hope that it will be useful, 1249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * but WITHOUT ANY WARRANTY; without even the implied warranty of 1349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh * GNU General Public License for more details. 1549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh */ 1649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 1749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh/* This driver handles L2TP data packets between a UDP socket and a PPP channel. 18463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * The socket must keep connected, and only one session per socket is permitted. 19463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * Sequencing of outgoing packets is controlled by LNS. Incoming packets with 20463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * sequences are reordered within a sliding window of one second. Currently 21463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * reordering only happens when a packet is received. It is done for simplicity 22463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * since no additional locks or threads are required. This driver only works on 23463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * IPv4 due to the lack of UDP encapsulation support in IPv6. */ 2449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 2549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/module.h> 26463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh#include <linux/jiffies.h> 27c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#include <linux/workqueue.h> 2849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/skbuff.h> 2949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/file.h> 30c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#include <linux/netdevice.h> 3149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/net.h> 3249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/udp.h> 3349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/ppp_defs.h> 3449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/if_ppp.h> 3549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/if_pppox.h> 3649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <linux/ppp_channel.h> 3749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#include <net/tcp_states.h> 38c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#include <asm/uaccess.h> 3949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 40c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#define L2TP_CONTROL_BIT 0x80 41c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#define L2TP_LENGTH_BIT 0x40 42c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#define L2TP_SEQUENCE_BIT 0x08 43c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#define L2TP_OFFSET_BIT 0x02 4449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#define L2TP_VERSION 0x02 45c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh#define L2TP_VERSION_MASK 0x0F 4649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 4749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#define PPP_ADDR 0xFF 4849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh#define PPP_CTRL 0x03 4949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 5049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehunion unaligned { 5149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh __u32 u32; 5249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} __attribute__((packed)); 5349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 5449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic inline union unaligned *unaligned(void *ptr) 5549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 5649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return (union unaligned *)ptr; 5749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 5849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 59463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yehstruct meta { 60463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh __u32 sequence; 61463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh __u32 timestamp; 62463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh}; 63463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 64463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yehstatic inline struct meta *skb_meta(struct sk_buff *skb) 65463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh{ 66463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh return (struct meta *)skb->cb; 67463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh} 68463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 69463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh/******************************************************************************/ 70463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 71c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yehstatic int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb) 7249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 73c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct sock *sk = (struct sock *)sk_udp->sk_user_data; 74c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac; 75463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh struct meta *meta = skb_meta(skb); 76463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh __u32 now = jiffies; 7749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh __u8 bits; 7849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh __u8 *ptr; 7949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 80463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Drop the packet if L2TP header is missing. */ 8149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (skb->len < sizeof(struct udphdr) + 6) 8249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 8349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 8449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Put it back if it is a control packet. */ 85c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT) 86c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh return opt->backlog_rcv(sk_udp, skb); 8749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 88c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh /* Skip UDP header. */ 8949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_pull(skb, sizeof(struct udphdr)); 9049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 9149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Check the version. */ 9249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if ((skb->data[1] & L2TP_VERSION_MASK) != L2TP_VERSION) 9349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 9449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh bits = skb->data[0]; 9549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh ptr = &skb->data[2]; 9649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 9749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Check the length if it is present. */ 98c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (bits & L2TP_LENGTH_BIT) { 9949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if ((ptr[0] << 8 | ptr[1]) != skb->len) 10049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 10149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh ptr += 2; 10249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 10349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 10449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Skip all fields including optional ones. */ 105c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (!skb_pull(skb, 6 + (bits & L2TP_SEQUENCE_BIT ? 4 : 0) + 106c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh (bits & L2TP_LENGTH_BIT ? 2 : 0) + 107c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh (bits & L2TP_OFFSET_BIT ? 2 : 0))) 10849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 10949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 11049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Skip the offset padding if it is present. */ 111c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (bits & L2TP_OFFSET_BIT && 11249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh !skb_pull(skb, skb->data[-2] << 8 | skb->data[-1])) 11349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 11449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 11549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Check the tunnel and the session. */ 116c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (unaligned(ptr)->u32 != opt->local) 11749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto drop; 11849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 119463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Check the sequence if it is present. */ 120463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (bits & L2TP_SEQUENCE_BIT) { 121463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh meta->sequence = ptr[4] << 8 | ptr[5]; 122463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if ((__s16)(meta->sequence - opt->recv_sequence) < 0) 123463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh goto drop; 124463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 12549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 12649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Skip PPP address and control if they are present. */ 12749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (skb->len >= 2 && skb->data[0] == PPP_ADDR && 12849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[1] == PPP_CTRL) 12949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_pull(skb, 2); 13049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 13149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Fix PPP protocol if it is compressed. */ 13249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (skb->len >= 1 && skb->data[0] & 1) 13349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_push(skb, 1)[0] = 0; 13449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 135463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Drop the packet if PPP protocol is missing. */ 136463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (skb->len < 2) 137463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh goto drop; 138463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 139463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Perform reordering if sequencing is enabled. */ 140463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT); 141463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (bits & L2TP_SEQUENCE_BIT) { 142463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh struct sk_buff *skb1; 143463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 144463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Insert the packet into receive queue in order. */ 145463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_set_owner_r(skb, sk); 146463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_queue_walk(&sk->sk_receive_queue, skb1) { 147463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh struct meta *meta1 = skb_meta(skb1); 148463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh __s16 order = meta->sequence - meta1->sequence; 149463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (order == 0) 150463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh goto drop; 151463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (order < 0) { 152463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh meta->timestamp = meta1->timestamp; 153463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_insert(skb1, skb, &sk->sk_receive_queue); 154463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb = NULL; 155463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh break; 156463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 157463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 158463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (skb) { 159463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh meta->timestamp = now; 160463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_queue_tail(&sk->sk_receive_queue, skb); 161463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 162463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 163463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Remove packets from receive queue as long as 164463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * 1. the receive buffer is full, 165463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * 2. they are queued longer than one second, or 166463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh * 3. there are no missing packets before them. */ 167463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) { 168463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh meta = skb_meta(skb); 169463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && 170463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh now - meta->timestamp < HZ && 171463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh meta->sequence != opt->recv_sequence) 172463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh break; 173463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_unlink(skb, &sk->sk_receive_queue); 174463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh opt->recv_sequence = (__u16)(meta->sequence + 1); 175463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_orphan(skb); 176463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh ppp_input(&pppox_sk(sk)->chan, skb); 177463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 178463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh return NET_RX_SUCCESS; 179463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh } 180463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh 181463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh /* Flush receive queue if sequencing is disabled. */ 182463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_queue_purge(&sk->sk_receive_queue); 18349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_orphan(skb); 18449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh ppp_input(&pppox_sk(sk)->chan, skb); 185c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh return NET_RX_SUCCESS; 18649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehdrop: 18749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh kfree_skb(skb); 188c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh return NET_RX_DROP; 189c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh} 190c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh 191c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yehstatic int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb) 192c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh{ 193c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sock_hold(sk_udp); 194c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_receive_skb(sk_udp, skb, 0); 19549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return 0; 19649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 19749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 198c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yehstatic struct sk_buff_head delivery_queue; 199c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh 200c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yehstatic void pppolac_xmit_core(struct work_struct *delivery_work) 201c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh{ 202c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh mm_segment_t old_fs = get_fs(); 203c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct sk_buff *skb; 204c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh 205c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh set_fs(KERNEL_DS); 206c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh while ((skb = skb_dequeue(&delivery_queue))) { 207c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct sock *sk_udp = skb->sk; 208c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; 209c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct msghdr msg = { 210c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh .msg_iov = (struct iovec *)&iov, 211c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh .msg_iovlen = 1, 212c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, 213c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh }; 214c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len); 215c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh kfree_skb(skb); 216c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh } 217c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh set_fs(old_fs); 218c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh} 219c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh 220c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yehstatic DECLARE_WORK(delivery_work, pppolac_xmit_core); 221c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh 22249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb) 22349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 22449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk_udp = (struct sock *)chan->private; 22549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac; 22649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 22749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Install PPP address and control. */ 22849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_push(skb, 2); 22949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[0] = PPP_ADDR; 23049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[1] = PPP_CTRL; 23149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 23249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Install L2TP header. */ 233463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh if (atomic_read(&opt->sequencing)) { 23449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_push(skb, 10); 235c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh skb->data[0] = L2TP_SEQUENCE_BIT; 236463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb->data[6] = opt->xmit_sequence >> 8; 237463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb->data[7] = opt->xmit_sequence; 23849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[8] = 0; 23949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[9] = 0; 240463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh opt->xmit_sequence++; 24149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } else { 24249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb_push(skb, 6); 24349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[0] = 0; 24449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 24549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh skb->data[1] = L2TP_VERSION; 24649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh unaligned(&skb->data[2])->u32 = opt->remote; 24749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 248c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh /* Now send the packet via the delivery queue. */ 249c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh skb_set_owner_w(skb, sk_udp); 250c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh skb_queue_tail(&delivery_queue, skb); 251c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh schedule_work(&delivery_work); 25249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return 1; 25349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 25449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 25549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh/******************************************************************************/ 25649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 25749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic struct ppp_channel_ops pppolac_channel_ops = { 25849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .start_xmit = pppolac_xmit, 25949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh}; 26049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 26149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic int pppolac_connect(struct socket *sock, struct sockaddr *useraddr, 26249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh int addrlen, int flags) 26349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 26449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk = sock->sk; 26549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct pppox_sock *po = pppox_sk(sk); 26649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sockaddr_pppolac *addr = (struct sockaddr_pppolac *)useraddr; 26749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct socket *sock_udp = NULL; 26849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk_udp; 26949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh int error; 27049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 27149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (addrlen != sizeof(struct sockaddr_pppolac) || 27249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh !addr->local.tunnel || !addr->local.session || 27349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh !addr->remote.tunnel || !addr->remote.session) { 27449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return -EINVAL; 27549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 27649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 27749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh lock_sock(sk); 27849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = -EALREADY; 27949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sk->sk_state != PPPOX_NONE) 28049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 28149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 28249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock_udp = sockfd_lookup(addr->udp_socket, &error); 28349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (!sock_udp) 28449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 28549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk_udp = sock_udp->sk; 28649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh lock_sock(sk_udp); 28749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 28849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh /* Remove this check when IPv6 supports UDP encapsulation. */ 28949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = -EAFNOSUPPORT; 29049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sk_udp->sk_family != AF_INET) 29149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 29249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = -EPROTONOSUPPORT; 29349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sk_udp->sk_protocol != IPPROTO_UDP) 29449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 29549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = -EDESTADDRREQ; 29649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sk_udp->sk_state != TCP_ESTABLISHED) 29749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 29849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = -EBUSY; 29949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (udp_sk(sk_udp)->encap_type || sk_udp->sk_user_data) 30049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 301c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (!sk_udp->sk_bound_dev_if) { 302c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh struct dst_entry *dst = sk_dst_get(sk_udp); 303c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh error = -ENODEV; 304c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh if (!dst) 305c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh goto out; 306c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_udp->sk_bound_dev_if = dst->dev->ifindex; 307c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh dst_release(dst); 308c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh } 30949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 31049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh po->chan.hdrlen = 12; 31149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh po->chan.private = sk_udp; 31249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh po->chan.ops = &pppolac_channel_ops; 313a6c61549be24ca408d691545ec8c3eaed9151cf6JP Abgrall po->chan.mtu = PPP_MRU - 80; 31449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh po->proto.lac.local = unaligned(&addr->local)->u32; 31549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh po->proto.lac.remote = unaligned(&addr->remote)->u32; 316463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh atomic_set(&po->proto.lac.sequencing, 1); 317c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv; 31849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 31949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = ppp_register_channel(&po->chan); 32049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (error) 32149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh goto out; 32249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 32349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk->sk_state = PPPOX_CONNECTED; 32449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP; 32549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh udp_sk(sk_udp)->encap_rcv = pppolac_recv; 326c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_udp->sk_backlog_rcv = pppolac_recv_core; 32749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk_udp->sk_user_data = sk; 32849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehout: 32949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sock_udp) { 33049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh release_sock(sk_udp); 33149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (error) 33249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sockfd_put(sock_udp); 33349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 33449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh release_sock(sk); 33549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return error; 33649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 33749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 33849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic int pppolac_release(struct socket *sock) 33949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 34049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk = sock->sk; 34149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 34249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (!sk) 34349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return 0; 34449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 34549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh lock_sock(sk); 34649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sock_flag(sk, SOCK_DEAD)) { 34749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh release_sock(sk); 34849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return -EBADF; 34949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 35049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 35149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (sk->sk_state != PPPOX_NONE) { 35249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private; 35349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh lock_sock(sk_udp); 354463ebc14ba6df67212ee2956b446eca88c419e1aChia-chi Yeh skb_queue_purge(&sk->sk_receive_queue); 35549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh pppox_unbind_sock(sk); 35649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh udp_sk(sk_udp)->encap_type = 0; 35749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh udp_sk(sk_udp)->encap_rcv = NULL; 358c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv; 359c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh sk_udp->sk_user_data = NULL; 36049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh release_sock(sk_udp); 36149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sockfd_put(sk_udp->sk_socket); 36249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh } 36349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 36449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock_orphan(sk); 36549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock->sk = NULL; 36649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh release_sock(sk); 36749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock_put(sk); 36849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return 0; 36949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 37049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 37149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh/******************************************************************************/ 37249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 37349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic struct proto pppolac_proto = { 37449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .name = "PPPOLAC", 37549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .owner = THIS_MODULE, 37649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .obj_size = sizeof(struct pppox_sock), 37749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh}; 37849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 37949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic struct proto_ops pppolac_proto_ops = { 38049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .family = PF_PPPOX, 38149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .owner = THIS_MODULE, 38249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .release = pppolac_release, 38349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .bind = sock_no_bind, 38449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .connect = pppolac_connect, 38549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .socketpair = sock_no_socketpair, 38649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .accept = sock_no_accept, 38749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .getname = sock_no_getname, 38849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .poll = sock_no_poll, 38949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .ioctl = pppox_ioctl, 39049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .listen = sock_no_listen, 39149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .shutdown = sock_no_shutdown, 39249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .setsockopt = sock_no_setsockopt, 39349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .getsockopt = sock_no_getsockopt, 39449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .sendmsg = sock_no_sendmsg, 39549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .recvmsg = sock_no_recvmsg, 39649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .mmap = sock_no_mmap, 39749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh}; 39849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 39949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic int pppolac_create(struct net *net, struct socket *sock) 40049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 40149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh struct sock *sk; 40249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 40349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppolac_proto); 40449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (!sk) 40549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return -ENOMEM; 40649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 40749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock_init_data(sock, sk); 40849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock->state = SS_UNCONNECTED; 40949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sock->ops = &pppolac_proto_ops; 41049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk->sk_protocol = PX_PROTO_OLAC; 41149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh sk->sk_state = PPPOX_NONE; 41249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return 0; 41349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 41449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 41549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh/******************************************************************************/ 41649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 41749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic struct pppox_proto pppolac_pppox_proto = { 41849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .create = pppolac_create, 41949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh .owner = THIS_MODULE, 42049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh}; 42149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 42249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic int __init pppolac_init(void) 42349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 42449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh int error; 42549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 42649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = proto_register(&pppolac_proto, 0); 42749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (error) 42849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return error; 42949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 43049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto); 43149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh if (error) 43249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh proto_unregister(&pppolac_proto); 433c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh else 434c54f674c656d66a27f555bdc85e122808f65d119Chia-chi Yeh skb_queue_head_init(&delivery_queue); 43549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh return error; 43649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 43749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 43849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehstatic void __exit pppolac_exit(void) 43949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh{ 44049c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh unregister_pppox_proto(PX_PROTO_OLAC); 44149c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh proto_unregister(&pppolac_proto); 44249c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh} 44349c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 44449c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehmodule_init(pppolac_init); 44549c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yehmodule_exit(pppolac_exit); 44649c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi Yeh 44749c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi YehMODULE_DESCRIPTION("PPP on L2TP Access Concentrator (PPPoLAC)"); 44849c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi YehMODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>"); 44949c48cb5388cb3b7aee62e1ea75381a033dd55dcChia-chi YehMODULE_LICENSE("GPL"); 450