OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [lwIP_MCF5235_GCC/] [lwip/] [src/] [netif/] [ppp/] [ipcp.c] - Blame information for rev 583

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 583 jeremybenn
/*****************************************************************************
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 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.