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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libnetworking/] [pppd/] [ipcp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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