179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/*
279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * Copyright (C) 2009 The Android Open Source Project
379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh *
479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * you may not use this file except in compliance with the License.
679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * You may obtain a copy of the License at
779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh *
879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh *
1079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * See the License for the specific language governing permissions and
1479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * limitations under the License.
1579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh */
1679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
1779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/* A simple implementation of L2TP Access Concentrator (RFC 2661) which only
1879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * creates a single session. The following code only handles control packets.
1979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * Data packets are handled by PPPoLAC driver which can be found in Android
2079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * kernel tree. */
2179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
2279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <stdio.h>
2379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <stdlib.h>
2479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <string.h>
2579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <errno.h>
26f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh#include <fcntl.h>
2779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <sys/types.h>
2879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <sys/socket.h>
29f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh#include <sys/stat.h>
3079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include <arpa/inet.h>
310f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh#include <linux/netdevice.h>
320f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh#include <linux/if_pppox.h>
336c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#include <openssl/md5.h>
3479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
3579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#include "mtpd.h"
3679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
3779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/* To avoid unnecessary endianness conversions, tunnels, sessions, attributes,
3879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * and values are all accessed in network order. */
3979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
4079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/* 0 is reserved. We put ACK here just for convenience. */
4179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehenum l2tp_message {
4279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    ACK = 0,
4379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    SCCRQ = 1,
4479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    SCCRP = 2,
4579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    SCCCN = 3,
4679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    STOPCCN = 4,
4779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    HELLO = 6,
4879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    OCRQ = 7,
4979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    OCRP = 8,
5079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    OCCN = 9,
5179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    ICRQ = 10,
5279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    ICRP = 11,
5379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    ICCN = 12,
5479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    CDN = 14,
5579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    WEN = 15,
5679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    SLI = 16,
5779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    MESSAGE_MAX = 16,
5879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh};
5979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
6079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic char *messages[] = {
6179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    "ACK", "SCCRQ", "SCCRP", "SCCCN", "STOPCCN", NULL, "HELLO", "OCRQ",
6279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    "OCRP", "OCCN", "ICRQ", "ICRP", "ICCN", NULL, "CDN", "WEN", "SLI",
6379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh};
6479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
6579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/* This is incomplete. Only those we used are listed here. */
6679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define RESULT_CODE             htons(1)
6779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define PROTOCOL_VERSION        htons(2)
6879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define FRAMING_CAPABILITIES    htons(3)
6979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define HOST_NAME               htons(7)
7079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ASSIGNED_TUNNEL         htons(9)
7179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define WINDOW_SIZE             htons(10)
726c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#define CHALLENGE               htons(11)
736c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#define CHALLENGE_RESPONSE      htons(13)
7479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ASSIGNED_SESSION        htons(14)
7579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define CALL_SERIAL_NUMBER      htons(15)
7679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define FRAMING_TYPE            htons(19)
7779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define CONNECT_SPEED           htons(24)
786c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#define RANDOM_VECTOR           htons(36)
7979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
8079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define MESSAGE_FLAG            0xC802
8179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define MESSAGE_MASK            0xCB0F
8279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ATTRIBUTE_FLAG(length)  (0x8006 + (length))
8379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ATTRIBUTE_LENGTH(flag)  (0x03FF & (flag))
8479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ATTRIBUTE_HIDDEN(flag)  (0x4000 & (flag))
8579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
8679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ACK_SIZE                12
8779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define MESSAGE_HEADER_SIZE     20
8879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define ATTRIBUTE_HEADER_SIZE   6
896c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#define MAX_ATTRIBUTE_SIZE      1024
9079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
9179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t local_tunnel;
9279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t local_session;
9379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t local_sequence;
9479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t remote_tunnel;
9579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t remote_session;
9679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t remote_sequence;
9779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
9879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic uint16_t state;
9979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int acknowledged;
10079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
101e859c5e118db1c1cf219df1d0f0887ff46826bfbChia-chi Yeh#define RANDOM_DEVICE   "/dev/urandom"
1026c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh#define CHALLENGE_SIZE  32
1036c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
1046c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic char *secret;
1056c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic int secret_length;
1066c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic uint8_t challenge[CHALLENGE_SIZE];
1076c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
10879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh/* According to RFC 2661 page 46, an exponential backoff strategy is required
10979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * for retransmission. However, it might waste too much time waiting for IPsec
11079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh * negotiation. Here we use the same interval to keep things simple. */
11179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define TIMEOUT_INTERVAL 2000
11279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
11379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh#define MAX_PACKET_LENGTH 2048
11479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
11579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic struct packet {
11679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    int message;
11779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    int length;
118f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh    uint8_t buffer[MAX_PACKET_LENGTH] __attribute__((aligned(4)));
11979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh} incoming, outgoing;
12079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
12179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstruct attribute {
12279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t flag;
12379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t vendor;
12479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t type;
12579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint8_t value[1];
12679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh} __attribute__((packed));
12779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
12879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void set_message(uint16_t session, uint16_t message)
12979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
13079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t *p = (uint16_t *)outgoing.buffer;
13179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[0] = htons(MESSAGE_FLAG);
13279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* p[1] will be filled in send_packet(). */
13379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[2] = remote_tunnel;
13479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[3] = session;
13579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[4] = htons(local_sequence);
13679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[5] = htons(remote_sequence);
13779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[6] = htons(ATTRIBUTE_FLAG(2));
13879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[7] = 0;
13979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[8] = 0;
14079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[9] = htons(message);
14179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    outgoing.message = message;
14279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    outgoing.length = MESSAGE_HEADER_SIZE;
14379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    ++local_sequence;
14479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
14579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
14679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void add_attribute_raw(uint16_t type, void *value, int size)
14779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
14879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    struct attribute *p = (struct attribute *)&outgoing.buffer[outgoing.length];
14979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p->flag = htons(ATTRIBUTE_FLAG(size));
15079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p->vendor = 0;
15179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p->type = type;
15279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    memcpy(&p->value, value, size);
15379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    outgoing.length += ATTRIBUTE_HEADER_SIZE + size;
15479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
15579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
15679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void add_attribute_u16(uint16_t attribute, uint16_t value)
15779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
15879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_raw(attribute, &value, sizeof(uint16_t));
15979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
16079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
16179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void add_attribute_u32(uint16_t attribute, uint32_t value)
16279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
16379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_raw(attribute, &value, sizeof(uint32_t));
16479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
16579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
16679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void send_packet()
16779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
16879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t *p = (uint16_t *)outgoing.buffer;
16979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    p[1] = htons(outgoing.length);
17079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    send(the_socket, outgoing.buffer, outgoing.length, 0);
17179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    acknowledged = 0;
17279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
17379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
17479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void send_ack()
17579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
17679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t buffer[6] = {
17779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        htons(MESSAGE_FLAG), htons(ACK_SIZE), remote_tunnel, 0,
17879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        htons(local_sequence), htons(remote_sequence),
17979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    };
18079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    send(the_socket, buffer, ACK_SIZE, 0);
18179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
18279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
18379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int recv_packet(uint16_t *session)
18479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
18579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t *p = (uint16_t *)incoming.buffer;
18679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
18779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    incoming.length = recv(the_socket, incoming.buffer, MAX_PACKET_LENGTH, 0);
1887b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh    if (incoming.length == -1) {
1897b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh        if (errno == EINTR) {
1907b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh            return 0;
1917b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh        }
19279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        log_print(FATAL, "Recv() %s", strerror(errno));
19379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        exit(NETWORK_ERROR);
19479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
19579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
19679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* We only handle packets in our tunnel. */
19779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if ((incoming.length != ACK_SIZE && incoming.length < MESSAGE_HEADER_SIZE)
198ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh            || (p[0] & htons(MESSAGE_MASK)) != htons(MESSAGE_FLAG) ||
199ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh            ntohs(p[1]) != incoming.length || p[2] != local_tunnel) {
20079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return 0;
20179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
20279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
20379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (incoming.length == ACK_SIZE) {
20479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        incoming.message = ACK;
20579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    } else if (p[6] == htons(ATTRIBUTE_FLAG(2)) && !p[7] && !p[8]) {
20679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        incoming.message = ntohs(p[9]);
20779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    } else {
20879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return 0;
20979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
21079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
21179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* Check if the packet is duplicated and send ACK if necessary. */
21279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if ((uint16_t)(ntohs(p[4]) - remote_sequence) > 32767) {
21379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        if (incoming.message != ACK) {
21479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            send_ack();
21579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        }
21679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return 0;
21779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
21879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
21979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (ntohs(p[5]) == local_sequence) {
22079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        acknowledged = 1;
22179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
22279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
22379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* Our sending and receiving window sizes are both 1. Thus we only handle
22479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh     * this packet if it is their next one and they received our last one. */
22579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (ntohs(p[4]) != remote_sequence || !acknowledged) {
22679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return 0;
22779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
22879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    *session = p[3];
22979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (incoming.message != ACK) {
23079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        ++remote_sequence;
23179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
23279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return 1;
23379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
23479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
23579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int get_attribute_raw(uint16_t type, void *value, int size)
23679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
23779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    int offset = MESSAGE_HEADER_SIZE;
2386c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    uint8_t *vector = NULL;
2396c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    int vector_length = 0;
2406c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
24179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    while (incoming.length >= offset + ATTRIBUTE_HEADER_SIZE) {
24279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        struct attribute *p = (struct attribute *)&incoming.buffer[offset];
24379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        uint16_t flag = ntohs(p->flag);
24479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        int length = ATTRIBUTE_LENGTH(flag);
24579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
24679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        offset += length;
24779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        length -= ATTRIBUTE_HEADER_SIZE;
24879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        if (length < 0 || offset > incoming.length) {
24979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            break;
25079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        }
2516c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        if (p->vendor) {
2526c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            continue;
2536c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
2546c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        if (p->type != type) {
2556c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            if (p->type == RANDOM_VECTOR && !ATTRIBUTE_HIDDEN(flag)) {
2566c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                vector = p->value;
2576c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                vector_length = length;
2586c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            }
2596c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            continue;
2606c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
26179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
2626c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        if (!ATTRIBUTE_HIDDEN(flag)) {
26379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (size > length) {
26479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                size = length;
26579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
26679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            memcpy(value, p->value, size);
26779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            return size;
26879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        }
2696c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
270905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh        if (!secret || !vector || length < 2) {
2716c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            return 0;
2726c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        } else {
2736c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            uint8_t buffer[MAX_ATTRIBUTE_SIZE];
2746c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            uint8_t hash[MD5_DIGEST_LENGTH];
2756c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_CTX ctx;
276905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh            int i;
2776c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
2786c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_Init(&ctx);
2796c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_Update(&ctx, &type, sizeof(uint16_t));
2806c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_Update(&ctx, secret, secret_length);
2816c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_Update(&ctx, vector, vector_length);
2826c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            MD5_Final(hash, &ctx);
2836c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
284905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh            for (i = 0; i < length; ++i) {
285905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                int j = i % MD5_DIGEST_LENGTH;
286905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                if (i && !j) {
287905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                    MD5_Init(&ctx);
288905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                    MD5_Update(&ctx, secret, secret_length);
289905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                    MD5_Update(&ctx, &p->value[i - MD5_DIGEST_LENGTH],
290905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                        MD5_DIGEST_LENGTH);
291905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                    MD5_Final(hash, &ctx);
2926c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                }
293905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh                buffer[i] = p->value[i] ^ hash[j];
2946c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            }
2956c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
2966c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            length = buffer[0] << 8 | buffer[1];
297905c2d0116da949bbbee4caed9958e774f00e0d3Chia-chi Yeh            if (length > i - 2) {
2986c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                return 0;
2996c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            }
3006c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            if (size > length) {
3016c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                size = length;
3026c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            }
3036c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            memcpy(value, &buffer[2], size);
3046c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            return size;
3056c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
30679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
30779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return 0;
30879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
30979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
31079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int get_attribute_u16(uint16_t type, uint16_t *value)
31179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
31279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return get_attribute_raw(type, value, sizeof(uint16_t)) == sizeof(uint16_t);
31379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
31479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
3157b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yehstatic int l2tp_connect(char **arguments)
31679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
3177b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh    create_socket(AF_INET, SOCK_DGRAM, arguments[0], arguments[1]);
31879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
31979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    while (!local_tunnel) {
32079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        local_tunnel = random();
32179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
32279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
32379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    log_print(DEBUG, "Sending SCCRQ (local_tunnel = %d)", local_tunnel);
32479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    state = SCCRQ;
32579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    set_message(0, SCCRQ);
32679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_u16(PROTOCOL_VERSION, htons(0x0100));
32779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_raw(HOST_NAME, "anonymous", 9);
32879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_u32(FRAMING_CAPABILITIES, htonl(3));
32979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_u16(ASSIGNED_TUNNEL, local_tunnel);
33079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    add_attribute_u16(WINDOW_SIZE, htons(1));
3316c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
3327b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh    if (arguments[2][0]) {
333f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh        int fd = open(RANDOM_DEVICE, O_RDONLY);
334f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh        if (fd == -1 || read(fd, challenge, CHALLENGE_SIZE) != CHALLENGE_SIZE) {
335e859c5e118db1c1cf219df1d0f0887ff46826bfbChia-chi Yeh            log_print(FATAL, "Cannot read %s", RANDOM_DEVICE);
336e859c5e118db1c1cf219df1d0f0887ff46826bfbChia-chi Yeh            exit(SYSTEM_ERROR);
3376c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
338f096f5babf211732dbf00c16f22fdfde82dfd43eChia-chi Yeh        close(fd);
339e859c5e118db1c1cf219df1d0f0887ff46826bfbChia-chi Yeh
3406c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        add_attribute_raw(CHALLENGE, challenge, CHALLENGE_SIZE);
3417b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh        secret = arguments[2];
3427b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh        secret_length = strlen(arguments[2]);
3436c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    }
3446c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
34579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    send_packet();
34679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return TIMEOUT_INTERVAL;
34779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
34879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
3490f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yehstatic int create_pppox()
35079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
3510f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh    int pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OLAC);
35279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    log_print(INFO, "Creating PPPoX socket");
35379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
35479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (pppox == -1) {
35579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        log_print(FATAL, "Socket() %s", strerror(errno));
3560f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh        exit(SYSTEM_ERROR);
35779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    } else {
35879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        struct sockaddr_pppolac address = {
35979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            .sa_family = AF_PPPOX,
3600f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh            .sa_protocol = PX_PROTO_OLAC,
36179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            .udp_socket = the_socket,
36279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            .local = {.tunnel = local_tunnel, .session = local_session},
36379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            .remote = {.tunnel = remote_tunnel, .session = remote_session},
36479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        };
365ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh        if (connect(pppox, (struct sockaddr *)&address, sizeof(address))) {
36679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            log_print(FATAL, "Connect() %s", strerror(errno));
3670f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh            exit(SYSTEM_ERROR);
36879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        }
36979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
37079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return pppox;
37179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
37279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
3736c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic uint8_t *compute_response(uint8_t type, void *challenge, int size)
3746c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh{
3756c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    static uint8_t response[MD5_DIGEST_LENGTH];
3766c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_CTX ctx;
3776c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_Init(&ctx);
3786c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_Update(&ctx, &type, sizeof(uint8_t));
3796c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_Update(&ctx, secret, secret_length);
3806c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_Update(&ctx, challenge, size);
3816c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    MD5_Final(response, &ctx);
3826c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    return response;
3836c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh}
3846c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
3856c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic int verify_challenge()
3866c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh{
3876c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    if (secret) {
3886c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        uint8_t response[MD5_DIGEST_LENGTH];
3896c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        if (get_attribute_raw(CHALLENGE_RESPONSE, response, MD5_DIGEST_LENGTH)
390ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                != MD5_DIGEST_LENGTH) {
3916c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            return 0;
3926c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
3936c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        return !memcmp(compute_response(SCCRP, challenge, CHALLENGE_SIZE),
394ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                response, MD5_DIGEST_LENGTH);
3956c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    }
3966c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    return 1;
3976c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh}
3986c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
3996c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yehstatic void answer_challenge()
4006c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh{
4016c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    if (secret) {
4026c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        uint8_t challenge[MAX_ATTRIBUTE_SIZE];
4036c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        int size = get_attribute_raw(CHALLENGE, challenge, MAX_ATTRIBUTE_SIZE);
4046c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        if (size > 0) {
4056c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            uint8_t *response = compute_response(SCCCN, challenge, size);
4066c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh            add_attribute_raw(CHALLENGE_RESPONSE, response, MD5_DIGEST_LENGTH);
4076c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh        }
4086c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    }
4096c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh}
4106c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh
41179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int l2tp_process()
41279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
41379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    uint16_t sequence = local_sequence;
4146c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    uint16_t tunnel = 0;
4156c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh    uint16_t session = 0;
41679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
41779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (!recv_packet(&session)) {
41879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return acknowledged ? 0 : TIMEOUT_INTERVAL;
41979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
42079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
42179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* Here is the fun part. We always try to protect our tunnel and session
42279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh     * from being closed even if we received unexpected messages. */
42379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    switch(incoming.message) {
42479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case SCCRP:
42579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (state == SCCRQ) {
426ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                if (get_attribute_u16(ASSIGNED_TUNNEL, &tunnel) && tunnel &&
427ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                        verify_challenge()) {
42879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    remote_tunnel = tunnel;
42979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    log_print(DEBUG, "Received SCCRP (remote_tunnel = %d) -> "
430ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                            "Sending SCCCN", remote_tunnel);
43179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    state = SCCCN;
43279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    set_message(0, SCCCN);
433440221128bf7a17d788be5caeefb0e7e1c89e95ashimizu.junichi                    answer_challenge();
43479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    break;
43579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                }
4366c0e6ee6cf1cd6dda611adbc61766b2405416107Chia-chi Yeh                log_print(DEBUG, "Received SCCRP without %s", tunnel ?
437ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                        "valid challenge response" : "assigned tunnel");
43879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(ERROR, "Protocol error");
439e859c5e118db1c1cf219df1d0f0887ff46826bfbChia-chi Yeh                return tunnel ? -CHALLENGE_FAILED : -PROTOCOL_ERROR;
44079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
44179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            break;
44279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
44379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case ICRP:
44479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (state == ICRQ && session == local_session) {
44579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) {
44679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    remote_session = session;
44779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    log_print(DEBUG, "Received ICRP (remote_session = %d) -> "
448ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                            "Sending ICCN", remote_session);
44979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    state = ICCN;
45079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    set_message(remote_session, ICCN);
45179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    add_attribute_u32(CONNECT_SPEED, htonl(100000000));
45279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    add_attribute_u32(FRAMING_TYPE, htonl(3));
45379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    break;
45479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                }
45579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received ICRP without assigned session");
45679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(ERROR, "Protocol error");
45779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                return -PROTOCOL_ERROR;
45879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
45979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            break;
46079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
46179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case STOPCCN:
46279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            log_print(DEBUG, "Received STOPCCN");
46379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            log_print(INFO, "Remote server hung up");
46479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            state = STOPCCN;
46579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            return -REMOTE_REQUESTED;
46679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
46779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case CDN:
46879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (session && session == local_session) {
46979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received CDN (local_session = %d)",
470ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                        local_session);
47179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(INFO, "Remote server hung up");
47279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                return -REMOTE_REQUESTED;
47379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
47479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            break;
47579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
47679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case ACK:
47779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case HELLO:
47879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case WEN:
47979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case SLI:
480ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh            /* These are harmless, so we just treat them in the same way. */
48179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (state == SCCCN) {
48279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                while (!local_session) {
48379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                    local_session = random();
48479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                }
48579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received %s -> Sending ICRQ (local_session = "
486ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                        "%d)", messages[incoming.message], local_session);
48779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(INFO, "Tunnel established");
48879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                state = ICRQ;
48979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                set_message(0, ICRQ);
49079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                add_attribute_u16(ASSIGNED_SESSION, local_session);
49179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                add_attribute_u32(CALL_SERIAL_NUMBER, random());
49279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                break;
49379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
49479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
49579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (incoming.message == ACK) {
49679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received ACK");
49779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            } else {
49879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received %s -> Sending ACK",
49979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                          messages[incoming.message]);
50079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                send_ack();
50179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
50279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
50379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (state == ICCN) {
50479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(INFO, "Session established");
50579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                state = ACK;
50679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                start_pppd(create_pppox());
50779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
50879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            return 0;
50979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
51079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case ICRQ:
51179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        case OCRQ:
51279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            /* Since we run pppd as a client, it does not makes sense to
51379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh             * accept ICRQ or OCRQ. Always send CDN with a proper error. */
51479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) {
51579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                log_print(DEBUG, "Received %s (remote_session = %d) -> "
516ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh                        "Sending CDN", messages[incoming.message], session);
51779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                set_message(session, CDN);
51879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                add_attribute_u32(RESULT_CODE, htonl(0x00020006));
51979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                add_attribute_u16(ASSIGNED_SESSION, 0);
52079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            }
52179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh            break;
52279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
52379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
52479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (sequence != local_sequence) {
52579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        send_packet();
52679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return TIMEOUT_INTERVAL;
52779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
52879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
52979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    /* We reach here if we got an unexpected message. Log it and send ACK. */
53079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (incoming.message > MESSAGE_MAX || !messages[incoming.message]) {
53179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        log_print(DEBUG, "Received UNKNOWN %d -> Sending ACK anyway",
53279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                incoming.message);
53379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    } else {
53479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        log_print(DEBUG, "Received UNEXPECTED %s -> Sending ACK anyway",
53579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh                messages[incoming.message]);
53679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
53779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    send_ack();
53879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return 0;
53979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
54079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
54179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic int l2tp_timeout()
54279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
54379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (acknowledged) {
54479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        return 0;
54579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
54679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    log_print(DEBUG, "Timeout -> Sending %s", messages[outgoing.message]);
54779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    send(the_socket, outgoing.buffer, outgoing.length, 0);
54879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    return TIMEOUT_INTERVAL;
54979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
55079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
55179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstatic void l2tp_shutdown()
55279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh{
55379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    if (state != STOPCCN) {
55479e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        log_print(DEBUG, "Sending STOPCCN");
55579e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        set_message(0, STOPCCN);
55679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        add_attribute_u16(ASSIGNED_TUNNEL, local_tunnel);
55779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        add_attribute_u16(RESULT_CODE, htons(6));
55879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh        send_packet();
55979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    }
56079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh}
56179e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh
56279e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yehstruct protocol l2tp = {
56379e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    .name = "l2tp",
5647b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh    .arguments = 3,
5657b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh    .usage = "<server> <port> <secret>",
56679e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    .connect = l2tp_connect,
56779e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    .process = l2tp_process,
56879e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    .timeout = l2tp_timeout,
56979e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh    .shutdown = l2tp_shutdown,
57079e6232ffa3765d3352e01e2b7887b6425c7c655Chia-chi Yeh};
571