#include <string.h>
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "ppp_msg.h"
#include "ppp_privmsg.h"
#include "ppp_client.h"
#include "ppp_option.h"
#include "ppp_command.h"
#include "ppp_manager.h"
u_long set_long_opt (struct opt_long *option, u_long opt, u_long mini, u_long maxi, u_long limit)
{
if (opt < mini) {
if (limit) opt = mini;
else return EINVAL;
}
else if (opt > maxi) {
if (limit) opt = maxi;
else return EINVAL;
}
option->set = 1;
option->val = opt;
return 0;
}
u_long set_str_opt (struct opt_str *option, char *opt, int len)
{
if (len < OPT_STR_LEN) {
option->set = 1;
strncpy(option->str, opt, len);
option->str[len] = 0;
return 0;
}
return EMSGSIZE;
}
u_long ppp_setoption (struct client *client, struct msg *msg)
{
struct ppp_opt *opt = (struct ppp_opt *)&msg->data[MSG_DATAOFF(msg)];
struct options *opts;
u_long err = 0, len = msg->hdr.m_len - sizeof(struct ppp_opt_hdr);
u_long speed;
struct ppp *ppp = ppp_find(msg);
if (!ppp) {
msg->hdr.m_result = ENODEV;
msg->hdr.m_len = 0;
return 0;
}
opts = client_findoptset(client, ppp_makeref(ppp));
if (!opts) {
opts = client_newoptset(client, ppp_makeref(ppp));
if (!opts) {
msg->hdr.m_result = ENOMEM;
msg->hdr.m_len = 0;
return 0;
}
}
switch (opt->o_type) {
case PPP_OPT_DEV_NAME:
err = set_str_opt(&opts->dev.name, &opt->o_data[0], len);
break;
case PPP_OPT_DEV_SPEED:
speed = *(u_long *)(&opt->o_data[0]);
if (speed <= 1200) speed = 1200;
else if ((speed > 1200) && (speed <= 2400)) speed = 2400;
else if ((speed > 2400) && (speed <= 9600)) speed = 9600;
else if ((speed > 9600) && (speed <= 19200)) speed = 19200;
else if ((speed > 19200) && (speed <= 38400)) speed = 38400;
else if ((speed > 38400) && (speed <= 57600)) speed = 57600;
else if ((speed > 38400) && (speed <= 57600)) speed = 57600;
else if ((speed > 57600) && (speed <= 0xFFFFFFFF)) speed = 115200;
err = set_long_opt(&opts->dev.speed, speed, 0, 0xFFFFFFFF, 0);
break;
case PPP_OPT_DEV_CONNECTSCRIPT:
err = set_str_opt(&opts->dev.connectscript, &opt->o_data[0], len);
break;
case PPP_OPT_DEV_DIALMODE:
err = set_long_opt(&opts->dev.dialmode, *(u_long *)(&opt->o_data[0]),
PPP_DEV_WAITFORDIALTONE, PPP_DEV_MANUALDIAL, 0);
break;
case PPP_OPT_COMM_TERMINALMODE:
err = set_long_opt(&opts->comm.terminalmode, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_COMM_TERMINALSCRIPT:
err = set_str_opt(&opts->comm.terminalscript, &opt->o_data[0], len);
break;
case PPP_OPT_COMM_REMOTEADDR:
err = set_str_opt(&opts->comm.remoteaddr, &opt->o_data[0], len);
break;
case PPP_OPT_COMM_IDLETIMER:
err = set_long_opt(&opts->comm.idletimer, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_COMM_SESSIONTIMER:
err = set_long_opt(&opts->comm.sessiontimer, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_COMM_CONNECTDELAY:
err = set_long_opt(&opts->comm.connectdelay, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LCP_HDRCOMP:
err = set_long_opt(&opts->lcp.pcomp, ((*(u_long *)(&opt->o_data[0])) & PPP_LCP_HDRCOMP_PROTO) ? 1 : 0, 0, 1, 1);
if (!err)
err = set_long_opt(&opts->lcp.accomp, ((*(u_long *)(&opt->o_data[0])) & PPP_LCP_HDRCOMP_ADDR) ? 1 : 0, 0, 1, 1);
break;
case PPP_OPT_LCP_MRU:
err = set_long_opt(&opts->lcp.mru, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LCP_MTU:
err = set_long_opt(&opts->lcp.mtu, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LCP_RCACCM:
err = set_long_opt(&opts->lcp.rcaccm, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LCP_TXACCM:
err = set_long_opt(&opts->lcp.txaccm, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LCP_ECHO:
err = set_long_opt(&opts->lcp.echointerval, ((struct ppp_opt_echo *)opt->o_data)->interval, 0, 0xFFFFFFFF, 1);
err = set_long_opt(&opts->lcp.echofailure, ((struct ppp_opt_echo *)opt->o_data)->failure, 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_AUTH_PROTO:
err = set_long_opt(&opts->auth.proto, *(u_long *)(&opt->o_data[0]), 0, PPP_AUTH_CHAP, 1);
break;
case PPP_OPT_AUTH_NAME:
err = set_str_opt(&opts->auth.name, &opt->o_data[0], len);
break;
case PPP_OPT_AUTH_PASSWD:
err = set_str_opt(&opts->auth.passwd, &opt->o_data[0], len);
break;
case PPP_OPT_IPCP_HDRCOMP:
err = set_long_opt(&opts->ipcp.hdrcomp, *(u_long *)(&opt->o_data[0]), 0, 1, 1);
break;
case PPP_OPT_IPCP_REMOTEADDR:
err = set_long_opt(&opts->ipcp.remoteaddr, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_IPCP_LOCALADDR:
err = set_long_opt(&opts->ipcp.localaddr, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_LOGFILE:
err = EOPNOTSUPP;
break;
case PPP_OPT_COMM_REMINDERTIMER:
err = set_long_opt(&opts->comm.remindertimer, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
case PPP_OPT_ALERTENABLE:
err = set_long_opt(&opts->misc.alertenable, *(u_long *)(&opt->o_data[0]), 0, 0xFFFFFFFF, 1);
break;
default:
err = EOPNOTSUPP;
};
msg->hdr.m_result = err;
msg->hdr.m_len = 0;
return 0;
}