ofono/gatchat/ppp_ipcp.c

241 lines
5.9 KiB
C
Raw Normal View History

/*
*
* 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"
#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))
struct ipcp_data {
guint8 ip_address[4];
guint8 primary_dns[4];
guint8 secondary_dns[4];
guint8 primary_nbns[4];
guint8 secondary_nbns[4];
};
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,
};
static void ipcp_up(struct pppcp_data *pppcp)
{
struct ipcp_data *data = pppcp_get_data(pppcp);
char ip[INET_ADDRSTRLEN];
char dns1[INET_ADDRSTRLEN];
char dns2[INET_ADDRSTRLEN];
struct in_addr addr;
memset(ip, 0, sizeof(ip));
addr.s_addr = __get_unaligned_long(data->ip_address);
inet_ntop(AF_INET, &addr, ip, INET_ADDRSTRLEN);
memset(dns1, 0, sizeof(dns1));
addr.s_addr = __get_unaligned_long(data->primary_dns);
inet_ntop(AF_INET, &addr, dns1, INET_ADDRSTRLEN);
memset(dns2, 0, sizeof(dns2));
addr.s_addr = __get_unaligned_long(data->secondary_dns);
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);
}
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)
{
pppcp_signal_up(data);
}
static void ipcp_finished(struct pppcp_data *data)
{
g_print("ipcp finished\n");
}
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) {
switch (ppp_option_iter_get_type(&iter)) {
case IP_ADDRESS:
memcpy(ipcp->ip_address,
ppp_option_iter_get_data(&iter), 4);
break;
default:
break;
}
}
}
/*
* Scan the option to see if it is acceptable, unacceptable, or rejected
*/
static guint ipcp_option_scan(struct pppcp_data *pppcp,
struct ppp_option *option)
{
switch (option->type) {
case IP_ADDRESS:
case PRIMARY_DNS_SERVER:
case PRIMARY_NBNS_SERVER:
case SECONDARY_DNS_SERVER:
case SECONDARY_NBNS_SERVER:
return OPTION_ACCEPT;
default:
g_printerr("Unknown ipcp option type %d\n", option->type);
return OPTION_REJECT;
}
}
/*
* act on an acceptable option
*/
static void ipcp_option_process(struct pppcp_data *pppcp,
struct ppp_option *option)
{
struct ipcp_data *ipcp = pppcp_get_data(pppcp);
switch (option->type) {
case PRIMARY_DNS_SERVER:
memcpy(ipcp->primary_dns, option->data, 4);
break;
case PRIMARY_NBNS_SERVER:
memcpy(ipcp->primary_nbns, option->data, 4);
break;
case SECONDARY_DNS_SERVER:
memcpy(ipcp->secondary_dns, option->data, 4);
break;
case SECONDARY_NBNS_SERVER:
memcpy(ipcp->secondary_nbns, option->data, 4);
break;
default:
g_printerr("Unable to process unknown option %d\n", option->type);
break;
}
}
static const char *ipcp_option_strings[256] = {
[IP_ADDRESSES] = "IP-Addresses (deprecated)",
[IP_COMPRESSION_PROTO] = "IP-Compression-Protocol",
[IP_ADDRESS] = "IP-Address",
[MOBILE_IPV4] = "Mobile-IPv4",
[PRIMARY_DNS_SERVER] = "Primary DNS Server Address",
[PRIMARY_NBNS_SERVER] = "Primary NBNS Server Address",
[SECONDARY_DNS_SERVER] = "Secondary DNS Server Address",
[SECONDARY_NBNS_SERVER] = "Secondary NBNS Server Address",
};
struct pppcp_proto ipcp_proto = {
.proto = IPCP_PROTO,
.name = "ipcp",
.supported_codes = IPCP_SUPPORTED_CODES,
.option_strings = ipcp_option_strings,
.this_layer_up = ipcp_up,
.this_layer_down = ipcp_down,
.this_layer_started = ipcp_started,
.this_layer_finished = ipcp_finished,
.rca = ipcp_rca,
.option_scan = ipcp_option_scan,
.option_process = ipcp_option_process,
};
struct pppcp_data *ipcp_new(GAtPPP *ppp)
{
2010-04-07 19:49:57 +00:00
struct ipcp_data *ipcp;
struct pppcp_data *pppcp;
struct ppp_option *ipcp_option;
2010-04-07 19:49:57 +00:00
ipcp = g_try_new0(struct ipcp_data, 1);
if (!ipcp)
return NULL;
pppcp = pppcp_new(ppp, &ipcp_proto);
if (!pppcp) {
g_printerr("Failed to allocate PPPCP struct\n");
2010-04-07 19:49:57 +00:00
g_free(ipcp);
return NULL;
}
2010-04-07 19:49:57 +00:00
pppcp_set_data(pppcp, ipcp);
/* add the default config options */
ipcp_option = g_try_malloc0(6);
if (!ipcp_option) {
2010-04-07 19:49:57 +00:00
ipcp_free(pppcp);
return NULL;
}
ipcp_option->type = IP_ADDRESS;
ipcp_option->length= 6;
pppcp_add_config_option(pppcp, ipcp_option);
return pppcp;
}
void ipcp_free(struct pppcp_data *data)
{
struct ipcp_data *ipcp = pppcp_get_data(data);
g_free(ipcp);
pppcp_free(data);
}