2010-04-02 17:42:04 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* PPP library with GLib integration
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include "gatutil.h"
|
|
|
|
#include "gatppp.h"
|
|
|
|
#include "ppp.h"
|
|
|
|
|
2010-04-05 21:16:14 +00:00
|
|
|
#define IPCP_SUPPORTED_CODES ((1 << PPPCP_CODE_TYPE_CONFIGURE_REQUEST) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_CONFIGURE_ACK) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_CONFIGURE_NAK) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_CONFIGURE_REJECT) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_TERMINATE_REQUEST) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_TERMINATE_ACK) | \
|
|
|
|
(1 << PPPCP_CODE_TYPE_CODE_REJECT))
|
|
|
|
|
2010-04-02 17:42:04 +00:00
|
|
|
enum ipcp_option_types {
|
|
|
|
IP_ADDRESSES = 1,
|
|
|
|
IP_COMPRESSION_PROTO = 2,
|
|
|
|
IP_ADDRESS = 3,
|
|
|
|
MOBILE_IPV4 = 4,
|
|
|
|
PRIMARY_DNS_SERVER = 129,
|
|
|
|
PRIMARY_NBNS_SERVER = 130,
|
|
|
|
SECONDARY_DNS_SERVER = 131,
|
|
|
|
SECONDARY_NBNS_SERVER = 132,
|
|
|
|
};
|
|
|
|
|
2010-04-08 21:41:44 +00:00
|
|
|
/* We request IP_ADDRESS, PRIMARY/SECONDARY DNS & NBNS */
|
|
|
|
#define MAX_CONFIG_OPTION_SIZE 5*6
|
|
|
|
|
2010-04-09 13:55:16 +00:00
|
|
|
#define REQ_OPTION_IPADDR 0x01
|
|
|
|
#define REQ_OPTION_DNS1 0x02
|
|
|
|
#define REQ_OPTION_DNS2 0x04
|
|
|
|
#define REQ_OPTION_NBNS1 0x08
|
|
|
|
#define REQ_OPTION_NBNS2 0x10
|
|
|
|
|
2010-04-08 21:41:44 +00:00
|
|
|
struct ipcp_data {
|
|
|
|
guint8 options[MAX_CONFIG_OPTION_SIZE];
|
|
|
|
guint16 options_len;
|
2010-04-09 13:55:16 +00:00
|
|
|
guint8 req_options;
|
2010-04-08 21:41:44 +00:00
|
|
|
guint32 ipaddr;
|
|
|
|
guint32 dns1;
|
|
|
|
guint32 dns2;
|
|
|
|
guint32 nbns1;
|
|
|
|
guint32 nbns2;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define FILL_IP(req, type, var) \
|
|
|
|
if (req) { \
|
|
|
|
ipcp->options[len] = type; \
|
|
|
|
ipcp->options[len + 1] = 6; \
|
|
|
|
memcpy(ipcp->options + len + 2, var, 4); \
|
|
|
|
\
|
|
|
|
len += 6; \
|
|
|
|
} \
|
|
|
|
|
|
|
|
static void ipcp_generate_config_options(struct ipcp_data *ipcp)
|
|
|
|
{
|
|
|
|
guint16 len = 0;
|
|
|
|
|
2010-04-09 13:55:16 +00:00
|
|
|
FILL_IP(ipcp->req_options & REQ_OPTION_IPADDR,
|
|
|
|
IP_ADDRESS, &ipcp->ipaddr);
|
|
|
|
FILL_IP(ipcp->req_options & REQ_OPTION_DNS1,
|
|
|
|
PRIMARY_DNS_SERVER, &ipcp->dns1);
|
|
|
|
FILL_IP(ipcp->req_options & REQ_OPTION_DNS2,
|
|
|
|
SECONDARY_DNS_SERVER, &ipcp->dns2);
|
|
|
|
FILL_IP(ipcp->req_options & REQ_OPTION_NBNS1,
|
|
|
|
PRIMARY_NBNS_SERVER, &ipcp->nbns1);
|
|
|
|
FILL_IP(ipcp->req_options & REQ_OPTION_NBNS2,
|
|
|
|
SECONDARY_NBNS_SERVER, &ipcp->nbns2);
|
2010-04-08 21:41:44 +00:00
|
|
|
|
|
|
|
ipcp->options_len = len;
|
|
|
|
}
|
|
|
|
|
2010-04-02 17:42:04 +00:00
|
|
|
static void ipcp_up(struct pppcp_data *pppcp)
|
|
|
|
{
|
2010-04-08 21:41:44 +00:00
|
|
|
struct ipcp_data *ipcp = pppcp_get_data(pppcp);
|
2010-04-02 17:42:04 +00:00
|
|
|
char ip[INET_ADDRSTRLEN];
|
|
|
|
char dns1[INET_ADDRSTRLEN];
|
|
|
|
char dns2[INET_ADDRSTRLEN];
|
|
|
|
struct in_addr addr;
|
|
|
|
|
|
|
|
memset(ip, 0, sizeof(ip));
|
2010-04-08 21:41:44 +00:00
|
|
|
addr.s_addr = ipcp->ipaddr;
|
2010-04-02 17:42:04 +00:00
|
|
|
inet_ntop(AF_INET, &addr, ip, INET_ADDRSTRLEN);
|
|
|
|
|
|
|
|
memset(dns1, 0, sizeof(dns1));
|
2010-04-08 21:41:44 +00:00
|
|
|
addr.s_addr = ipcp->dns1;
|
2010-04-02 17:42:04 +00:00
|
|
|
inet_ntop(AF_INET, &addr, dns1, INET_ADDRSTRLEN);
|
|
|
|
|
|
|
|
memset(dns2, 0, sizeof(dns2));
|
2010-04-08 21:41:44 +00:00
|
|
|
addr.s_addr = ipcp->dns2;
|
2010-04-02 17:42:04 +00:00
|
|
|
inet_ntop(AF_INET, &addr, dns2, INET_ADDRSTRLEN);
|
|
|
|
|
2010-04-05 21:44:00 +00:00
|
|
|
ppp_connect_cb(pppcp_get_ppp(pppcp), G_AT_PPP_CONNECT_SUCCESS,
|
2010-04-04 05:25:09 +00:00
|
|
|
ip[0] ? ip : NULL,
|
|
|
|
dns1[0] ? dns1 : NULL,
|
|
|
|
dns2[0] ? dns2 : NULL);
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ipcp_down(struct pppcp_data *data)
|
|
|
|
{
|
|
|
|
g_print("ipcp down\n");
|
|
|
|
|
|
|
|
/* re-add what default config options we want negotiated */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tell the protocol to start the handshake
|
|
|
|
*/
|
|
|
|
static void ipcp_started(struct pppcp_data *data)
|
|
|
|
{
|
2010-04-05 18:05:08 +00:00
|
|
|
pppcp_signal_up(data);
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ipcp_finished(struct pppcp_data *data)
|
|
|
|
{
|
|
|
|
g_print("ipcp finished\n");
|
|
|
|
}
|
|
|
|
|
2010-04-07 21:40:49 +00:00
|
|
|
static void ipcp_rca(struct pppcp_data *pppcp,
|
|
|
|
const struct pppcp_packet *packet)
|
|
|
|
{
|
|
|
|
struct ipcp_data *ipcp = pppcp_get_data(pppcp);
|
|
|
|
struct ppp_option_iter iter;
|
|
|
|
|
|
|
|
ppp_option_iter_init(&iter, packet);
|
|
|
|
|
|
|
|
while (ppp_option_iter_next(&iter) == TRUE) {
|
2010-04-08 21:41:44 +00:00
|
|
|
const guint8 *data = ppp_option_iter_get_data(&iter);
|
|
|
|
|
2010-04-07 21:40:49 +00:00
|
|
|
switch (ppp_option_iter_get_type(&iter)) {
|
|
|
|
case IP_ADDRESS:
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->ipaddr, data, 4);
|
|
|
|
break;
|
|
|
|
case PRIMARY_DNS_SERVER:
|
|
|
|
memcpy(&ipcp->dns1, data, 4);
|
|
|
|
break;
|
|
|
|
case PRIMARY_NBNS_SERVER:
|
|
|
|
memcpy(&ipcp->nbns1, data, 4);
|
|
|
|
break;
|
|
|
|
case SECONDARY_DNS_SERVER:
|
|
|
|
memcpy(&ipcp->dns2, data, 4);
|
|
|
|
break;
|
|
|
|
case SECONDARY_NBNS_SERVER:
|
|
|
|
memcpy(&ipcp->nbns2, data, 4);
|
2010-04-07 21:40:49 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-08 21:41:44 +00:00
|
|
|
static void ipcp_rcn_nak(struct pppcp_data *pppcp,
|
|
|
|
const struct pppcp_packet *packet)
|
2010-04-02 17:42:04 +00:00
|
|
|
{
|
2010-04-08 21:41:44 +00:00
|
|
|
struct ipcp_data *ipcp = pppcp_get_data(pppcp);
|
|
|
|
struct ppp_option_iter iter;
|
|
|
|
|
|
|
|
g_print("Received IPCP NAK\n");
|
|
|
|
|
|
|
|
ppp_option_iter_init(&iter, packet);
|
|
|
|
|
|
|
|
while (ppp_option_iter_next(&iter) == TRUE) {
|
|
|
|
const guint8 *data = ppp_option_iter_get_data(&iter);
|
|
|
|
|
|
|
|
switch (ppp_option_iter_get_type(&iter)) {
|
|
|
|
case IP_ADDRESS:
|
|
|
|
g_print("Setting suggested ip addr\n");
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options |= REQ_OPTION_IPADDR;
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->ipaddr, data, 4);
|
|
|
|
break;
|
|
|
|
case PRIMARY_DNS_SERVER:
|
|
|
|
g_print("Setting suggested dns1\n");
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options |= REQ_OPTION_DNS1;
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->dns1, data, 4);
|
|
|
|
break;
|
|
|
|
case PRIMARY_NBNS_SERVER:
|
|
|
|
g_print("Setting suggested nbns1\n");
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options |= REQ_OPTION_NBNS1;
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->nbns1, data, 4);
|
|
|
|
break;
|
|
|
|
case SECONDARY_DNS_SERVER:
|
|
|
|
g_print("Setting suggested dns2\n");
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options |= REQ_OPTION_DNS2;
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->dns2, data, 4);
|
|
|
|
break;
|
|
|
|
case SECONDARY_NBNS_SERVER:
|
|
|
|
g_print("Setting suggested nbns2\n");
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options |= REQ_OPTION_NBNS2;
|
2010-04-08 21:41:44 +00:00
|
|
|
memcpy(&ipcp->nbns2, data, 4);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
2010-04-08 21:41:44 +00:00
|
|
|
|
|
|
|
ipcp_generate_config_options(ipcp);
|
|
|
|
pppcp_set_local_options(pppcp, ipcp->options, ipcp->options_len);
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
|
|
|
|
2010-04-08 21:41:44 +00:00
|
|
|
static void ipcp_rcn_rej(struct pppcp_data *pppcp,
|
|
|
|
const struct pppcp_packet *packet)
|
2010-04-02 17:42:04 +00:00
|
|
|
{
|
2010-04-05 19:16:00 +00:00
|
|
|
struct ipcp_data *ipcp = pppcp_get_data(pppcp);
|
2010-04-08 21:41:44 +00:00
|
|
|
struct ppp_option_iter iter;
|
2010-04-02 17:42:04 +00:00
|
|
|
|
2010-04-08 21:41:44 +00:00
|
|
|
ppp_option_iter_init(&iter, packet);
|
|
|
|
|
|
|
|
while (ppp_option_iter_next(&iter) == TRUE) {
|
|
|
|
switch (ppp_option_iter_get_type(&iter)) {
|
|
|
|
case IP_ADDRESS:
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options &= ~REQ_OPTION_IPADDR;
|
2010-04-08 21:41:44 +00:00
|
|
|
break;
|
|
|
|
case PRIMARY_DNS_SERVER:
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options &= ~REQ_OPTION_DNS1;
|
2010-04-08 21:41:44 +00:00
|
|
|
break;
|
|
|
|
case PRIMARY_NBNS_SERVER:
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options &= ~REQ_OPTION_NBNS1;
|
2010-04-08 21:41:44 +00:00
|
|
|
break;
|
|
|
|
case SECONDARY_DNS_SERVER:
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options &= ~REQ_OPTION_DNS2;
|
2010-04-08 21:41:44 +00:00
|
|
|
break;
|
|
|
|
case SECONDARY_NBNS_SERVER:
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options &= ~REQ_OPTION_NBNS2;
|
2010-04-08 21:41:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
2010-04-08 21:41:44 +00:00
|
|
|
|
|
|
|
ipcp_generate_config_options(ipcp);
|
|
|
|
pppcp_set_local_options(pppcp, ipcp->options, ipcp->options_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum rcr_result ipcp_rcr(struct pppcp_data *pppcp,
|
|
|
|
const struct pppcp_packet *packet,
|
|
|
|
guint8 **new_options, guint16 *new_len)
|
|
|
|
{
|
|
|
|
struct ppp_option_iter iter;
|
|
|
|
|
|
|
|
ppp_option_iter_init(&iter, packet);
|
|
|
|
|
|
|
|
if (ppp_option_iter_next(&iter) == FALSE)
|
|
|
|
return RCR_ACCEPT;
|
|
|
|
|
|
|
|
/* Reject all options */
|
|
|
|
*new_len = packet->length - sizeof(*packet);
|
|
|
|
*new_options = g_memdup(packet->data, *new_len);
|
|
|
|
|
|
|
|
return RCR_REJECT;
|
2010-04-02 17:42:04 +00:00
|
|
|
}
|
|
|
|
|
2010-04-08 15:39:00 +00:00
|
|
|
struct pppcp_proto ipcp_proto = {
|
|
|
|
.proto = IPCP_PROTO,
|
|
|
|
.name = "ipcp",
|
|
|
|
.supported_codes = IPCP_SUPPORTED_CODES,
|
|
|
|
.this_layer_up = ipcp_up,
|
|
|
|
.this_layer_down = ipcp_down,
|
|
|
|
.this_layer_started = ipcp_started,
|
|
|
|
.this_layer_finished = ipcp_finished,
|
|
|
|
.rca = ipcp_rca,
|
2010-04-08 21:41:44 +00:00
|
|
|
.rcn_nak = ipcp_rcn_nak,
|
|
|
|
.rcn_rej = ipcp_rcn_rej,
|
|
|
|
.rcr = ipcp_rcr,
|
2010-04-08 15:39:00 +00:00
|
|
|
};
|
|
|
|
|
2010-04-02 17:42:04 +00:00
|
|
|
struct pppcp_data *ipcp_new(GAtPPP *ppp)
|
|
|
|
{
|
2010-04-07 19:49:57 +00:00
|
|
|
struct ipcp_data *ipcp;
|
2010-04-02 17:42:04 +00:00
|
|
|
struct pppcp_data *pppcp;
|
|
|
|
|
2010-04-07 19:49:57 +00:00
|
|
|
ipcp = g_try_new0(struct ipcp_data, 1);
|
|
|
|
if (!ipcp)
|
2010-04-02 17:42:04 +00:00
|
|
|
return NULL;
|
|
|
|
|
2010-04-08 15:39:00 +00:00
|
|
|
pppcp = pppcp_new(ppp, &ipcp_proto);
|
2010-04-02 17:42:04 +00:00
|
|
|
if (!pppcp) {
|
|
|
|
g_printerr("Failed to allocate PPPCP struct\n");
|
2010-04-07 19:49:57 +00:00
|
|
|
g_free(ipcp);
|
2010-04-02 17:42:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-04-05 18:12:43 +00:00
|
|
|
|
2010-04-07 19:49:57 +00:00
|
|
|
pppcp_set_data(pppcp, ipcp);
|
2010-04-02 17:42:04 +00:00
|
|
|
|
2010-04-09 13:55:16 +00:00
|
|
|
ipcp->req_options = REQ_OPTION_IPADDR | REQ_OPTION_DNS1 |
|
|
|
|
REQ_OPTION_DNS2 | REQ_OPTION_NBNS1 |
|
|
|
|
REQ_OPTION_NBNS2;
|
2010-04-08 21:41:44 +00:00
|
|
|
|
|
|
|
ipcp_generate_config_options(ipcp);
|
|
|
|
pppcp_set_local_options(pppcp, ipcp->options, ipcp->options_len);
|
2010-04-02 17:42:04 +00:00
|
|
|
|
|
|
|
return pppcp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ipcp_free(struct pppcp_data *data)
|
|
|
|
{
|
2010-04-05 19:16:00 +00:00
|
|
|
struct ipcp_data *ipcp = pppcp_get_data(data);
|
2010-04-02 17:42:04 +00:00
|
|
|
|
|
|
|
g_free(ipcp);
|
|
|
|
pppcp_free(data);
|
|
|
|
}
|