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