xref: /nrf52832-nimble/rt-thread/components/net/lwip-1.4.1/src/netif/ppp/ipcp.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /** In contrast to pppd 2.3.1, DNS support has been added, proxy-ARP and
2*10465441SEvalZero     dial-on-demand has been stripped. */
3*10465441SEvalZero /*****************************************************************************
4*10465441SEvalZero * ipcp.c - Network PPP IP Control Protocol program file.
5*10465441SEvalZero *
6*10465441SEvalZero * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
7*10465441SEvalZero * portions Copyright (c) 1997 by Global Election Systems Inc.
8*10465441SEvalZero *
9*10465441SEvalZero * The authors hereby grant permission to use, copy, modify, distribute,
10*10465441SEvalZero * and license this software and its documentation for any purpose, provided
11*10465441SEvalZero * that existing copyright notices are retained in all copies and that this
12*10465441SEvalZero * notice and the following disclaimer are included verbatim in any
13*10465441SEvalZero * distributions. No written agreement, license, or royalty fee is required
14*10465441SEvalZero * for any of the authorized uses.
15*10465441SEvalZero *
16*10465441SEvalZero * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
17*10465441SEvalZero * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*10465441SEvalZero * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*10465441SEvalZero * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*10465441SEvalZero * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*10465441SEvalZero * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*10465441SEvalZero * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*10465441SEvalZero * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*10465441SEvalZero * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*10465441SEvalZero * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*10465441SEvalZero *
27*10465441SEvalZero ******************************************************************************
28*10465441SEvalZero * REVISION HISTORY
29*10465441SEvalZero *
30*10465441SEvalZero * 03-01-01 Marc Boucher <[email protected]>
31*10465441SEvalZero *   Ported to lwIP.
32*10465441SEvalZero * 97-12-08 Guy Lancaster <[email protected]>, Global Election Systems Inc.
33*10465441SEvalZero *   Original.
34*10465441SEvalZero *****************************************************************************/
35*10465441SEvalZero /*
36*10465441SEvalZero  * ipcp.c - PPP IP Control Protocol.
37*10465441SEvalZero  *
38*10465441SEvalZero  * Copyright (c) 1989 Carnegie Mellon University.
39*10465441SEvalZero  * All rights reserved.
40*10465441SEvalZero  *
41*10465441SEvalZero  * Redistribution and use in source and binary forms are permitted
42*10465441SEvalZero  * provided that the above copyright notice and this paragraph are
43*10465441SEvalZero  * duplicated in all such forms and that any documentation,
44*10465441SEvalZero  * advertising materials, and other materials related to such
45*10465441SEvalZero  * distribution and use acknowledge that the software was developed
46*10465441SEvalZero  * by Carnegie Mellon University.  The name of the
47*10465441SEvalZero  * University may not be used to endorse or promote products derived
48*10465441SEvalZero  * from this software without specific prior written permission.
49*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50*10465441SEvalZero  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51*10465441SEvalZero  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
52*10465441SEvalZero  */
53*10465441SEvalZero 
54*10465441SEvalZero #include "lwip/opt.h"
55*10465441SEvalZero 
56*10465441SEvalZero #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
57*10465441SEvalZero 
58*10465441SEvalZero #include "ppp_impl.h"
59*10465441SEvalZero #include "pppdebug.h"
60*10465441SEvalZero 
61*10465441SEvalZero #include "auth.h"
62*10465441SEvalZero #include "fsm.h"
63*10465441SEvalZero #include "vj.h"
64*10465441SEvalZero #include "ipcp.h"
65*10465441SEvalZero 
66*10465441SEvalZero #include "lwip/inet.h"
67*10465441SEvalZero 
68*10465441SEvalZero #include <string.h>
69*10465441SEvalZero 
70*10465441SEvalZero /* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */
71*10465441SEvalZero 
72*10465441SEvalZero /* global vars */
73*10465441SEvalZero ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */
74*10465441SEvalZero ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */
75*10465441SEvalZero ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
76*10465441SEvalZero ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */
77*10465441SEvalZero 
78*10465441SEvalZero /* local vars */
79*10465441SEvalZero static int default_route_set[NUM_PPP]; /* Have set up a default route */
80*10465441SEvalZero static int cis_received[NUM_PPP];      /* # Conf-Reqs received */
81*10465441SEvalZero 
82*10465441SEvalZero 
83*10465441SEvalZero /*
84*10465441SEvalZero  * Callbacks for fsm code.  (CI = Configuration Information)
85*10465441SEvalZero  */
86*10465441SEvalZero static void ipcp_resetci (fsm *);                     /* Reset our CI */
87*10465441SEvalZero static int  ipcp_cilen (fsm *);                       /* Return length of our CI */
88*10465441SEvalZero static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */
89*10465441SEvalZero static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */
90*10465441SEvalZero static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */
91*10465441SEvalZero static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */
92*10465441SEvalZero static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
93*10465441SEvalZero static void ipcp_up (fsm *);                          /* We're UP */
94*10465441SEvalZero static void ipcp_down (fsm *);                        /* We're DOWN */
95*10465441SEvalZero #if PPP_ADDITIONAL_CALLBACKS
96*10465441SEvalZero static void ipcp_script (fsm *, char *); /* Run an up/down script */
97*10465441SEvalZero #endif
98*10465441SEvalZero static void ipcp_finished (fsm *);                    /* Don't need lower layer */
99*10465441SEvalZero 
100*10465441SEvalZero 
101*10465441SEvalZero fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
102*10465441SEvalZero 
103*10465441SEvalZero 
104*10465441SEvalZero static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
105*10465441SEvalZero   ipcp_resetci,  /* Reset our Configuration Information */
106*10465441SEvalZero   ipcp_cilen,    /* Length of our Configuration Information */
107*10465441SEvalZero   ipcp_addci,    /* Add our Configuration Information */
108*10465441SEvalZero   ipcp_ackci,    /* ACK our Configuration Information */
109*10465441SEvalZero   ipcp_nakci,    /* NAK our Configuration Information */
110*10465441SEvalZero   ipcp_rejci,    /* Reject our Configuration Information */
111*10465441SEvalZero   ipcp_reqci,    /* Request peer's Configuration Information */
112*10465441SEvalZero   ipcp_up,       /* Called when fsm reaches LS_OPENED state */
113*10465441SEvalZero   ipcp_down,     /* Called when fsm leaves LS_OPENED state */
114*10465441SEvalZero   NULL,          /* Called when we want the lower layer up */
115*10465441SEvalZero   ipcp_finished, /* Called when we want the lower layer down */
116*10465441SEvalZero   NULL,          /* Called when Protocol-Reject received */
117*10465441SEvalZero   NULL,          /* Retransmission is necessary */
118*10465441SEvalZero   NULL,          /* Called to handle protocol-specific codes */
119*10465441SEvalZero   "IPCP"         /* String name of protocol */
120*10465441SEvalZero };
121*10465441SEvalZero 
122*10465441SEvalZero /*
123*10465441SEvalZero  * Protocol entry points from main code.
124*10465441SEvalZero  */
125*10465441SEvalZero static void ipcp_init (int);
126*10465441SEvalZero static void ipcp_open (int);
127*10465441SEvalZero static void ipcp_close (int, char *);
128*10465441SEvalZero static void ipcp_lowerup (int);
129*10465441SEvalZero static void ipcp_lowerdown (int);
130*10465441SEvalZero static void ipcp_input (int, u_char *, int);
131*10465441SEvalZero static void ipcp_protrej (int);
132*10465441SEvalZero 
133*10465441SEvalZero 
134*10465441SEvalZero struct protent ipcp_protent = {
135*10465441SEvalZero   PPP_IPCP,
136*10465441SEvalZero   ipcp_init,
137*10465441SEvalZero   ipcp_input,
138*10465441SEvalZero   ipcp_protrej,
139*10465441SEvalZero   ipcp_lowerup,
140*10465441SEvalZero   ipcp_lowerdown,
141*10465441SEvalZero   ipcp_open,
142*10465441SEvalZero   ipcp_close,
143*10465441SEvalZero #if PPP_ADDITIONAL_CALLBACKS
144*10465441SEvalZero   ipcp_printpkt,
145*10465441SEvalZero   NULL,
146*10465441SEvalZero #endif /* PPP_ADDITIONAL_CALLBACKS */
147*10465441SEvalZero   1,
148*10465441SEvalZero   "IPCP",
149*10465441SEvalZero #if PPP_ADDITIONAL_CALLBACKS
150*10465441SEvalZero   ip_check_options,
151*10465441SEvalZero   NULL,
152*10465441SEvalZero   ip_active_pkt
153*10465441SEvalZero #endif /* PPP_ADDITIONAL_CALLBACKS */
154*10465441SEvalZero };
155*10465441SEvalZero 
156*10465441SEvalZero static void ipcp_clear_addrs (int);
157*10465441SEvalZero 
158*10465441SEvalZero /*
159*10465441SEvalZero  * Lengths of configuration options.
160*10465441SEvalZero  */
161*10465441SEvalZero #define CILEN_VOID     2
162*10465441SEvalZero #define CILEN_COMPRESS 4  /* min length for compression protocol opt. */
163*10465441SEvalZero #define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */
164*10465441SEvalZero #define CILEN_ADDR     6  /* new-style single address option */
165*10465441SEvalZero #define CILEN_ADDRS    10 /* old-style dual address option */
166*10465441SEvalZero 
167*10465441SEvalZero 
168*10465441SEvalZero #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
169*10465441SEvalZero                      (x) == CONFNAK ? "NAK" : "REJ")
170*10465441SEvalZero 
171*10465441SEvalZero 
172*10465441SEvalZero /*
173*10465441SEvalZero  * ipcp_init - Initialize IPCP.
174*10465441SEvalZero  */
175*10465441SEvalZero static void
ipcp_init(int unit)176*10465441SEvalZero ipcp_init(int unit)
177*10465441SEvalZero {
178*10465441SEvalZero   fsm           *f = &ipcp_fsm[unit];
179*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[unit];
180*10465441SEvalZero   ipcp_options *ao = &ipcp_allowoptions[unit];
181*10465441SEvalZero 
182*10465441SEvalZero   f->unit      = unit;
183*10465441SEvalZero   f->protocol  = PPP_IPCP;
184*10465441SEvalZero   f->callbacks = &ipcp_callbacks;
185*10465441SEvalZero   fsm_init(&ipcp_fsm[unit]);
186*10465441SEvalZero 
187*10465441SEvalZero   memset(wo, 0, sizeof(*wo));
188*10465441SEvalZero   memset(ao, 0, sizeof(*ao));
189*10465441SEvalZero 
190*10465441SEvalZero   wo->neg_addr      = 1;
191*10465441SEvalZero   wo->ouraddr       = 0;
192*10465441SEvalZero #if VJ_SUPPORT
193*10465441SEvalZero   wo->neg_vj        = 1;
194*10465441SEvalZero #else  /* VJ_SUPPORT */
195*10465441SEvalZero   wo->neg_vj        = 0;
196*10465441SEvalZero #endif /* VJ_SUPPORT */
197*10465441SEvalZero   wo->vj_protocol   = IPCP_VJ_COMP;
198*10465441SEvalZero   wo->maxslotindex  = MAX_SLOTS - 1;
199*10465441SEvalZero   wo->cflag         = 0;
200*10465441SEvalZero   wo->default_route = 1;
201*10465441SEvalZero 
202*10465441SEvalZero   ao->neg_addr      = 1;
203*10465441SEvalZero #if VJ_SUPPORT
204*10465441SEvalZero   ao->neg_vj        = 1;
205*10465441SEvalZero #else  /* VJ_SUPPORT */
206*10465441SEvalZero   ao->neg_vj        = 0;
207*10465441SEvalZero #endif /* VJ_SUPPORT */
208*10465441SEvalZero   ao->maxslotindex  = MAX_SLOTS - 1;
209*10465441SEvalZero   ao->cflag         = 1;
210*10465441SEvalZero   ao->default_route = 1;
211*10465441SEvalZero }
212*10465441SEvalZero 
213*10465441SEvalZero 
214*10465441SEvalZero /*
215*10465441SEvalZero  * ipcp_open - IPCP is allowed to come up.
216*10465441SEvalZero  */
217*10465441SEvalZero static void
ipcp_open(int unit)218*10465441SEvalZero ipcp_open(int unit)
219*10465441SEvalZero {
220*10465441SEvalZero   fsm_open(&ipcp_fsm[unit]);
221*10465441SEvalZero }
222*10465441SEvalZero 
223*10465441SEvalZero 
224*10465441SEvalZero /*
225*10465441SEvalZero  * ipcp_close - Take IPCP down.
226*10465441SEvalZero  */
227*10465441SEvalZero static void
ipcp_close(int unit,char * reason)228*10465441SEvalZero ipcp_close(int unit, char *reason)
229*10465441SEvalZero {
230*10465441SEvalZero   fsm_close(&ipcp_fsm[unit], reason);
231*10465441SEvalZero }
232*10465441SEvalZero 
233*10465441SEvalZero 
234*10465441SEvalZero /*
235*10465441SEvalZero  * ipcp_lowerup - The lower layer is up.
236*10465441SEvalZero  */
237*10465441SEvalZero static void
ipcp_lowerup(int unit)238*10465441SEvalZero ipcp_lowerup(int unit)
239*10465441SEvalZero {
240*10465441SEvalZero   fsm_lowerup(&ipcp_fsm[unit]);
241*10465441SEvalZero }
242*10465441SEvalZero 
243*10465441SEvalZero 
244*10465441SEvalZero /*
245*10465441SEvalZero  * ipcp_lowerdown - The lower layer is down.
246*10465441SEvalZero  */
247*10465441SEvalZero static void
ipcp_lowerdown(int unit)248*10465441SEvalZero ipcp_lowerdown(int unit)
249*10465441SEvalZero {
250*10465441SEvalZero   fsm_lowerdown(&ipcp_fsm[unit]);
251*10465441SEvalZero }
252*10465441SEvalZero 
253*10465441SEvalZero 
254*10465441SEvalZero /*
255*10465441SEvalZero  * ipcp_input - Input IPCP packet.
256*10465441SEvalZero  */
257*10465441SEvalZero static void
ipcp_input(int unit,u_char * p,int len)258*10465441SEvalZero ipcp_input(int unit, u_char *p, int len)
259*10465441SEvalZero {
260*10465441SEvalZero   fsm_input(&ipcp_fsm[unit], p, len);
261*10465441SEvalZero }
262*10465441SEvalZero 
263*10465441SEvalZero 
264*10465441SEvalZero /*
265*10465441SEvalZero  * ipcp_protrej - A Protocol-Reject was received for IPCP.
266*10465441SEvalZero  *
267*10465441SEvalZero  * Pretend the lower layer went down, so we shut up.
268*10465441SEvalZero  */
269*10465441SEvalZero static void
ipcp_protrej(int unit)270*10465441SEvalZero ipcp_protrej(int unit)
271*10465441SEvalZero {
272*10465441SEvalZero   fsm_lowerdown(&ipcp_fsm[unit]);
273*10465441SEvalZero }
274*10465441SEvalZero 
275*10465441SEvalZero 
276*10465441SEvalZero /*
277*10465441SEvalZero  * ipcp_resetci - Reset our CI.
278*10465441SEvalZero  */
279*10465441SEvalZero static void
ipcp_resetci(fsm * f)280*10465441SEvalZero ipcp_resetci(fsm *f)
281*10465441SEvalZero {
282*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[f->unit];
283*10465441SEvalZero 
284*10465441SEvalZero   wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
285*10465441SEvalZero   if (wo->ouraddr == 0) {
286*10465441SEvalZero     wo->accept_local = 1;
287*10465441SEvalZero   }
288*10465441SEvalZero   if (wo->hisaddr == 0) {
289*10465441SEvalZero     wo->accept_remote = 1;
290*10465441SEvalZero   }
291*10465441SEvalZero   /* Request DNS addresses from the peer */
292*10465441SEvalZero   wo->req_dns1 = ppp_settings.usepeerdns;
293*10465441SEvalZero   wo->req_dns2 = ppp_settings.usepeerdns;
294*10465441SEvalZero   ipcp_gotoptions[f->unit] = *wo;
295*10465441SEvalZero   cis_received[f->unit] = 0;
296*10465441SEvalZero }
297*10465441SEvalZero 
298*10465441SEvalZero 
299*10465441SEvalZero /*
300*10465441SEvalZero  * ipcp_cilen - Return length of our CI.
301*10465441SEvalZero  */
302*10465441SEvalZero static int
ipcp_cilen(fsm * f)303*10465441SEvalZero ipcp_cilen(fsm *f)
304*10465441SEvalZero {
305*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
306*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[f->unit];
307*10465441SEvalZero   ipcp_options *ho = &ipcp_hisoptions[f->unit];
308*10465441SEvalZero 
309*10465441SEvalZero #define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
310*10465441SEvalZero #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
311*10465441SEvalZero #define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0)
312*10465441SEvalZero 
313*10465441SEvalZero   /*
314*10465441SEvalZero    * First see if we want to change our options to the old
315*10465441SEvalZero    * forms because we have received old forms from the peer.
316*10465441SEvalZero    */
317*10465441SEvalZero   if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
318*10465441SEvalZero     /* use the old style of address negotiation */
319*10465441SEvalZero     go->neg_addr = 1;
320*10465441SEvalZero     go->old_addrs = 1;
321*10465441SEvalZero   }
322*10465441SEvalZero   if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
323*10465441SEvalZero     /* try an older style of VJ negotiation */
324*10465441SEvalZero     if (cis_received[f->unit] == 0) {
325*10465441SEvalZero       /* keep trying the new style until we see some CI from the peer */
326*10465441SEvalZero       go->neg_vj = 1;
327*10465441SEvalZero     } else {
328*10465441SEvalZero       /* use the old style only if the peer did */
329*10465441SEvalZero       if (ho->neg_vj && ho->old_vj) {
330*10465441SEvalZero         go->neg_vj = 1;
331*10465441SEvalZero         go->old_vj = 1;
332*10465441SEvalZero         go->vj_protocol = ho->vj_protocol;
333*10465441SEvalZero       }
334*10465441SEvalZero     }
335*10465441SEvalZero   }
336*10465441SEvalZero 
337*10465441SEvalZero   return (LENCIADDR(go->neg_addr, go->old_addrs) +
338*10465441SEvalZero           LENCIVJ(go->neg_vj, go->old_vj) +
339*10465441SEvalZero           LENCIDNS(go->req_dns1) +
340*10465441SEvalZero           LENCIDNS(go->req_dns2));
341*10465441SEvalZero }
342*10465441SEvalZero 
343*10465441SEvalZero 
344*10465441SEvalZero /*
345*10465441SEvalZero  * ipcp_addci - Add our desired CIs to a packet.
346*10465441SEvalZero  */
347*10465441SEvalZero static void
ipcp_addci(fsm * f,u_char * ucp,int * lenp)348*10465441SEvalZero ipcp_addci(fsm *f, u_char *ucp, int *lenp)
349*10465441SEvalZero {
350*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
351*10465441SEvalZero   int len = *lenp;
352*10465441SEvalZero 
353*10465441SEvalZero #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
354*10465441SEvalZero   if (neg) { \
355*10465441SEvalZero     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
356*10465441SEvalZero     if (len >= vjlen) { \
357*10465441SEvalZero       PUTCHAR(opt, ucp); \
358*10465441SEvalZero       PUTCHAR(vjlen, ucp); \
359*10465441SEvalZero       PUTSHORT(val, ucp); \
360*10465441SEvalZero       if (!old) { \
361*10465441SEvalZero         PUTCHAR(maxslotindex, ucp); \
362*10465441SEvalZero         PUTCHAR(cflag, ucp); \
363*10465441SEvalZero       } \
364*10465441SEvalZero       len -= vjlen; \
365*10465441SEvalZero     } else { \
366*10465441SEvalZero       neg = 0; \
367*10465441SEvalZero     } \
368*10465441SEvalZero   }
369*10465441SEvalZero 
370*10465441SEvalZero #define ADDCIADDR(opt, neg, old, val1, val2) \
371*10465441SEvalZero   if (neg) { \
372*10465441SEvalZero     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
373*10465441SEvalZero     if (len >= addrlen) { \
374*10465441SEvalZero       u32_t l; \
375*10465441SEvalZero       PUTCHAR(opt, ucp); \
376*10465441SEvalZero       PUTCHAR(addrlen, ucp); \
377*10465441SEvalZero       l = ntohl(val1); \
378*10465441SEvalZero       PUTLONG(l, ucp); \
379*10465441SEvalZero       if (old) { \
380*10465441SEvalZero         l = ntohl(val2); \
381*10465441SEvalZero         PUTLONG(l, ucp); \
382*10465441SEvalZero       } \
383*10465441SEvalZero       len -= addrlen; \
384*10465441SEvalZero     } else { \
385*10465441SEvalZero       neg = 0; \
386*10465441SEvalZero     } \
387*10465441SEvalZero   }
388*10465441SEvalZero 
389*10465441SEvalZero #define ADDCIDNS(opt, neg, addr) \
390*10465441SEvalZero   if (neg) { \
391*10465441SEvalZero     if (len >= CILEN_ADDR) { \
392*10465441SEvalZero       u32_t l; \
393*10465441SEvalZero       PUTCHAR(opt, ucp); \
394*10465441SEvalZero       PUTCHAR(CILEN_ADDR, ucp); \
395*10465441SEvalZero       l = ntohl(addr); \
396*10465441SEvalZero       PUTLONG(l, ucp); \
397*10465441SEvalZero       len -= CILEN_ADDR; \
398*10465441SEvalZero     } else { \
399*10465441SEvalZero       neg = 0; \
400*10465441SEvalZero     } \
401*10465441SEvalZero   }
402*10465441SEvalZero 
403*10465441SEvalZero   ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
404*10465441SEvalZero       go->old_addrs, go->ouraddr, go->hisaddr);
405*10465441SEvalZero 
406*10465441SEvalZero   ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
407*10465441SEvalZero       go->maxslotindex, go->cflag);
408*10465441SEvalZero 
409*10465441SEvalZero   ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
410*10465441SEvalZero 
411*10465441SEvalZero   ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
412*10465441SEvalZero 
413*10465441SEvalZero   *lenp -= len;
414*10465441SEvalZero }
415*10465441SEvalZero 
416*10465441SEvalZero 
417*10465441SEvalZero /*
418*10465441SEvalZero  * ipcp_ackci - Ack our CIs.
419*10465441SEvalZero  *
420*10465441SEvalZero  * Returns:
421*10465441SEvalZero  *  0 - Ack was bad.
422*10465441SEvalZero  *  1 - Ack was good.
423*10465441SEvalZero  */
424*10465441SEvalZero static int
ipcp_ackci(fsm * f,u_char * p,int len)425*10465441SEvalZero ipcp_ackci(fsm *f, u_char *p, int len)
426*10465441SEvalZero {
427*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
428*10465441SEvalZero   u_short cilen, citype, cishort;
429*10465441SEvalZero   u32_t cilong;
430*10465441SEvalZero   u_char cimaxslotindex, cicflag;
431*10465441SEvalZero 
432*10465441SEvalZero   /*
433*10465441SEvalZero    * CIs must be in exactly the same order that we sent...
434*10465441SEvalZero    * Check packet length and CI length at each step.
435*10465441SEvalZero    * If we find any deviations, then this packet is bad.
436*10465441SEvalZero    */
437*10465441SEvalZero 
438*10465441SEvalZero #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
439*10465441SEvalZero   if (neg) { \
440*10465441SEvalZero     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
441*10465441SEvalZero     if ((len -= vjlen) < 0) { \
442*10465441SEvalZero       goto bad; \
443*10465441SEvalZero     } \
444*10465441SEvalZero     GETCHAR(citype, p); \
445*10465441SEvalZero     GETCHAR(cilen, p); \
446*10465441SEvalZero     if (cilen != vjlen || \
447*10465441SEvalZero         citype != opt) { \
448*10465441SEvalZero       goto bad; \
449*10465441SEvalZero     } \
450*10465441SEvalZero     GETSHORT(cishort, p); \
451*10465441SEvalZero     if (cishort != val) { \
452*10465441SEvalZero       goto bad; \
453*10465441SEvalZero     } \
454*10465441SEvalZero     if (!old) { \
455*10465441SEvalZero       GETCHAR(cimaxslotindex, p); \
456*10465441SEvalZero       if (cimaxslotindex != maxslotindex) { \
457*10465441SEvalZero         goto bad; \
458*10465441SEvalZero       } \
459*10465441SEvalZero       GETCHAR(cicflag, p); \
460*10465441SEvalZero       if (cicflag != cflag) { \
461*10465441SEvalZero         goto bad; \
462*10465441SEvalZero       } \
463*10465441SEvalZero     } \
464*10465441SEvalZero   }
465*10465441SEvalZero 
466*10465441SEvalZero #define ACKCIADDR(opt, neg, old, val1, val2) \
467*10465441SEvalZero   if (neg) { \
468*10465441SEvalZero     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
469*10465441SEvalZero     u32_t l; \
470*10465441SEvalZero     if ((len -= addrlen) < 0) { \
471*10465441SEvalZero       goto bad; \
472*10465441SEvalZero     } \
473*10465441SEvalZero     GETCHAR(citype, p); \
474*10465441SEvalZero     GETCHAR(cilen, p); \
475*10465441SEvalZero     if (cilen != addrlen || \
476*10465441SEvalZero         citype != opt) { \
477*10465441SEvalZero       goto bad; \
478*10465441SEvalZero     } \
479*10465441SEvalZero     GETLONG(l, p); \
480*10465441SEvalZero     cilong = htonl(l); \
481*10465441SEvalZero     if (val1 != cilong) { \
482*10465441SEvalZero       goto bad; \
483*10465441SEvalZero     } \
484*10465441SEvalZero     if (old) { \
485*10465441SEvalZero       GETLONG(l, p); \
486*10465441SEvalZero       cilong = htonl(l); \
487*10465441SEvalZero       if (val2 != cilong) { \
488*10465441SEvalZero         goto bad; \
489*10465441SEvalZero       } \
490*10465441SEvalZero     } \
491*10465441SEvalZero   }
492*10465441SEvalZero 
493*10465441SEvalZero #define ACKCIDNS(opt, neg, addr) \
494*10465441SEvalZero   if (neg) { \
495*10465441SEvalZero     u32_t l; \
496*10465441SEvalZero     if ((len -= CILEN_ADDR) < 0) { \
497*10465441SEvalZero       goto bad; \
498*10465441SEvalZero     } \
499*10465441SEvalZero     GETCHAR(citype, p); \
500*10465441SEvalZero     GETCHAR(cilen, p); \
501*10465441SEvalZero     if (cilen != CILEN_ADDR || \
502*10465441SEvalZero         citype != opt) { \
503*10465441SEvalZero       goto bad; \
504*10465441SEvalZero     } \
505*10465441SEvalZero     GETLONG(l, p); \
506*10465441SEvalZero     cilong = htonl(l); \
507*10465441SEvalZero     if (addr != cilong) { \
508*10465441SEvalZero       goto bad; \
509*10465441SEvalZero     } \
510*10465441SEvalZero   }
511*10465441SEvalZero 
512*10465441SEvalZero   ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
513*10465441SEvalZero         go->old_addrs, go->ouraddr, go->hisaddr);
514*10465441SEvalZero 
515*10465441SEvalZero   ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
516*10465441SEvalZero       go->maxslotindex, go->cflag);
517*10465441SEvalZero 
518*10465441SEvalZero   ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
519*10465441SEvalZero 
520*10465441SEvalZero   ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
521*10465441SEvalZero 
522*10465441SEvalZero   /*
523*10465441SEvalZero    * If there are any remaining CIs, then this packet is bad.
524*10465441SEvalZero    */
525*10465441SEvalZero   if (len != 0) {
526*10465441SEvalZero     goto bad;
527*10465441SEvalZero   }
528*10465441SEvalZero   return (1);
529*10465441SEvalZero 
530*10465441SEvalZero bad:
531*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n"));
532*10465441SEvalZero   return (0);
533*10465441SEvalZero }
534*10465441SEvalZero 
535*10465441SEvalZero /*
536*10465441SEvalZero  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
537*10465441SEvalZero  * This should not modify any state if the Nak is bad
538*10465441SEvalZero  * or if IPCP is in the LS_OPENED state.
539*10465441SEvalZero  *
540*10465441SEvalZero  * Returns:
541*10465441SEvalZero  *  0 - Nak was bad.
542*10465441SEvalZero  *  1 - Nak was good.
543*10465441SEvalZero  */
544*10465441SEvalZero static int
ipcp_nakci(fsm * f,u_char * p,int len)545*10465441SEvalZero ipcp_nakci(fsm *f, u_char *p, int len)
546*10465441SEvalZero {
547*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
548*10465441SEvalZero   u_char cimaxslotindex, cicflag;
549*10465441SEvalZero   u_char citype, cilen, *next;
550*10465441SEvalZero   u_short cishort;
551*10465441SEvalZero   u32_t ciaddr1, ciaddr2, l, cidnsaddr;
552*10465441SEvalZero   ipcp_options no;    /* options we've seen Naks for */
553*10465441SEvalZero   ipcp_options try;    /* options to request next time */
554*10465441SEvalZero 
555*10465441SEvalZero   BZERO(&no, sizeof(no));
556*10465441SEvalZero   try = *go;
557*10465441SEvalZero 
558*10465441SEvalZero   /*
559*10465441SEvalZero    * Any Nak'd CIs must be in exactly the same order that we sent.
560*10465441SEvalZero    * Check packet length and CI length at each step.
561*10465441SEvalZero    * If we find any deviations, then this packet is bad.
562*10465441SEvalZero    */
563*10465441SEvalZero #define NAKCIADDR(opt, neg, old, code) \
564*10465441SEvalZero   if (go->neg && \
565*10465441SEvalZero       len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
566*10465441SEvalZero       p[1] == cilen && \
567*10465441SEvalZero       p[0] == opt) { \
568*10465441SEvalZero     len -= cilen; \
569*10465441SEvalZero     INCPTR(2, p); \
570*10465441SEvalZero     GETLONG(l, p); \
571*10465441SEvalZero     ciaddr1 = htonl(l); \
572*10465441SEvalZero     if (old) { \
573*10465441SEvalZero       GETLONG(l, p); \
574*10465441SEvalZero       ciaddr2 = htonl(l); \
575*10465441SEvalZero       no.old_addrs = 1; \
576*10465441SEvalZero     } else { \
577*10465441SEvalZero       ciaddr2 = 0; \
578*10465441SEvalZero     } \
579*10465441SEvalZero     no.neg = 1; \
580*10465441SEvalZero     code \
581*10465441SEvalZero   }
582*10465441SEvalZero 
583*10465441SEvalZero #define NAKCIVJ(opt, neg, code) \
584*10465441SEvalZero   if (go->neg && \
585*10465441SEvalZero       ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
586*10465441SEvalZero       len >= cilen && \
587*10465441SEvalZero       p[0] == opt) { \
588*10465441SEvalZero     len -= cilen; \
589*10465441SEvalZero     INCPTR(2, p); \
590*10465441SEvalZero     GETSHORT(cishort, p); \
591*10465441SEvalZero     no.neg = 1; \
592*10465441SEvalZero     code \
593*10465441SEvalZero   }
594*10465441SEvalZero 
595*10465441SEvalZero #define NAKCIDNS(opt, neg, code) \
596*10465441SEvalZero   if (go->neg && \
597*10465441SEvalZero       ((cilen = p[1]) == CILEN_ADDR) && \
598*10465441SEvalZero       len >= cilen && \
599*10465441SEvalZero       p[0] == opt) { \
600*10465441SEvalZero     len -= cilen; \
601*10465441SEvalZero     INCPTR(2, p); \
602*10465441SEvalZero     GETLONG(l, p); \
603*10465441SEvalZero     cidnsaddr = htonl(l); \
604*10465441SEvalZero     no.neg = 1; \
605*10465441SEvalZero     code \
606*10465441SEvalZero   }
607*10465441SEvalZero 
608*10465441SEvalZero   /*
609*10465441SEvalZero    * Accept the peer's idea of {our,his} address, if different
610*10465441SEvalZero    * from our idea, only if the accept_{local,remote} flag is set.
611*10465441SEvalZero    */
612*10465441SEvalZero   NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
613*10465441SEvalZero     if (go->accept_local && ciaddr1) { /* Do we know our address? */
614*10465441SEvalZero       try.ouraddr = ciaddr1;
615*10465441SEvalZero       IPCPDEBUG(LOG_INFO, ("local IP address %s\n",
616*10465441SEvalZero            inet_ntoa(ciaddr1)));
617*10465441SEvalZero     }
618*10465441SEvalZero     if (go->accept_remote && ciaddr2) { /* Does he know his? */
619*10465441SEvalZero       try.hisaddr = ciaddr2;
620*10465441SEvalZero       IPCPDEBUG(LOG_INFO, ("remote IP address %s\n",
621*10465441SEvalZero            inet_ntoa(ciaddr2)));
622*10465441SEvalZero     }
623*10465441SEvalZero   );
624*10465441SEvalZero 
625*10465441SEvalZero   /*
626*10465441SEvalZero    * Accept the peer's value of maxslotindex provided that it
627*10465441SEvalZero    * is less than what we asked for.  Turn off slot-ID compression
628*10465441SEvalZero    * if the peer wants.  Send old-style compress-type option if
629*10465441SEvalZero    * the peer wants.
630*10465441SEvalZero    */
631*10465441SEvalZero   NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
632*10465441SEvalZero     if (cilen == CILEN_VJ) {
633*10465441SEvalZero       GETCHAR(cimaxslotindex, p);
634*10465441SEvalZero       GETCHAR(cicflag, p);
635*10465441SEvalZero       if (cishort == IPCP_VJ_COMP) {
636*10465441SEvalZero         try.old_vj = 0;
637*10465441SEvalZero         if (cimaxslotindex < go->maxslotindex) {
638*10465441SEvalZero           try.maxslotindex = cimaxslotindex;
639*10465441SEvalZero         }
640*10465441SEvalZero         if (!cicflag) {
641*10465441SEvalZero           try.cflag = 0;
642*10465441SEvalZero         }
643*10465441SEvalZero       } else {
644*10465441SEvalZero         try.neg_vj = 0;
645*10465441SEvalZero       }
646*10465441SEvalZero     } else {
647*10465441SEvalZero       if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
648*10465441SEvalZero         try.old_vj = 1;
649*10465441SEvalZero         try.vj_protocol = cishort;
650*10465441SEvalZero       } else {
651*10465441SEvalZero         try.neg_vj = 0;
652*10465441SEvalZero       }
653*10465441SEvalZero     }
654*10465441SEvalZero   );
655*10465441SEvalZero 
656*10465441SEvalZero   NAKCIDNS(CI_MS_DNS1, req_dns1,
657*10465441SEvalZero       try.dnsaddr[0] = cidnsaddr;
658*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("primary DNS address %s\n", inet_ntoa(cidnsaddr)));
659*10465441SEvalZero       );
660*10465441SEvalZero 
661*10465441SEvalZero   NAKCIDNS(CI_MS_DNS2, req_dns2,
662*10465441SEvalZero       try.dnsaddr[1] = cidnsaddr;
663*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("secondary DNS address %s\n", inet_ntoa(cidnsaddr)));
664*10465441SEvalZero       );
665*10465441SEvalZero 
666*10465441SEvalZero   /*
667*10465441SEvalZero   * There may be remaining CIs, if the peer is requesting negotiation
668*10465441SEvalZero   * on an option that we didn't include in our request packet.
669*10465441SEvalZero   * If they want to negotiate about IP addresses, we comply.
670*10465441SEvalZero   * If they want us to ask for compression, we refuse.
671*10465441SEvalZero   */
672*10465441SEvalZero   while (len > CILEN_VOID) {
673*10465441SEvalZero     GETCHAR(citype, p);
674*10465441SEvalZero     GETCHAR(cilen, p);
675*10465441SEvalZero     if( (len -= cilen) < 0 ) {
676*10465441SEvalZero       goto bad;
677*10465441SEvalZero     }
678*10465441SEvalZero     next = p + cilen - 2;
679*10465441SEvalZero 
680*10465441SEvalZero     switch (citype) {
681*10465441SEvalZero       case CI_COMPRESSTYPE:
682*10465441SEvalZero         if (go->neg_vj || no.neg_vj ||
683*10465441SEvalZero             (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
684*10465441SEvalZero           goto bad;
685*10465441SEvalZero         }
686*10465441SEvalZero         no.neg_vj = 1;
687*10465441SEvalZero         break;
688*10465441SEvalZero       case CI_ADDRS:
689*10465441SEvalZero         if ((go->neg_addr && go->old_addrs) || no.old_addrs
690*10465441SEvalZero             || cilen != CILEN_ADDRS) {
691*10465441SEvalZero           goto bad;
692*10465441SEvalZero         }
693*10465441SEvalZero         try.neg_addr = 1;
694*10465441SEvalZero         try.old_addrs = 1;
695*10465441SEvalZero         GETLONG(l, p);
696*10465441SEvalZero         ciaddr1 = htonl(l);
697*10465441SEvalZero         if (ciaddr1 && go->accept_local) {
698*10465441SEvalZero           try.ouraddr = ciaddr1;
699*10465441SEvalZero         }
700*10465441SEvalZero         GETLONG(l, p);
701*10465441SEvalZero         ciaddr2 = htonl(l);
702*10465441SEvalZero         if (ciaddr2 && go->accept_remote) {
703*10465441SEvalZero           try.hisaddr = ciaddr2;
704*10465441SEvalZero         }
705*10465441SEvalZero         no.old_addrs = 1;
706*10465441SEvalZero         break;
707*10465441SEvalZero       case CI_ADDR:
708*10465441SEvalZero         if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {
709*10465441SEvalZero           goto bad;
710*10465441SEvalZero         }
711*10465441SEvalZero         try.old_addrs = 0;
712*10465441SEvalZero         GETLONG(l, p);
713*10465441SEvalZero         ciaddr1 = htonl(l);
714*10465441SEvalZero         if (ciaddr1 && go->accept_local) {
715*10465441SEvalZero           try.ouraddr = ciaddr1;
716*10465441SEvalZero         }
717*10465441SEvalZero         if (try.ouraddr != 0) {
718*10465441SEvalZero           try.neg_addr = 1;
719*10465441SEvalZero         }
720*10465441SEvalZero         no.neg_addr = 1;
721*10465441SEvalZero         break;
722*10465441SEvalZero     }
723*10465441SEvalZero     p = next;
724*10465441SEvalZero   }
725*10465441SEvalZero 
726*10465441SEvalZero   /* If there is still anything left, this packet is bad. */
727*10465441SEvalZero   if (len != 0) {
728*10465441SEvalZero     goto bad;
729*10465441SEvalZero   }
730*10465441SEvalZero 
731*10465441SEvalZero   /*
732*10465441SEvalZero    * OK, the Nak is good.  Now we can update state.
733*10465441SEvalZero    */
734*10465441SEvalZero   if (f->state != LS_OPENED) {
735*10465441SEvalZero     *go = try;
736*10465441SEvalZero   }
737*10465441SEvalZero 
738*10465441SEvalZero   return 1;
739*10465441SEvalZero 
740*10465441SEvalZero bad:
741*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp_nakci: received bad Nak!\n"));
742*10465441SEvalZero   return 0;
743*10465441SEvalZero }
744*10465441SEvalZero 
745*10465441SEvalZero 
746*10465441SEvalZero /*
747*10465441SEvalZero  * ipcp_rejci - Reject some of our CIs.
748*10465441SEvalZero  */
749*10465441SEvalZero static int
ipcp_rejci(fsm * f,u_char * p,int len)750*10465441SEvalZero ipcp_rejci(fsm *f, u_char *p, int len)
751*10465441SEvalZero {
752*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
753*10465441SEvalZero   u_char cimaxslotindex, ciflag, cilen;
754*10465441SEvalZero   u_short cishort;
755*10465441SEvalZero   u32_t cilong;
756*10465441SEvalZero   ipcp_options try;    /* options to request next time */
757*10465441SEvalZero 
758*10465441SEvalZero   try = *go;
759*10465441SEvalZero   /*
760*10465441SEvalZero    * Any Rejected CIs must be in exactly the same order that we sent.
761*10465441SEvalZero    * Check packet length and CI length at each step.
762*10465441SEvalZero    * If we find any deviations, then this packet is bad.
763*10465441SEvalZero    */
764*10465441SEvalZero #define REJCIADDR(opt, neg, old, val1, val2) \
765*10465441SEvalZero   if (go->neg && \
766*10465441SEvalZero       len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
767*10465441SEvalZero       p[1] == cilen && \
768*10465441SEvalZero       p[0] == opt) { \
769*10465441SEvalZero     u32_t l; \
770*10465441SEvalZero     len -= cilen; \
771*10465441SEvalZero     INCPTR(2, p); \
772*10465441SEvalZero     GETLONG(l, p); \
773*10465441SEvalZero     cilong = htonl(l); \
774*10465441SEvalZero     /* Check rejected value. */ \
775*10465441SEvalZero     if (cilong != val1) { \
776*10465441SEvalZero       goto bad; \
777*10465441SEvalZero     } \
778*10465441SEvalZero     if (old) { \
779*10465441SEvalZero       GETLONG(l, p); \
780*10465441SEvalZero       cilong = htonl(l); \
781*10465441SEvalZero       /* Check rejected value. */ \
782*10465441SEvalZero       if (cilong != val2) { \
783*10465441SEvalZero         goto bad; \
784*10465441SEvalZero       } \
785*10465441SEvalZero     } \
786*10465441SEvalZero     try.neg = 0; \
787*10465441SEvalZero   }
788*10465441SEvalZero 
789*10465441SEvalZero #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
790*10465441SEvalZero   if (go->neg && \
791*10465441SEvalZero       p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
792*10465441SEvalZero       len >= p[1] && \
793*10465441SEvalZero       p[0] == opt) { \
794*10465441SEvalZero     len -= p[1]; \
795*10465441SEvalZero     INCPTR(2, p); \
796*10465441SEvalZero     GETSHORT(cishort, p); \
797*10465441SEvalZero     /* Check rejected value. */  \
798*10465441SEvalZero     if (cishort != val) { \
799*10465441SEvalZero       goto bad; \
800*10465441SEvalZero     } \
801*10465441SEvalZero     if (!old) { \
802*10465441SEvalZero       GETCHAR(cimaxslotindex, p); \
803*10465441SEvalZero       if (cimaxslotindex != maxslot) { \
804*10465441SEvalZero         goto bad; \
805*10465441SEvalZero       } \
806*10465441SEvalZero       GETCHAR(ciflag, p); \
807*10465441SEvalZero       if (ciflag != cflag) { \
808*10465441SEvalZero         goto bad; \
809*10465441SEvalZero       } \
810*10465441SEvalZero     } \
811*10465441SEvalZero     try.neg = 0; \
812*10465441SEvalZero   }
813*10465441SEvalZero 
814*10465441SEvalZero #define REJCIDNS(opt, neg, dnsaddr) \
815*10465441SEvalZero   if (go->neg && \
816*10465441SEvalZero       ((cilen = p[1]) == CILEN_ADDR) && \
817*10465441SEvalZero       len >= cilen && \
818*10465441SEvalZero       p[0] == opt) { \
819*10465441SEvalZero     u32_t l; \
820*10465441SEvalZero     len -= cilen; \
821*10465441SEvalZero     INCPTR(2, p); \
822*10465441SEvalZero     GETLONG(l, p); \
823*10465441SEvalZero     cilong = htonl(l); \
824*10465441SEvalZero     /* Check rejected value. */ \
825*10465441SEvalZero     if (cilong != dnsaddr) { \
826*10465441SEvalZero       goto bad; \
827*10465441SEvalZero     } \
828*10465441SEvalZero     try.neg = 0; \
829*10465441SEvalZero   }
830*10465441SEvalZero 
831*10465441SEvalZero   REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
832*10465441SEvalZero         go->old_addrs, go->ouraddr, go->hisaddr);
833*10465441SEvalZero 
834*10465441SEvalZero   REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
835*10465441SEvalZero       go->maxslotindex, go->cflag);
836*10465441SEvalZero 
837*10465441SEvalZero   REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
838*10465441SEvalZero 
839*10465441SEvalZero   REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
840*10465441SEvalZero 
841*10465441SEvalZero   /*
842*10465441SEvalZero    * If there are any remaining CIs, then this packet is bad.
843*10465441SEvalZero    */
844*10465441SEvalZero   if (len != 0) {
845*10465441SEvalZero     goto bad;
846*10465441SEvalZero   }
847*10465441SEvalZero   /*
848*10465441SEvalZero    * Now we can update state.
849*10465441SEvalZero    */
850*10465441SEvalZero   if (f->state != LS_OPENED) {
851*10465441SEvalZero     *go = try;
852*10465441SEvalZero   }
853*10465441SEvalZero   return 1;
854*10465441SEvalZero 
855*10465441SEvalZero bad:
856*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp_rejci: received bad Reject!\n"));
857*10465441SEvalZero   return 0;
858*10465441SEvalZero }
859*10465441SEvalZero 
860*10465441SEvalZero 
861*10465441SEvalZero /*
862*10465441SEvalZero  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
863*10465441SEvalZero  *
864*10465441SEvalZero  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
865*10465441SEvalZero  * appropriately.  If reject_if_disagree is non-zero, doesn't return
866*10465441SEvalZero  * CONFNAK; returns CONFREJ if it can't return CONFACK.
867*10465441SEvalZero  */
868*10465441SEvalZero static int
ipcp_reqci(fsm * f,u_char * inp,int * len,int reject_if_disagree)869*10465441SEvalZero ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)
870*10465441SEvalZero {
871*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[f->unit];
872*10465441SEvalZero   ipcp_options *ho = &ipcp_hisoptions[f->unit];
873*10465441SEvalZero   ipcp_options *ao = &ipcp_allowoptions[f->unit];
874*10465441SEvalZero #ifdef OLD_CI_ADDRS
875*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
876*10465441SEvalZero #endif
877*10465441SEvalZero   u_char *cip, *next;     /* Pointer to current and next CIs */
878*10465441SEvalZero   u_short cilen, citype;  /* Parsed len, type */
879*10465441SEvalZero   u_short cishort;        /* Parsed short value */
880*10465441SEvalZero   u32_t tl, ciaddr1;      /* Parsed address values */
881*10465441SEvalZero #ifdef OLD_CI_ADDRS
882*10465441SEvalZero   u32_t ciaddr2;          /* Parsed address values */
883*10465441SEvalZero #endif
884*10465441SEvalZero   int rc = CONFACK;       /* Final packet return code */
885*10465441SEvalZero   int orc;                /* Individual option return code */
886*10465441SEvalZero   u_char *p;              /* Pointer to next char to parse */
887*10465441SEvalZero   u_char *ucp = inp;      /* Pointer to current output char */
888*10465441SEvalZero   int l = *len;           /* Length left */
889*10465441SEvalZero   u_char maxslotindex, cflag;
890*10465441SEvalZero   int d;
891*10465441SEvalZero 
892*10465441SEvalZero   cis_received[f->unit] = 1;
893*10465441SEvalZero 
894*10465441SEvalZero   /*
895*10465441SEvalZero    * Reset all his options.
896*10465441SEvalZero    */
897*10465441SEvalZero   BZERO(ho, sizeof(*ho));
898*10465441SEvalZero 
899*10465441SEvalZero   /*
900*10465441SEvalZero    * Process all his options.
901*10465441SEvalZero    */
902*10465441SEvalZero   next = inp;
903*10465441SEvalZero   while (l) {
904*10465441SEvalZero     orc = CONFACK;       /* Assume success */
905*10465441SEvalZero     cip = p = next;      /* Remember begining of CI */
906*10465441SEvalZero     if (l < 2 ||         /* Not enough data for CI header or */
907*10465441SEvalZero         p[1] < 2 ||      /*  CI length too small or */
908*10465441SEvalZero         p[1] > l) {      /*  CI length too big? */
909*10465441SEvalZero       IPCPDEBUG(LOG_INFO, ("ipcp_reqci: bad CI length!\n"));
910*10465441SEvalZero       orc = CONFREJ;     /* Reject bad CI */
911*10465441SEvalZero       cilen = (u_short)l;/* Reject till end of packet */
912*10465441SEvalZero       l = 0;             /* Don't loop again */
913*10465441SEvalZero       goto endswitch;
914*10465441SEvalZero     }
915*10465441SEvalZero     GETCHAR(citype, p);  /* Parse CI type */
916*10465441SEvalZero     GETCHAR(cilen, p);   /* Parse CI length */
917*10465441SEvalZero     l -= cilen;          /* Adjust remaining length */
918*10465441SEvalZero     next += cilen;       /* Step to next CI */
919*10465441SEvalZero 
920*10465441SEvalZero     switch (citype) {      /* Check CI type */
921*10465441SEvalZero #ifdef OLD_CI_ADDRS /* Need to save space... */
922*10465441SEvalZero       case CI_ADDRS:
923*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received ADDRS\n"));
924*10465441SEvalZero         if (!ao->neg_addr ||
925*10465441SEvalZero             cilen != CILEN_ADDRS) {  /* Check CI length */
926*10465441SEvalZero           orc = CONFREJ;    /* Reject CI */
927*10465441SEvalZero           break;
928*10465441SEvalZero         }
929*10465441SEvalZero 
930*10465441SEvalZero         /*
931*10465441SEvalZero          * If he has no address, or if we both have his address but
932*10465441SEvalZero          * disagree about it, then NAK it with our idea.
933*10465441SEvalZero          * In particular, if we don't know his address, but he does,
934*10465441SEvalZero          * then accept it.
935*10465441SEvalZero          */
936*10465441SEvalZero         GETLONG(tl, p);    /* Parse source address (his) */
937*10465441SEvalZero         ciaddr1 = htonl(tl);
938*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("his addr %s\n", inet_ntoa(ciaddr1)));
939*10465441SEvalZero         if (ciaddr1 != wo->hisaddr
940*10465441SEvalZero             && (ciaddr1 == 0 || !wo->accept_remote)) {
941*10465441SEvalZero           orc = CONFNAK;
942*10465441SEvalZero           if (!reject_if_disagree) {
943*10465441SEvalZero             DECPTR(sizeof(u32_t), p);
944*10465441SEvalZero             tl = ntohl(wo->hisaddr);
945*10465441SEvalZero             PUTLONG(tl, p);
946*10465441SEvalZero           }
947*10465441SEvalZero         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
948*10465441SEvalZero           /*
949*10465441SEvalZero            * If neither we nor he knows his address, reject the option.
950*10465441SEvalZero            */
951*10465441SEvalZero           orc = CONFREJ;
952*10465441SEvalZero           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */
953*10465441SEvalZero           break;
954*10465441SEvalZero         }
955*10465441SEvalZero 
956*10465441SEvalZero         /*
957*10465441SEvalZero          * If he doesn't know our address, or if we both have our address
958*10465441SEvalZero          * but disagree about it, then NAK it with our idea.
959*10465441SEvalZero          */
960*10465441SEvalZero         GETLONG(tl, p);    /* Parse desination address (ours) */
961*10465441SEvalZero         ciaddr2 = htonl(tl);
962*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("our addr %s\n", inet_ntoa(ciaddr2)));
963*10465441SEvalZero         if (ciaddr2 != wo->ouraddr) {
964*10465441SEvalZero           if (ciaddr2 == 0 || !wo->accept_local) {
965*10465441SEvalZero             orc = CONFNAK;
966*10465441SEvalZero             if (!reject_if_disagree) {
967*10465441SEvalZero               DECPTR(sizeof(u32_t), p);
968*10465441SEvalZero               tl = ntohl(wo->ouraddr);
969*10465441SEvalZero               PUTLONG(tl, p);
970*10465441SEvalZero             }
971*10465441SEvalZero           } else {
972*10465441SEvalZero             go->ouraddr = ciaddr2;  /* accept peer's idea */
973*10465441SEvalZero           }
974*10465441SEvalZero         }
975*10465441SEvalZero 
976*10465441SEvalZero         ho->neg_addr = 1;
977*10465441SEvalZero         ho->old_addrs = 1;
978*10465441SEvalZero         ho->hisaddr = ciaddr1;
979*10465441SEvalZero         ho->ouraddr = ciaddr2;
980*10465441SEvalZero         break;
981*10465441SEvalZero #endif
982*10465441SEvalZero 
983*10465441SEvalZero       case CI_ADDR:
984*10465441SEvalZero         if (!ao->neg_addr) {
985*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR not allowed\n"));
986*10465441SEvalZero           orc = CONFREJ;        /* Reject CI */
987*10465441SEvalZero           break;
988*10465441SEvalZero         } else if (cilen != CILEN_ADDR) {  /* Check CI length */
989*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR bad len\n"));
990*10465441SEvalZero           orc = CONFREJ;        /* Reject CI */
991*10465441SEvalZero           break;
992*10465441SEvalZero         }
993*10465441SEvalZero 
994*10465441SEvalZero         /*
995*10465441SEvalZero          * If he has no address, or if we both have his address but
996*10465441SEvalZero          * disagree about it, then NAK it with our idea.
997*10465441SEvalZero          * In particular, if we don't know his address, but he does,
998*10465441SEvalZero          * then accept it.
999*10465441SEvalZero          */
1000*10465441SEvalZero         GETLONG(tl, p);  /* Parse source address (his) */
1001*10465441SEvalZero         ciaddr1 = htonl(tl);
1002*10465441SEvalZero         if (ciaddr1 != wo->hisaddr
1003*10465441SEvalZero             && (ciaddr1 == 0 || !wo->accept_remote)) {
1004*10465441SEvalZero           orc = CONFNAK;
1005*10465441SEvalZero           if (!reject_if_disagree) {
1006*10465441SEvalZero             DECPTR(sizeof(u32_t), p);
1007*10465441SEvalZero             tl = ntohl(wo->hisaddr);
1008*10465441SEvalZero             PUTLONG(tl, p);
1009*10465441SEvalZero           }
1010*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));
1011*10465441SEvalZero         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
1012*10465441SEvalZero           /*
1013*10465441SEvalZero            * Don't ACK an address of 0.0.0.0 - reject it instead.
1014*10465441SEvalZero            */
1015*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));
1016*10465441SEvalZero           orc = CONFREJ;
1017*10465441SEvalZero           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */
1018*10465441SEvalZero           break;
1019*10465441SEvalZero         }
1020*10465441SEvalZero 
1021*10465441SEvalZero         ho->neg_addr = 1;
1022*10465441SEvalZero         ho->hisaddr = ciaddr1;
1023*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));
1024*10465441SEvalZero         break;
1025*10465441SEvalZero 
1026*10465441SEvalZero       case CI_MS_DNS1:
1027*10465441SEvalZero       case CI_MS_DNS2:
1028*10465441SEvalZero         /* Microsoft primary or secondary DNS request */
1029*10465441SEvalZero         d = citype == CI_MS_DNS2;
1030*10465441SEvalZero 
1031*10465441SEvalZero         /* If we do not have a DNS address then we cannot send it */
1032*10465441SEvalZero         if (ao->dnsaddr[d] == 0 ||
1033*10465441SEvalZero             cilen != CILEN_ADDR) {  /* Check CI length */
1034*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting DNS%d Request\n", d+1));
1035*10465441SEvalZero           orc = CONFREJ;        /* Reject CI */
1036*10465441SEvalZero           break;
1037*10465441SEvalZero         }
1038*10465441SEvalZero         GETLONG(tl, p);
1039*10465441SEvalZero         if (htonl(tl) != ao->dnsaddr[d]) {
1040*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking DNS%d Request %s\n",
1041*10465441SEvalZero                 d+1, inet_ntoa(tl)));
1042*10465441SEvalZero           DECPTR(sizeof(u32_t), p);
1043*10465441SEvalZero           tl = ntohl(ao->dnsaddr[d]);
1044*10465441SEvalZero           PUTLONG(tl, p);
1045*10465441SEvalZero           orc = CONFNAK;
1046*10465441SEvalZero         }
1047*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received DNS%d Request\n", d+1));
1048*10465441SEvalZero         break;
1049*10465441SEvalZero 
1050*10465441SEvalZero       case CI_MS_WINS1:
1051*10465441SEvalZero       case CI_MS_WINS2:
1052*10465441SEvalZero         /* Microsoft primary or secondary WINS request */
1053*10465441SEvalZero         d = citype == CI_MS_WINS2;
1054*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received WINS%d Request\n", d+1));
1055*10465441SEvalZero 
1056*10465441SEvalZero         /* If we do not have a DNS address then we cannot send it */
1057*10465441SEvalZero         if (ao->winsaddr[d] == 0 ||
1058*10465441SEvalZero           cilen != CILEN_ADDR) {  /* Check CI length */
1059*10465441SEvalZero           orc = CONFREJ;      /* Reject CI */
1060*10465441SEvalZero           break;
1061*10465441SEvalZero         }
1062*10465441SEvalZero         GETLONG(tl, p);
1063*10465441SEvalZero         if (htonl(tl) != ao->winsaddr[d]) {
1064*10465441SEvalZero           DECPTR(sizeof(u32_t), p);
1065*10465441SEvalZero           tl = ntohl(ao->winsaddr[d]);
1066*10465441SEvalZero           PUTLONG(tl, p);
1067*10465441SEvalZero           orc = CONFNAK;
1068*10465441SEvalZero         }
1069*10465441SEvalZero         break;
1070*10465441SEvalZero 
1071*10465441SEvalZero       case CI_COMPRESSTYPE:
1072*10465441SEvalZero         if (!ao->neg_vj) {
1073*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));
1074*10465441SEvalZero           orc = CONFREJ;
1075*10465441SEvalZero           break;
1076*10465441SEvalZero         } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {
1077*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));
1078*10465441SEvalZero           orc = CONFREJ;
1079*10465441SEvalZero           break;
1080*10465441SEvalZero         }
1081*10465441SEvalZero         GETSHORT(cishort, p);
1082*10465441SEvalZero 
1083*10465441SEvalZero         if (!(cishort == IPCP_VJ_COMP ||
1084*10465441SEvalZero             (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
1085*10465441SEvalZero           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));
1086*10465441SEvalZero           orc = CONFREJ;
1087*10465441SEvalZero           break;
1088*10465441SEvalZero         }
1089*10465441SEvalZero 
1090*10465441SEvalZero         ho->neg_vj = 1;
1091*10465441SEvalZero         ho->vj_protocol = cishort;
1092*10465441SEvalZero         if (cilen == CILEN_VJ) {
1093*10465441SEvalZero           GETCHAR(maxslotindex, p);
1094*10465441SEvalZero           if (maxslotindex > ao->maxslotindex) {
1095*10465441SEvalZero             IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));
1096*10465441SEvalZero             orc = CONFNAK;
1097*10465441SEvalZero             if (!reject_if_disagree) {
1098*10465441SEvalZero               DECPTR(1, p);
1099*10465441SEvalZero               PUTCHAR(ao->maxslotindex, p);
1100*10465441SEvalZero             }
1101*10465441SEvalZero           }
1102*10465441SEvalZero           GETCHAR(cflag, p);
1103*10465441SEvalZero           if (cflag && !ao->cflag) {
1104*10465441SEvalZero             IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ cflag %d\n", cflag));
1105*10465441SEvalZero             orc = CONFNAK;
1106*10465441SEvalZero             if (!reject_if_disagree) {
1107*10465441SEvalZero               DECPTR(1, p);
1108*10465441SEvalZero               PUTCHAR(wo->cflag, p);
1109*10465441SEvalZero             }
1110*10465441SEvalZero           }
1111*10465441SEvalZero           ho->maxslotindex = maxslotindex;
1112*10465441SEvalZero           ho->cflag = cflag;
1113*10465441SEvalZero         } else {
1114*10465441SEvalZero           ho->old_vj = 1;
1115*10465441SEvalZero           ho->maxslotindex = MAX_SLOTS - 1;
1116*10465441SEvalZero           ho->cflag = 1;
1117*10465441SEvalZero         }
1118*10465441SEvalZero         IPCPDEBUG(LOG_INFO, (
1119*10465441SEvalZero               "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",
1120*10465441SEvalZero               ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));
1121*10465441SEvalZero         break;
1122*10465441SEvalZero 
1123*10465441SEvalZero       default:
1124*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting unknown CI type %d\n", citype));
1125*10465441SEvalZero         orc = CONFREJ;
1126*10465441SEvalZero         break;
1127*10465441SEvalZero     }
1128*10465441SEvalZero 
1129*10465441SEvalZero endswitch:
1130*10465441SEvalZero     if (orc == CONFACK &&    /* Good CI */
1131*10465441SEvalZero         rc != CONFACK) {     /*  but prior CI wasnt? */
1132*10465441SEvalZero       continue;              /* Don't send this one */
1133*10465441SEvalZero     }
1134*10465441SEvalZero 
1135*10465441SEvalZero     if (orc == CONFNAK) {    /* Nak this CI? */
1136*10465441SEvalZero       if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */
1137*10465441SEvalZero         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting too many naks\n"));
1138*10465441SEvalZero         orc = CONFREJ;       /* Get tough if so */
1139*10465441SEvalZero       } else {
1140*10465441SEvalZero         if (rc == CONFREJ) { /* Rejecting prior CI? */
1141*10465441SEvalZero           continue;          /* Don't send this one */
1142*10465441SEvalZero         }
1143*10465441SEvalZero         if (rc == CONFACK) { /* Ack'd all prior CIs? */
1144*10465441SEvalZero           rc = CONFNAK;      /* Not anymore... */
1145*10465441SEvalZero           ucp = inp;         /* Backup */
1146*10465441SEvalZero         }
1147*10465441SEvalZero       }
1148*10465441SEvalZero     }
1149*10465441SEvalZero 
1150*10465441SEvalZero     if (orc == CONFREJ &&    /* Reject this CI */
1151*10465441SEvalZero         rc != CONFREJ) {  /*  but no prior ones? */
1152*10465441SEvalZero       rc = CONFREJ;
1153*10465441SEvalZero       ucp = inp;        /* Backup */
1154*10465441SEvalZero     }
1155*10465441SEvalZero 
1156*10465441SEvalZero     /* Need to move CI? */
1157*10465441SEvalZero     if (ucp != cip) {
1158*10465441SEvalZero       BCOPY(cip, ucp, cilen);  /* Move it */
1159*10465441SEvalZero     }
1160*10465441SEvalZero 
1161*10465441SEvalZero     /* Update output pointer */
1162*10465441SEvalZero     INCPTR(cilen, ucp);
1163*10465441SEvalZero   }
1164*10465441SEvalZero 
1165*10465441SEvalZero   /*
1166*10465441SEvalZero    * If we aren't rejecting this packet, and we want to negotiate
1167*10465441SEvalZero    * their address, and they didn't send their address, then we
1168*10465441SEvalZero    * send a NAK with a CI_ADDR option appended.  We assume the
1169*10465441SEvalZero    * input buffer is long enough that we can append the extra
1170*10465441SEvalZero    * option safely.
1171*10465441SEvalZero    */
1172*10465441SEvalZero   if (rc != CONFREJ && !ho->neg_addr &&
1173*10465441SEvalZero       wo->req_addr && !reject_if_disagree) {
1174*10465441SEvalZero     IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Requesting peer address\n"));
1175*10465441SEvalZero     if (rc == CONFACK) {
1176*10465441SEvalZero       rc = CONFNAK;
1177*10465441SEvalZero       ucp = inp;        /* reset pointer */
1178*10465441SEvalZero       wo->req_addr = 0;    /* don't ask again */
1179*10465441SEvalZero     }
1180*10465441SEvalZero     PUTCHAR(CI_ADDR, ucp);
1181*10465441SEvalZero     PUTCHAR(CILEN_ADDR, ucp);
1182*10465441SEvalZero     tl = ntohl(wo->hisaddr);
1183*10465441SEvalZero     PUTLONG(tl, ucp);
1184*10465441SEvalZero   }
1185*10465441SEvalZero 
1186*10465441SEvalZero   *len = (int)(ucp - inp);    /* Compute output length */
1187*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));
1188*10465441SEvalZero   return (rc);      /* Return final code */
1189*10465441SEvalZero }
1190*10465441SEvalZero 
1191*10465441SEvalZero 
1192*10465441SEvalZero #if 0
1193*10465441SEvalZero /*
1194*10465441SEvalZero  * ip_check_options - check that any IP-related options are OK,
1195*10465441SEvalZero  * and assign appropriate defaults.
1196*10465441SEvalZero  */
1197*10465441SEvalZero static void
1198*10465441SEvalZero ip_check_options(u_long localAddr)
1199*10465441SEvalZero {
1200*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[0];
1201*10465441SEvalZero 
1202*10465441SEvalZero   /*
1203*10465441SEvalZero    * Load our default IP address but allow the remote host to give us
1204*10465441SEvalZero    * a new address.
1205*10465441SEvalZero    */
1206*10465441SEvalZero   if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {
1207*10465441SEvalZero     wo->accept_local = 1;  /* don't insist on this default value */
1208*10465441SEvalZero     wo->ouraddr = htonl(localAddr);
1209*10465441SEvalZero   }
1210*10465441SEvalZero }
1211*10465441SEvalZero #endif
1212*10465441SEvalZero 
1213*10465441SEvalZero 
1214*10465441SEvalZero /*
1215*10465441SEvalZero  * ipcp_up - IPCP has come UP.
1216*10465441SEvalZero  *
1217*10465441SEvalZero  * Configure the IP network interface appropriately and bring it up.
1218*10465441SEvalZero  */
1219*10465441SEvalZero static void
ipcp_up(fsm * f)1220*10465441SEvalZero ipcp_up(fsm *f)
1221*10465441SEvalZero {
1222*10465441SEvalZero   u32_t mask;
1223*10465441SEvalZero   ipcp_options *ho = &ipcp_hisoptions[f->unit];
1224*10465441SEvalZero   ipcp_options *go = &ipcp_gotoptions[f->unit];
1225*10465441SEvalZero   ipcp_options *wo = &ipcp_wantoptions[f->unit];
1226*10465441SEvalZero 
1227*10465441SEvalZero   np_up(f->unit, PPP_IP);
1228*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp: up\n"));
1229*10465441SEvalZero 
1230*10465441SEvalZero   /*
1231*10465441SEvalZero    * We must have a non-zero IP address for both ends of the link.
1232*10465441SEvalZero    */
1233*10465441SEvalZero   if (!ho->neg_addr) {
1234*10465441SEvalZero     ho->hisaddr = wo->hisaddr;
1235*10465441SEvalZero   }
1236*10465441SEvalZero 
1237*10465441SEvalZero   if (ho->hisaddr == 0) {
1238*10465441SEvalZero     IPCPDEBUG(LOG_ERR, ("Could not determine remote IP address\n"));
1239*10465441SEvalZero     ipcp_close(f->unit, "Could not determine remote IP address");
1240*10465441SEvalZero     return;
1241*10465441SEvalZero   }
1242*10465441SEvalZero   if (go->ouraddr == 0) {
1243*10465441SEvalZero     IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n"));
1244*10465441SEvalZero     ipcp_close(f->unit, "Could not determine local IP address");
1245*10465441SEvalZero     return;
1246*10465441SEvalZero   }
1247*10465441SEvalZero 
1248*10465441SEvalZero   if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
1249*10465441SEvalZero     /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/
1250*10465441SEvalZero   }
1251*10465441SEvalZero 
1252*10465441SEvalZero   /*
1253*10465441SEvalZero    * Check that the peer is allowed to use the IP address it wants.
1254*10465441SEvalZero    */
1255*10465441SEvalZero   if (!auth_ip_addr(f->unit, ho->hisaddr)) {
1256*10465441SEvalZero     IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n",
1257*10465441SEvalZero         inet_ntoa(ho->hisaddr)));
1258*10465441SEvalZero     ipcp_close(f->unit, "Unauthorized remote IP address");
1259*10465441SEvalZero     return;
1260*10465441SEvalZero   }
1261*10465441SEvalZero 
1262*10465441SEvalZero   /* set tcp compression */
1263*10465441SEvalZero   sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
1264*10465441SEvalZero 
1265*10465441SEvalZero   /*
1266*10465441SEvalZero    * Set IP addresses and (if specified) netmask.
1267*10465441SEvalZero    */
1268*10465441SEvalZero   mask = GetMask(go->ouraddr);
1269*10465441SEvalZero 
1270*10465441SEvalZero   if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {
1271*10465441SEvalZero     IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n"));
1272*10465441SEvalZero     ipcp_close(f->unit, "Interface configuration failed");
1273*10465441SEvalZero     return;
1274*10465441SEvalZero   }
1275*10465441SEvalZero 
1276*10465441SEvalZero   /* bring the interface up for IP */
1277*10465441SEvalZero   if (!sifup(f->unit)) {
1278*10465441SEvalZero     IPCPDEBUG(LOG_WARNING, ("sifup failed\n"));
1279*10465441SEvalZero     ipcp_close(f->unit, "Interface configuration failed");
1280*10465441SEvalZero     return;
1281*10465441SEvalZero   }
1282*10465441SEvalZero 
1283*10465441SEvalZero   sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
1284*10465441SEvalZero 
1285*10465441SEvalZero   /* assign a default route through the interface if required */
1286*10465441SEvalZero   if (ipcp_wantoptions[f->unit].default_route) {
1287*10465441SEvalZero     if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {
1288*10465441SEvalZero       default_route_set[f->unit] = 1;
1289*10465441SEvalZero     }
1290*10465441SEvalZero   }
1291*10465441SEvalZero 
1292*10465441SEvalZero   IPCPDEBUG(LOG_NOTICE, ("local  IP address %s\n", inet_ntoa(go->ouraddr)));
1293*10465441SEvalZero   IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr)));
1294*10465441SEvalZero   if (go->dnsaddr[0]) {
1295*10465441SEvalZero     IPCPDEBUG(LOG_NOTICE, ("primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));
1296*10465441SEvalZero   }
1297*10465441SEvalZero   if (go->dnsaddr[1]) {
1298*10465441SEvalZero     IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));
1299*10465441SEvalZero   }
1300*10465441SEvalZero }
1301*10465441SEvalZero 
1302*10465441SEvalZero 
1303*10465441SEvalZero /*
1304*10465441SEvalZero  * ipcp_down - IPCP has gone DOWN.
1305*10465441SEvalZero  *
1306*10465441SEvalZero  * Take the IP network interface down, clear its addresses
1307*10465441SEvalZero  * and delete routes through it.
1308*10465441SEvalZero  */
1309*10465441SEvalZero static void
ipcp_down(fsm * f)1310*10465441SEvalZero ipcp_down(fsm *f)
1311*10465441SEvalZero {
1312*10465441SEvalZero   IPCPDEBUG(LOG_INFO, ("ipcp: down\n"));
1313*10465441SEvalZero   np_down(f->unit, PPP_IP);
1314*10465441SEvalZero   sifvjcomp(f->unit, 0, 0, 0);
1315*10465441SEvalZero 
1316*10465441SEvalZero   sifdown(f->unit);
1317*10465441SEvalZero   ipcp_clear_addrs(f->unit);
1318*10465441SEvalZero }
1319*10465441SEvalZero 
1320*10465441SEvalZero 
1321*10465441SEvalZero /*
1322*10465441SEvalZero  * ipcp_clear_addrs() - clear the interface addresses, routes, etc.
1323*10465441SEvalZero  */
1324*10465441SEvalZero static void
ipcp_clear_addrs(int unit)1325*10465441SEvalZero ipcp_clear_addrs(int unit)
1326*10465441SEvalZero {
1327*10465441SEvalZero   u32_t ouraddr, hisaddr;
1328*10465441SEvalZero 
1329*10465441SEvalZero   ouraddr = ipcp_gotoptions[unit].ouraddr;
1330*10465441SEvalZero   hisaddr = ipcp_hisoptions[unit].hisaddr;
1331*10465441SEvalZero   if (default_route_set[unit]) {
1332*10465441SEvalZero     cifdefaultroute(unit, ouraddr, hisaddr);
1333*10465441SEvalZero     default_route_set[unit] = 0;
1334*10465441SEvalZero   }
1335*10465441SEvalZero   cifaddr(unit, ouraddr, hisaddr);
1336*10465441SEvalZero }
1337*10465441SEvalZero 
1338*10465441SEvalZero 
1339*10465441SEvalZero /*
1340*10465441SEvalZero  * ipcp_finished - possibly shut down the lower layers.
1341*10465441SEvalZero  */
1342*10465441SEvalZero static void
ipcp_finished(fsm * f)1343*10465441SEvalZero ipcp_finished(fsm *f)
1344*10465441SEvalZero {
1345*10465441SEvalZero   np_finished(f->unit, PPP_IP);
1346*10465441SEvalZero }
1347*10465441SEvalZero 
1348*10465441SEvalZero #if PPP_ADDITIONAL_CALLBACKS
1349*10465441SEvalZero static int
ipcp_printpkt(u_char * p,int plen,void (* printer)(void *,char *,...),void * arg)1350*10465441SEvalZero ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
1351*10465441SEvalZero {
1352*10465441SEvalZero   LWIP_UNUSED_ARG(p);
1353*10465441SEvalZero   LWIP_UNUSED_ARG(plen);
1354*10465441SEvalZero   LWIP_UNUSED_ARG(printer);
1355*10465441SEvalZero   LWIP_UNUSED_ARG(arg);
1356*10465441SEvalZero   return 0;
1357*10465441SEvalZero }
1358*10465441SEvalZero 
1359*10465441SEvalZero /*
1360*10465441SEvalZero  * ip_active_pkt - see if this IP packet is worth bringing the link up for.
1361*10465441SEvalZero  * We don't bring the link up for IP fragments or for TCP FIN packets
1362*10465441SEvalZero  * with no data.
1363*10465441SEvalZero  */
1364*10465441SEvalZero #define IP_HDRLEN   20  /* bytes */
1365*10465441SEvalZero #define IP_OFFMASK  0x1fff
1366*10465441SEvalZero #define IPPROTO_TCP 6
1367*10465441SEvalZero #define TCP_HDRLEN  20
1368*10465441SEvalZero #define TH_FIN      0x01
1369*10465441SEvalZero 
1370*10465441SEvalZero /*
1371*10465441SEvalZero  * We use these macros because the IP header may be at an odd address,
1372*10465441SEvalZero  * and some compilers might use word loads to get th_off or ip_hl.
1373*10465441SEvalZero  */
1374*10465441SEvalZero 
1375*10465441SEvalZero #define net_short(x)    (((x)[0] << 8) + (x)[1])
1376*10465441SEvalZero #define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)
1377*10465441SEvalZero #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)
1378*10465441SEvalZero #define get_ipproto(x)  (((unsigned char *)(x))[9])
1379*10465441SEvalZero #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1380*10465441SEvalZero #define get_tcpflags(x) (((unsigned char *)(x))[13])
1381*10465441SEvalZero 
1382*10465441SEvalZero static int
ip_active_pkt(u_char * pkt,int len)1383*10465441SEvalZero ip_active_pkt(u_char *pkt, int len)
1384*10465441SEvalZero {
1385*10465441SEvalZero   u_char *tcp;
1386*10465441SEvalZero   int hlen;
1387*10465441SEvalZero 
1388*10465441SEvalZero   len -= PPP_HDRLEN;
1389*10465441SEvalZero   pkt += PPP_HDRLEN;
1390*10465441SEvalZero   if (len < IP_HDRLEN) {
1391*10465441SEvalZero     return 0;
1392*10465441SEvalZero   }
1393*10465441SEvalZero   if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {
1394*10465441SEvalZero     return 0;
1395*10465441SEvalZero   }
1396*10465441SEvalZero   if (get_ipproto(pkt) != IPPROTO_TCP) {
1397*10465441SEvalZero     return 1;
1398*10465441SEvalZero   }
1399*10465441SEvalZero   hlen = get_iphl(pkt) * 4;
1400*10465441SEvalZero   if (len < hlen + TCP_HDRLEN) {
1401*10465441SEvalZero     return 0;
1402*10465441SEvalZero   }
1403*10465441SEvalZero   tcp = pkt + hlen;
1404*10465441SEvalZero   if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {
1405*10465441SEvalZero     return 0;
1406*10465441SEvalZero   }
1407*10465441SEvalZero   return 1;
1408*10465441SEvalZero }
1409*10465441SEvalZero #endif /* PPP_ADDITIONAL_CALLBACKS */
1410*10465441SEvalZero 
1411*10465441SEvalZero #endif /* PPP_SUPPORT */
1412