ipcp.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:31k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ipcp.c - PPP IP Control Protocol */
  2. /* Copyright 1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1989 Carnegie Mellon University.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by Carnegie Mellon University.  The name of the
  14.  * University may not be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20. /*
  21. modification history
  22. --------------------
  23. 01e,16jun95,dzb  header file consolidation.
  24. 01d,08jun95,dzb  made LOG_NOTICE message printed even w/o debug option.
  25. 01c,07feb95,dab  die() if IP address reject (SPR #4038).
  26. 01b,16jan95,dab  removed ipcp_script call.  removed pathname.h inclusion.
  27. 01a,21dec94,dab  VxWorks port - first WRS version.
  28.    +dzb  added: path for ppp header files, WRS copyright.
  29. */
  30. #include <vxWorks.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <sys/types.h>
  34. #include <sys/socket.h>
  35. #include <netinet/in.h>
  36. #include "pppLib.h"
  37. /*
  38.  * Callbacks for fsm code.  (CI = Configuration Information)
  39.  */
  40. static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */
  41. static int  ipcp_cilen __ARGS((fsm *));         /* Return length of our CI */
  42. static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */
  43. static int  ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
  44. static int  ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
  45. static int  ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
  46. static int  ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */
  47. static void ipcp_up __ARGS((fsm *)); /* We're UP */
  48. static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
  49. static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
  50.     ipcp_resetci, /* Reset our Configuration Information */
  51.     ipcp_cilen, /* Length of our Configuration Information */
  52.     ipcp_addci, /* Add our Configuration Information */
  53.     ipcp_ackci, /* ACK our Configuration Information */
  54.     ipcp_nakci, /* NAK our Configuration Information */
  55.     ipcp_rejci, /* Reject our Configuration Information */
  56.     ipcp_reqci, /* Request peer's Configuration Information */
  57.     ipcp_up, /* Called when fsm reaches OPENED state */
  58.     ipcp_down, /* Called when fsm leaves OPENED state */
  59.     NULL, /* Called when we want the lower layer up */
  60.     NULL, /* Called when we want the lower layer down */
  61.     NULL, /* Called when Protocol-Reject received */
  62.     NULL, /* Retransmission is necessary */
  63.     NULL, /* Called to handle protocol-specific codes */
  64.     "IPCP" /* String name of protocol */
  65. };
  66. /*
  67.  * Lengths of configuration options.
  68.  */
  69. #define CILEN_VOID 2
  70. #define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
  71. #define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
  72. #define CILEN_ADDR 6 /* new-style single address option */
  73. #define CILEN_ADDRS 10 /* old-style dual address option */
  74. #define CODENAME(x) ((x) == CONFACK ? "ACK" : 
  75.  (x) == CONFNAK ? "NAK" : "REJ")
  76. /*
  77.  * Make a string representation of a network IP address.
  78.  */
  79. char *
  80. ip_ntoa(ipaddr)
  81.     u_long ipaddr;
  82. {
  83.     static char b[64];
  84.     ipaddr = ntohl(ipaddr);
  85.     sprintf(b, "%d.%d.%d.%d",
  86.     (u_char)(ipaddr >> 24),
  87.     (u_char)(ipaddr >> 16),
  88.     (u_char)(ipaddr >> 8),
  89.     (u_char)(ipaddr));
  90.     return b;
  91. }
  92. /*
  93.  * ipcp_init - Initialize IPCP.
  94.  */
  95. void
  96. ipcp_init(unit)
  97.     int unit;
  98. {
  99.     fsm *f = &ppp_if[unit]->ipcp_fsm;
  100.     ipcp_options *wo = &ppp_if[unit]->ipcp_wantoptions;
  101.     ipcp_options *ao = &ppp_if[unit]->ipcp_allowoptions;
  102.     f->unit = unit;
  103.     f->protocol = IPCP;
  104.     f->callbacks = &ipcp_callbacks;
  105.     fsm_init(&ppp_if[unit]->ipcp_fsm);
  106.     wo->neg_addr = 1;
  107.     wo->old_addrs = 0;
  108.     wo->ouraddr = 0;
  109.     wo->hisaddr = 0;
  110.     wo->neg_vj = 1;
  111.     wo->old_vj = 0;
  112.     wo->vj_protocol = IPCP_VJ_COMP;
  113.     wo->maxslotindex = MAX_STATES - 1; /* really max index */
  114.     wo->cflag = 1;
  115.     /* max slots and slot-id compression are currently hardwired in */
  116.     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
  117.     /* things) gmc */
  118.     ao->neg_addr = 1;
  119.     ao->neg_vj = 1;
  120.     ao->maxslotindex = MAX_STATES - 1;
  121.     ao->cflag = 1;
  122. }
  123. /*
  124.  * ipcp_open - IPCP is allowed to come up.
  125.  */
  126. void
  127. ipcp_open(unit)
  128.     int unit;
  129. {
  130.     fsm_open(&ppp_if[unit]->ipcp_fsm);
  131. }
  132. /*
  133.  * ipcp_close - Take IPCP down.
  134.  */
  135. void
  136. ipcp_close(unit)
  137.     int unit;
  138. {
  139.     fsm_close(&ppp_if[unit]->ipcp_fsm);
  140.     /*
  141.      * NB
  142.      * Since the only NCP supported by VxWorks is IPCP, this routine should
  143.      * also take down the entire link if IPCP is going down... Thus,
  144.      * an LCP should occur so that an LCP terminate request is sent to the
  145.      * peer.  This is *not* usual behavior, especially in regard to the
  146.      * RFC's protocol specification, but it makes sense for VxWorks.
  147.      * Users should not mind, since the link is useless without IPCP.
  148.      * -dzb
  149.      */
  150.      die(unit, 1);
  151. }
  152. /*
  153.  * ipcp_lowerup - The lower layer is up.
  154.  */
  155. void
  156. ipcp_lowerup(unit)
  157.     int unit;
  158. {
  159.     fsm_lowerup(&ppp_if[unit]->ipcp_fsm);
  160. }
  161. /*
  162.  * ipcp_lowerdown - The lower layer is down.
  163.  */
  164. void
  165. ipcp_lowerdown(unit)
  166.     int unit;
  167. {
  168.     fsm_lowerdown(&ppp_if[unit]->ipcp_fsm);
  169. }
  170. /*
  171.  * ipcp_input - Input IPCP packet.
  172.  */
  173. void
  174. ipcp_input(unit, p, len)
  175.     int unit;
  176.     u_char *p;
  177.     int len;
  178. {
  179.     fsm_input(&ppp_if[unit]->ipcp_fsm, p, len);
  180. }
  181. /*
  182.  * ipcp_protrej - A Protocol-Reject was received for IPCP.
  183.  *
  184.  * Pretend the lower layer went down, so we shut up.
  185.  */
  186. void
  187. ipcp_protrej(unit)
  188.     int unit;
  189. {
  190.     fsm_lowerdown(&ppp_if[unit]->ipcp_fsm);
  191. }
  192. /*
  193.  * ipcp_resetci - Reset our CI.
  194.  */
  195. static void
  196. ipcp_resetci(f)
  197.     fsm *f;
  198. {
  199.     ipcp_options *wo = &ppp_if[f->unit]->ipcp_wantoptions;
  200.     wo->req_addr = wo->neg_addr && ppp_if[f->unit]->ipcp_allowoptions.neg_addr;
  201.     if (wo->ouraddr == 0)
  202.         wo->accept_local = 1;
  203.     if (wo->hisaddr == 0)
  204.         wo->accept_remote = 1;
  205.     ppp_if[f->unit]->ipcp_gotoptions = *wo;
  206.     ppp_if[f->unit]->cis_received = 0;
  207. }
  208. /*
  209.  * ipcp_cilen - Return length of our CI.
  210.  */
  211. static int
  212. ipcp_cilen(f)
  213.     fsm *f;
  214. {
  215.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  216. #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
  217. #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
  218.     return (LENCIADDR(go->neg_addr, go->old_addrs) +
  219.     LENCIVJ(go->neg_vj, go->old_vj));
  220. }
  221. /*
  222.  * ipcp_addci - Add our desired CIs to a packet.
  223.  */
  224. static void
  225. ipcp_addci(f, ucp, lenp)
  226.     fsm *f;
  227.     u_char *ucp;
  228.     int *lenp;
  229. {
  230.     ipcp_options *wo = &ppp_if[f->unit]->ipcp_wantoptions;
  231.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  232.     ipcp_options *ho = &ppp_if[f->unit]->ipcp_hisoptions;
  233.     int len = *lenp;
  234. #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) 
  235.     if (neg) { 
  236. int vjlen = old? CILEN_COMPRESS : CILEN_VJ; 
  237. if (len >= vjlen) { 
  238.     PUTCHAR(opt, ucp); 
  239.     PUTCHAR(vjlen, ucp); 
  240.     PUTSHORT(val, ucp); 
  241.     if (!old) { 
  242. PUTCHAR(maxslotindex, ucp); 
  243. PUTCHAR(cflag, ucp); 
  244.     } 
  245.     len -= vjlen; 
  246. } else 
  247.     neg = 0; 
  248.     }
  249. #define ADDCIADDR(opt, neg, old, val1, val2) 
  250.     if (neg) { 
  251. int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); 
  252. if (len >= addrlen) { 
  253.     u_long l; 
  254.     PUTCHAR(opt, ucp); 
  255.     PUTCHAR(addrlen, ucp); 
  256.     l = ntohl(val1); 
  257.     PUTLONG(l, ucp); 
  258.     if (old) { 
  259. l = ntohl(val2); 
  260. PUTLONG(l, ucp); 
  261.     } 
  262.     len -= addrlen; 
  263. } else 
  264.     neg = 0; 
  265.     }
  266.     /*
  267.      * First see if we want to change our options to the old
  268.      * forms because we have received old forms from the peer.
  269.      */
  270.     if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
  271. /* use the old style of address negotiation */
  272. go->neg_addr = 1;
  273. go->old_addrs = 1;
  274.     }
  275.     if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
  276. /* try an older style of VJ negotiation */
  277. if (ppp_if[f->unit]->cis_received == 0) {
  278.     /* keep trying the new style until we see some CI from the peer */
  279.     go->neg_vj = 1;
  280. } else {
  281.     /* use the old style only if the peer did */
  282.     if (ho->neg_vj && ho->old_vj) {
  283. go->neg_vj = 1;
  284. go->old_vj = 1;
  285. go->vj_protocol = ho->vj_protocol;
  286.     }
  287. }
  288.     }
  289.     ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
  290.       go->old_addrs, go->ouraddr, go->hisaddr);
  291.     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
  292.     go->maxslotindex, go->cflag);
  293.     *lenp -= len;
  294. }
  295. /*
  296.  * ipcp_ackci - Ack our CIs.
  297.  *
  298.  * Returns:
  299.  * 0 - Ack was bad.
  300.  * 1 - Ack was good.
  301.  */
  302. static int
  303. ipcp_ackci(f, p, len)
  304.     fsm *f;
  305.     u_char *p;
  306.     int len;
  307. {
  308.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  309.     u_short cilen, citype, cishort;
  310.     u_long cilong;
  311.     u_char cimaxslotindex, cicflag;
  312.     /*
  313.      * CIs must be in exactly the same order that we sent...
  314.      * Check packet length and CI length at each step.
  315.      * If we find any deviations, then this packet is bad.
  316.      */
  317. #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) 
  318.     if (neg) { 
  319. int vjlen = old? CILEN_COMPRESS : CILEN_VJ; 
  320. if ((len -= vjlen) < 0) 
  321.     goto bad; 
  322. GETCHAR(citype, p); 
  323. GETCHAR(cilen, p); 
  324. if (cilen != vjlen || 
  325.     citype != opt)  
  326.     goto bad; 
  327. GETSHORT(cishort, p); 
  328. if (cishort != val) 
  329.     goto bad; 
  330. if (!old) { 
  331.     GETCHAR(cimaxslotindex, p); 
  332.     if (cimaxslotindex != maxslotindex) 
  333. goto bad; 
  334.     GETCHAR(cicflag, p); 
  335.     if (cicflag != cflag) 
  336. goto bad; 
  337.     }
  338. #define ACKCIADDR(opt, neg, old, val1, val2) 
  339.     if (neg) { 
  340. int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); 
  341. u_long l; 
  342. if ((len -= addrlen) < 0) 
  343.     goto bad; 
  344. GETCHAR(citype, p); 
  345. GETCHAR(cilen, p); 
  346. if (cilen != addrlen || 
  347.     citype != opt) 
  348.     goto bad; 
  349. GETLONG(l, p); 
  350. cilong = htonl(l); 
  351. if (val1 != cilong) 
  352.     goto bad; 
  353. if (old) { 
  354.     GETLONG(l, p); 
  355.     cilong = htonl(l); 
  356.     if (val2 != cilong) 
  357. goto bad; 
  358.     }
  359.     ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
  360.       go->old_addrs, go->ouraddr, go->hisaddr);
  361.     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
  362.     go->maxslotindex, go->cflag);
  363.     /*
  364.      * If there are any remaining CIs, then this packet is bad.
  365.      */
  366.     if (len != 0)
  367. goto bad;
  368.     return (1);
  369. bad:
  370.     IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
  371.     return (0);
  372. }
  373. /*
  374.  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
  375.  * This should not modify any state if the Nak is bad
  376.  * or if IPCP is in the OPENED state.
  377.  *
  378.  * Returns:
  379.  * 0 - Nak was bad.
  380.  * 1 - Nak was good.
  381.  */
  382. static int
  383. ipcp_nakci(f, p, len)
  384.     fsm *f;
  385.     u_char *p;
  386.     int len;
  387. {
  388.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  389.     u_char cimaxslotindex = 0, cicflag = 0;
  390.     u_char citype, cilen, *next;
  391.     u_short cishort;
  392.     u_long ciaddr1, ciaddr2, l;
  393.     ipcp_options no; /* options we've seen Naks for */
  394.     ipcp_options try; /* options to request next time */
  395.     BZERO((char *)&no, sizeof(no));
  396.     try = *go;
  397.     /*
  398.      * Any Nak'd CIs must be in exactly the same order that we sent.
  399.      * Check packet length and CI length at each step.
  400.      * If we find any deviations, then this packet is bad.
  401.      */
  402. #define NAKCIADDR(opt, neg, old, code) 
  403.     if (go->neg && 
  404. len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && 
  405. p[1] == cilen && 
  406. p[0] == opt) { 
  407. len -= cilen; 
  408. INCPTR(2, p); 
  409. GETLONG(l, p); 
  410. ciaddr1 = htonl(l); 
  411. if (old) { 
  412.     GETLONG(l, p); 
  413.     ciaddr2 = htonl(l); 
  414.     no.old_addrs = 1; 
  415. } else 
  416.     ciaddr2 = 0; 
  417. no.neg = 1; 
  418. code 
  419.     }
  420. #define NAKCIVJ(opt, neg, code) 
  421.     if (go->neg && 
  422. ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && 
  423. len >= cilen && 
  424. p[0] == opt) { 
  425. len -= cilen; 
  426. INCPTR(2, p); 
  427. GETSHORT(cishort, p); 
  428. no.neg = 1; 
  429.         code 
  430.     }
  431.     /*
  432.      * Accept the peer's idea of {our,his} address, if different
  433.      * from our idea, only if the accept_{local,remote} flag is set.
  434.      */
  435.     NAKCIADDR(CI_ADDR, neg_addr, go->old_addrs,
  436.               if (go->accept_local && ciaddr1) { /* Do we know our address? */
  437.                   try.ouraddr = ciaddr1;
  438.                   IPCPDEBUG((LOG_INFO, "local IP address %s",
  439.                              ip_ntoa(ciaddr1)));
  440.               }
  441.               if (go->accept_remote && ciaddr2) { /* Does he know his? */
  442.                   try.hisaddr = ciaddr2;
  443.                   IPCPDEBUG((LOG_INFO, "remote IP address %s",
  444.                              ip_ntoa(ciaddr2)));
  445.               }
  446.               );
  447.     /*
  448.      * Accept the peer's value of maxslotindex provided that it
  449.      * is less than what we asked for.  Turn off slot-ID compression
  450.      * if the peer wants.  Send old-style compress-type option if
  451.      * the peer wants.
  452.      */
  453.     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
  454.     if (cilen == CILEN_VJ) {
  455.                 GETCHAR(cimaxslotindex, p);
  456.                 GETCHAR(cicflag, p);
  457. if (cishort == IPCP_VJ_COMP) {
  458.     try.old_vj = 0;
  459.     if (cimaxslotindex < go->maxslotindex)
  460. try.maxslotindex = cimaxslotindex;
  461.     if (!cicflag)
  462. try.cflag = 0;
  463. } else {
  464.     try.neg_vj = 0;
  465. }
  466.     } else {
  467. if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
  468.     try.old_vj = 1;
  469.     try.vj_protocol = cishort;
  470. } else {
  471.     try.neg_vj = 0;
  472. }
  473.     }
  474.     );
  475.     /*
  476.      * There may be remaining CIs, if the peer is requesting negotiation
  477.      * on an option that we didn't include in our request packet.
  478.      * If they want to negotiate about IP addresses, we comply.
  479.      * If they want us to ask for compression, we refuse.
  480.      */
  481.     while (len > CILEN_VOID) {
  482. GETCHAR(citype, p);
  483. GETCHAR(cilen, p);
  484. if( (len -= cilen) < 0 )
  485.     goto bad;
  486. next = p + cilen - 2;
  487. switch (citype) {
  488. case CI_COMPRESSTYPE:
  489.     if (go->neg_vj || no.neg_vj ||
  490. (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
  491. goto bad;
  492.     no.neg_vj = 1;
  493.     break;
  494. case CI_ADDRS:
  495.     if ((go->neg_addr && go->old_addrs) || no.old_addrs
  496. || cilen != CILEN_ADDRS)
  497. goto bad;
  498.     try.neg_addr = 1;
  499.     try.old_addrs = 1;
  500.     GETLONG(l, p);
  501.     ciaddr1 = htonl(l);
  502.     if (ciaddr1 && go->accept_local)
  503. try.ouraddr = ciaddr1;
  504.     GETLONG(l, p);
  505.     ciaddr2 = htonl(l);
  506.     if (ciaddr2 && go->accept_remote)
  507. try.hisaddr = ciaddr2;
  508.     no.old_addrs = 1;
  509.     break;
  510. case CI_ADDR:
  511.     if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
  512. goto bad;
  513.     try.neg_addr = 1;
  514.     try.old_addrs = 0;
  515.     GETLONG(l, p);
  516.     ciaddr1 = htonl(l);
  517.     if (ciaddr1 && go->accept_local)
  518. try.ouraddr = ciaddr1;
  519.     no.neg_addr = 1;
  520.     break;
  521. default:
  522.     goto bad;
  523. }
  524. p = next;
  525.     }
  526.     /* If there is still anything left, this packet is bad. */
  527.     if (len != 0)
  528. goto bad;
  529.     /*
  530.      * OK, the Nak is good.  Now we can update state.
  531.      */
  532.     if (f->state != OPENED)
  533. *go = try;
  534.     return 1;
  535. bad:
  536.     IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
  537.     return 0;
  538. }
  539. /*
  540.  * ipcp_rejci - Reject some of our CIs.
  541.  */
  542. static int
  543. ipcp_rejci(f, p, len)
  544.     fsm *f;
  545.     u_char *p;
  546.     int len;
  547. {
  548.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  549.     u_char cimaxslotindex, ciflag, cilen;
  550.     u_short cishort;
  551.     u_long cilong;
  552.     ipcp_options try; /* options to request next time */
  553.     try = *go;
  554.     /*
  555.      * Bring down link if peer rejects the IPCP address configuration option,
  556.      * since if the IP address can't be negotiated then the link is useless.
  557.      */
  558.     /*
  559.      * Any Rejected CIs must be in exactly the same order that we sent.
  560.      * Check packet length and CI length at each step.
  561.      * If we find any deviations, then this packet is bad.
  562.      */
  563. #define REJCIADDR(opt, neg, old, val1, val2) 
  564.     if (go->neg && 
  565. len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && 
  566. p[1] == cilen && 
  567. p[0] == opt) { 
  568. u_long l; 
  569.         die(f->unit, 1); /* not to protocol spec. see note in ipcp_close() */ 
  570. len -= cilen; 
  571. INCPTR(2, p); 
  572. GETLONG(l, p); 
  573. cilong = htonl(l); 
  574. /* Check rejected value. */ 
  575. if (cilong != val1) 
  576.     goto bad; 
  577. if (old) { 
  578.     GETLONG(l, p); 
  579.     cilong = htonl(l); 
  580.     /* Check rejected value. */ 
  581.     if (cilong != val2) 
  582. goto bad; 
  583. try.neg = 0; 
  584.     }
  585. #define REJCIVJ(opt, neg, val, old, maxslot, cflag) 
  586.     if (go->neg && 
  587. p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && 
  588. len >= p[1] && 
  589. p[0] == opt) { 
  590. len -= p[1]; 
  591. INCPTR(2, p); 
  592. GETSHORT(cishort, p); 
  593. /* Check rejected value. */  
  594. if (cishort != val) 
  595.     goto bad; 
  596. if (!old) { 
  597.    GETCHAR(cimaxslotindex, p); 
  598.    if (cimaxslotindex != maxslot) 
  599.      goto bad; 
  600.    GETCHAR(ciflag, p); 
  601.    if (ciflag != cflag) 
  602.      goto bad; 
  603.         } 
  604. try.neg = 0; 
  605.      }
  606.     REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
  607.       go->old_addrs, go->ouraddr, go->hisaddr);
  608.     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
  609.     go->maxslotindex, go->cflag);
  610.     /*
  611.      * If there are any remaining CIs, then this packet is bad.
  612.      */
  613.     if (len != 0)
  614. goto bad;
  615.     /*
  616.      * Now we can update state.
  617.      */
  618.     if (f->state != OPENED)
  619. *go = try;
  620.     return 1;
  621. bad:
  622.     IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
  623.     return 0;
  624. }
  625. /*
  626.  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
  627.  *
  628.  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
  629.  * appropriately.  If reject_if_disagree is non-zero, doesn't return
  630.  * CONFNAK; returns CONFREJ if it can't return CONFACK.
  631.  */
  632. static int
  633. ipcp_reqci(f, inp, len, reject_if_disagree)
  634.     fsm *f;
  635.     u_char *inp;                /* Requested CIs */
  636.     int *len;                   /* Length of requested CIs */
  637.     int reject_if_disagree;
  638. {
  639.     ipcp_options *wo = &ppp_if[f->unit]->ipcp_wantoptions;
  640.     ipcp_options *ho = &ppp_if[f->unit]->ipcp_hisoptions;
  641.     ipcp_options *ao = &ppp_if[f->unit]->ipcp_allowoptions;
  642.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  643.     u_char *cip, *next; /* Pointer to current and next CIs */
  644.     u_short cilen, citype; /* Parsed len, type */
  645.     u_short cishort; /* Parsed short value */
  646.     u_long tl, ciaddr1, ciaddr2;/* Parsed address values */
  647.     int rc = CONFACK; /* Final packet return code */
  648.     int orc; /* Individual option return code */
  649.     u_char *p; /* Pointer to next char to parse */
  650.     u_char *ucp = inp; /* Pointer to current output char */
  651.     int l = *len; /* Length left */
  652.     u_char maxslotindex, cflag;
  653.     /*
  654.      * Reset all his options.
  655.      */
  656.     BZERO((char *)ho, sizeof(*ho));
  657.     
  658.     /*
  659.      * Process all his options.
  660.      */
  661.     next = inp;
  662.     while (l) {
  663. orc = CONFACK; /* Assume success */
  664. cip = p = next; /* Remember begining of CI */
  665. if (l < 2 || /* Not enough data for CI header or */
  666.     p[1] < 2 || /*  CI length too small or */
  667.     p[1] > l) { /*  CI length too big? */
  668.     IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
  669.     orc = CONFREJ; /* Reject bad CI */
  670.     cilen = l; /* Reject till end of packet */
  671.     l = 0; /* Don't loop again */
  672.     goto endswitch;
  673. }
  674. GETCHAR(citype, p); /* Parse CI type */
  675. GETCHAR(cilen, p); /* Parse CI length */
  676. l -= cilen; /* Adjust remaining length */
  677. next += cilen; /* Step to next CI */
  678. switch (citype) { /* Check CI type */
  679. case CI_ADDRS:
  680.     IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
  681.     if (!ao->neg_addr ||
  682. cilen != CILEN_ADDRS) { /* Check CI length */
  683. orc = CONFREJ; /* Reject CI */
  684. break;
  685.     }
  686.     /*
  687.      * If he has no address, or if we both have his address but
  688.      * disagree about it, then NAK it with our idea.
  689.      * In particular, if we don't know his address, but he does,
  690.      * then accept it.
  691.      */
  692.     GETLONG(tl, p); /* Parse source address (his) */
  693.     ciaddr1 = htonl(tl);
  694.     IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
  695.     if (ciaddr1 != wo->hisaddr
  696.                 && (ciaddr1 == 0 || !wo->accept_remote)) {
  697. orc = CONFNAK;
  698. if (!reject_if_disagree) {
  699.     DECPTR(sizeof (long), p);
  700.     tl = ntohl(wo->hisaddr);
  701.     PUTLONG(tl, p);
  702. }
  703.     }
  704.     /*
  705.      * If he doesn't know our address, or if we both have our address
  706.      * but disagree about it, then NAK it with our idea.
  707.      */
  708.     GETLONG(tl, p); /* Parse desination address (ours) */
  709.     ciaddr2 = htonl(tl);
  710.     IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
  711.     if (ciaddr2 != wo->ouraddr) {
  712.                 if (ciaddr2 == 0 || !wo->accept_local) {
  713.                     orc = CONFNAK;
  714.                     if (!reject_if_disagree) {
  715.                         DECPTR(sizeof (long), p);
  716.                         tl = ntohl(wo->ouraddr);
  717.                         PUTLONG(tl, p);
  718.                     }
  719.                 } else {
  720.                     go->ouraddr = ciaddr2;      /* accept peer's idea */
  721.                 }
  722.             }
  723.     ho->neg_addr = 1;
  724.     ho->old_addrs = 1;
  725.     ho->hisaddr = ciaddr1;
  726.     ho->ouraddr = ciaddr2;
  727.     break;
  728. case CI_ADDR:
  729.     IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
  730.     if (!ao->neg_addr ||
  731. cilen != CILEN_ADDR) { /* Check CI length */
  732. orc = CONFREJ; /* Reject CI */
  733. break;
  734.     }
  735.     /*
  736.      * If he has no address, or if we both have his address but
  737.      * disagree about it, then NAK it with our idea.
  738.      * In particular, if we don't know his address, but he does,
  739.      * then accept it.
  740.      */
  741.     GETLONG(tl, p); /* Parse source address (his) */
  742.     ciaddr1 = htonl(tl);
  743.     IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
  744.             if (ciaddr1 != wo->hisaddr
  745.                 && (ciaddr1 == 0 || !wo->accept_remote)) {
  746.                 orc = CONFNAK;
  747.                 if (!reject_if_disagree) {
  748.                     DECPTR(sizeof (long), p);
  749.                     tl = ntohl(wo->hisaddr);
  750.                     PUTLONG(tl, p);
  751.                 }
  752.             }
  753.     ho->neg_addr = 1;
  754.     ho->hisaddr = ciaddr1;
  755.     break;
  756. case CI_COMPRESSTYPE:
  757.     IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
  758.     if (!ao->neg_vj ||
  759. (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
  760. orc = CONFREJ;
  761. break;
  762.     }
  763.     GETSHORT(cishort, p);
  764.     IPCPDEBUG((LOG_INFO, "(%d)", cishort));
  765.     if (!(cishort == IPCP_VJ_COMP ||
  766.   (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
  767. orc = CONFREJ;
  768. break;
  769.     }
  770.     ho->neg_vj = 1;
  771.     ho->vj_protocol = cishort;
  772.     if (cilen == CILEN_VJ) {
  773. GETCHAR(maxslotindex, p);
  774. if (maxslotindex > ao->maxslotindex) { 
  775.     orc = CONFNAK;
  776.     if (!reject_if_disagree){
  777. DECPTR(1, p);
  778. PUTCHAR(ao->maxslotindex, p);
  779.     }
  780. }
  781. GETCHAR(cflag, p);
  782. if (cflag && !ao->cflag) {
  783.     orc = CONFNAK;
  784.     if (!reject_if_disagree){
  785. DECPTR(1, p);
  786. PUTCHAR(wo->cflag, p);
  787.     }
  788. }
  789.                 ho->maxslotindex = maxslotindex;
  790.                 ho->cflag = wo->cflag;
  791.             } else {
  792.                 ho->old_vj = 1;
  793.                 ho->maxslotindex = MAX_STATES - 1;
  794.                 ho->cflag = 1;
  795.             }
  796.             break;
  797. default:
  798.     orc = CONFREJ;
  799.     break;
  800. }
  801. endswitch:
  802. IPCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc)));
  803. if (orc == CONFACK && /* Good CI */
  804.     rc != CONFACK) /*  but prior CI wasnt? */
  805.     continue; /* Don't send this one */
  806. if (orc == CONFNAK) { /* Nak this CI? */
  807.     if (reject_if_disagree) /* Getting fed up with sending NAKs? */
  808. orc = CONFREJ; /* Get tough if so */
  809.     else {
  810. if (rc == CONFREJ) /* Rejecting prior CI? */
  811.     continue; /* Don't send this one */
  812. if (rc == CONFACK) { /* Ack'd all prior CIs? */
  813.     rc = CONFNAK; /* Not anymore... */
  814.     ucp = inp; /* Backup */
  815. }
  816.     }
  817. }
  818. if (orc == CONFREJ && /* Reject this CI */
  819.     rc != CONFREJ) { /*  but no prior ones? */
  820.     rc = CONFREJ;
  821.     ucp = inp; /* Backup */
  822. }
  823. /* Need to move CI? */
  824. if (ucp != cip)
  825.     BCOPY((char *)cip, (char *)ucp, cilen); /* Move it */
  826. /* Update output pointer */
  827. INCPTR(cilen, ucp);
  828.     }
  829.     /*
  830.      * If we aren't rejecting this packet, and we want to negotiate
  831.      * their address, and they didn't send their address, then we
  832.      * send a NAK with a CI_ADDR option appended.  We assume the
  833.      * input buffer is long enough that we can append the extra
  834.      * option safely.
  835.      */
  836.     if (rc != CONFREJ && !ho->neg_addr &&
  837. wo->req_addr && !reject_if_disagree) {
  838. if (rc == CONFACK) {
  839.     rc = CONFNAK;
  840.     ucp = inp; /* reset pointer */
  841.     wo->req_addr = 0; /* don't ask again */
  842. }
  843. PUTCHAR(CI_ADDR, ucp);
  844. PUTCHAR(CILEN_ADDR, ucp);
  845. tl = ntohl(wo->hisaddr);
  846. PUTLONG(tl, ucp);
  847.     }
  848.     *len = ucp - inp; /* Compute output length */
  849.     IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
  850.     return (rc); /* Return final code */
  851. }
  852. /*
  853.  * ipcp_up - IPCP has come UP.
  854.  *
  855.  * Configure the IP network interface appropriately and bring it up.
  856.  */
  857. static void
  858. ipcp_up(f)
  859.     fsm *f;
  860. {
  861.     u_long mask;
  862.     ipcp_options *ho = &ppp_if[f->unit]->ipcp_hisoptions;
  863.     ipcp_options *go = &ppp_if[f->unit]->ipcp_gotoptions;
  864.     IPCPDEBUG((LOG_INFO, "ipcp: up"));
  865.     go->default_route = 0;
  866.     go->proxy_arp = 0;
  867.     /*
  868.      * We must have a non-zero IP address for both ends of the link.
  869.      */
  870.     if (!ho->neg_addr)
  871. ho->hisaddr = ppp_if[f->unit]->ipcp_wantoptions.hisaddr;
  872.     if (ho->hisaddr == 0) {
  873. syslog(LOG_ERR, "Could not determine remote IP address");
  874. ipcp_close(f->unit);
  875. return;
  876.     }
  877.     if (go->ouraddr == 0) {
  878. syslog(LOG_ERR, "Could not determine local IP address");
  879. ipcp_close(f->unit);
  880. return;
  881.     }
  882.     /*
  883.      * Check that the peer is allowed to use the IP address it wants.
  884.      */
  885.     if (!auth_ip_addr(f->unit, ho->hisaddr)) {
  886. syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
  887.        ip_ntoa(ho->hisaddr));
  888. ipcp_close(f->unit);
  889. return;
  890.     }
  891.     syslog (LOG_NOTICE, "local  IP address %s", ip_ntoa(go->ouraddr));
  892.     syslog (LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
  893.     /*
  894.      * Set IP addresses and (if specified) netmask.
  895.      */
  896.     mask = GetMask(go->ouraddr);
  897.     if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
  898. IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
  899. ipcp_close(f->unit);
  900. return;
  901.     }
  902.     /* set tcp compression */
  903.     sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
  904.     /* bring the interface up for IP */
  905.     if (!sifup(f->unit)) {
  906. IPCPDEBUG((LOG_WARNING, "sifup failed"));
  907. ipcp_close(f->unit);
  908. return;
  909.     }
  910.     /* assign a default route through the interface if required */
  911.     if (ppp_if[f->unit]->ipcp_wantoptions.default_route) 
  912. if (sifdefaultroute(f->unit, ho->hisaddr))
  913.     go->default_route = 1;
  914.     /* Make a proxy ARP entry if requested. */
  915.     if (ppp_if[f->unit]->ipcp_wantoptions.proxy_arp)
  916. if (sifproxyarp(f->unit, ho->hisaddr))
  917.     go->proxy_arp = 1;
  918. }
  919. /*
  920.  * ipcp_down - IPCP has gone DOWN.
  921.  *
  922.  * Take the IP network interface down, clear its addresses
  923.  * and delete routes through it.
  924.  */
  925. static void
  926. ipcp_down(f)
  927.     fsm *f;
  928. {
  929.     u_long ouraddr, hisaddr;
  930.     IPCPDEBUG((LOG_INFO, "ipcp: down"));
  931.     ouraddr = ppp_if[f->unit]->ipcp_gotoptions.ouraddr;
  932.     hisaddr = ppp_if[f->unit]->ipcp_hisoptions.hisaddr;
  933.     if (ppp_if[f->unit]->ipcp_gotoptions.proxy_arp)
  934. cifproxyarp(f->unit, hisaddr);
  935.     if (ppp_if[f->unit]->ipcp_gotoptions.default_route) 
  936. cifdefaultroute(f->unit, hisaddr);
  937.     sifdown(f->unit);
  938.     cifaddr(f->unit, ouraddr, hisaddr);
  939. }
  940. #ifdef notyet
  941. /*
  942.  * ipcp_script - Execute a script with arguments
  943.  * interface-name tty-name speed local-IP remote-IP.
  944.  */
  945. static void
  946. ipcp_script(f, script)
  947.     fsm *f;
  948.     char *script;
  949. {
  950.     char strspeed[32], strlocal[32], strremote[32];
  951.     char *argv[8];
  952.     sprintf(strspeed, "%d", ppp_if[f->unit]->baud_rate);
  953.     strcpy(strlocal, ip_ntoa(ppp_if[f->unit]->ipcp_gotoptions.ouraddr));
  954.     strcpy(strremote, ip_ntoa(ppp_if[f->unit]->ipcp_hisoptions.hisaddr));
  955.     argv[0] = script;
  956.     argv[1] = ppp_if[f->unit]->ifname;
  957.     argv[2] = ppp_if[f->unit]->devname;
  958.     argv[3] = strspeed;
  959.     argv[4] = strlocal;
  960.     argv[5] = strremote;
  961.     argv[6] = NULL;
  962.     run_program(script, argv, 0);
  963. }
  964. #endif /* notyet */
  965. /*
  966.  * ipcp_printpkt - print the contents of an IPCP packet.
  967.  */
  968. char *ipcp_codenames[] = {
  969.     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
  970.     "TermReq", "TermAck", "CodeRej"
  971. };
  972. int
  973. ipcp_printpkt(p, plen, printer, arg)
  974.     u_char *p;
  975.     int plen;
  976.     void (*printer)();
  977.     void *arg;
  978. {
  979.     int code, id, len, olen;
  980.     u_char *pstart, *optend;
  981.     u_short cishort;
  982.     u_long cilong;
  983.     if (plen < HEADERLEN)
  984.         return 0;
  985.     pstart = p;
  986.     GETCHAR(code, p);
  987.     GETCHAR(id, p);
  988.     GETSHORT(len, p);
  989.     if (len < HEADERLEN || len > plen)
  990.         return 0;
  991.     if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
  992.         printer(arg, " %s", ipcp_codenames[code-1]);
  993.     else
  994.         printer(arg, " code=0x%x", code);
  995.     printer(arg, " id=0x%x", id);
  996.     len -= HEADERLEN;
  997.     switch (code) {
  998.     case CONFREQ:
  999.     case CONFACK:
  1000.     case CONFNAK:
  1001.     case CONFREJ:
  1002.         /* print option list */
  1003.         while (len >= 2) {
  1004.             GETCHAR(code, p);
  1005.             GETCHAR(olen, p);
  1006.             p -= 2;
  1007.             if (olen < 2 || olen > len) {
  1008.                 break;
  1009.             }
  1010.             printer(arg, " <");
  1011.             len -= olen;
  1012.             optend = p + olen;
  1013.             switch (code) {
  1014.             case CI_ADDRS:
  1015.                 if (olen == CILEN_ADDRS) {
  1016.                     p += 2;
  1017.                     GETLONG(cilong, p);
  1018.                     printer(arg, "addrs %s", ip_ntoa(htonl(cilong)));
  1019.                     GETLONG(cilong, p);
  1020.                     printer(arg, " %s", ip_ntoa(htonl(cilong)));
  1021.                 }
  1022.                 break;
  1023.             case CI_COMPRESSTYPE:
  1024.                 if (olen >= CILEN_COMPRESS) {
  1025.                     p += 2;
  1026.                     GETSHORT(cishort, p);
  1027.                     printer(arg, "compress ");
  1028.                     switch (cishort) {
  1029.                     case IPCP_VJ_COMP:
  1030.                         printer(arg, "VJ");
  1031.                         break;
  1032.                     case IPCP_VJ_COMP_OLD:
  1033.                         printer(arg, "old-VJ");
  1034.                         break;
  1035.                     default:
  1036.                         printer(arg, "0x%x", cishort);
  1037.                     }
  1038.                 }
  1039.                 break;
  1040.             case CI_ADDR:
  1041.                 if (olen == CILEN_ADDR) {
  1042.                     p += 2;
  1043.                     GETLONG(cilong, p);
  1044.                     printer(arg, "addr %s", ip_ntoa(htonl(cilong)));
  1045.                 }
  1046.                 break;
  1047.             }
  1048.             while (p < optend) {
  1049.                 GETCHAR(code, p);
  1050.                 printer(arg, " %.2x", code);
  1051.             }
  1052.             printer(arg, ">");
  1053.         }
  1054.         break;
  1055.     }
  1056.     /* print the rest of the bytes in the packet */
  1057.     for (; len > 0; --len) {
  1058.         GETCHAR(code, p);
  1059.         printer(arg, " %.2x", code);
  1060.     }
  1061.     return p - pstart;
  1062. }