source: rtems/cpukit/pppd/ipcp.c @ 0286b9f

4.104.114.84.9
Last change on this file since 0286b9f was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 31, 2002 at 9:42:11 PM

2001-01-31 Mike Siers <mikes@…>

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