source: rtems/cpukit/pppd/ipcp.c @ 6d9ade62

4.104.114.84.95
Last change on this file since 6d9ade62 was 19ed3cf, checked in by Joel Sherrill <joel.sherrill@…>, on 09/07/02 at 23:07:58

2002-09-07 Joel Sherrill <joel@…>

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