source: rtems/cpukit/pppd/ipcp.c @ 9d770ab5

4.104.114.84.95
Last change on this file since 9d770ab5 was abb63593, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/03/05 at 06:46:57

2005-02-03 Ralf Corsepius <ralf.corsepius@…>

PR 755/rtems

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