source: rtems/cpukit/pppd/ipcp.c @ 66c0078

4.115
Last change on this file since 66c0078 was 05c1886, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/30/09 at 16:01:51

Whitespace removal.

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