source: rtems/cpukit/pppd/ipcp.c @ df49c60

4.104.114.84.95
Last change on this file since df49c60 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/99 at 22:12:50

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

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