Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_ipv6cp.c Source File

lwip_ipv6cp.c

00001 /*
00002  * ipv6cp.c - PPP IPV6 Control Protocol.
00003  *
00004  * Copyright (c) 1999 Tommi Komulainen.  All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. The name(s) of the authors of this software must not be used to
00019  *    endorse or promote products derived from this software without
00020  *    prior written permission.
00021  *
00022  * 4. Redistributions of any form whatsoever must retain the following
00023  *    acknowledgment:
00024  *    "This product includes software developed by Tommi Komulainen
00025  *     <Tommi.Komulainen@iki.fi>".
00026  *
00027  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
00028  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00029  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00030  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00031  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00032  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00033  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00034  *
00035  */
00036 
00037 /*  Original version, based on RFC2023 :
00038 
00039     Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
00040     Alain.Durand@imag.fr, IMAG,
00041     Jean-Luc.Richier@imag.fr, IMAG-LSR.
00042 
00043     Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
00044     Alain.Durand@imag.fr, IMAG,
00045     Jean-Luc.Richier@imag.fr, IMAG-LSR.
00046 
00047     Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
00048     Économique ayant pour membres BULL S.A. et l'INRIA).
00049 
00050     Ce logiciel informatique est disponible aux conditions
00051     usuelles dans la recherche, c'est-à-dire qu'il peut
00052     être utilisé, copié, modifié, distribué à l'unique
00053     condition que ce texte soit conservé afin que
00054     l'origine de ce logiciel soit reconnue.
00055 
00056     Le nom de l'Institut National de Recherche en Informatique
00057     et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
00058     ou physique ayant participé à l'élaboration de ce logiciel ne peut
00059     être utilisé sans son accord préalable explicite.
00060 
00061     Ce logiciel est fourni tel quel sans aucune garantie,
00062     support ou responsabilité d'aucune sorte.
00063     Ce logiciel est dérivé de sources d'origine
00064     "University of California at Berkeley" et
00065     "Digital Equipment Corporation" couvertes par des copyrights.
00066 
00067     L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
00068     est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
00069     Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
00070     sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
00071 
00072     This work has been done in the context of GIE DYADE (joint R & D venture
00073     between BULL S.A. and INRIA).
00074 
00075     This software is available with usual "research" terms
00076     with the aim of retain credits of the software. 
00077     Permission to use, copy, modify and distribute this software for any
00078     purpose and without fee is hereby granted, provided that the above
00079     copyright notice and this permission notice appear in all copies,
00080     and the name of INRIA, IMAG, or any contributor not be used in advertising
00081     or publicity pertaining to this material without the prior explicit
00082     permission. The software is provided "as is" without any
00083     warranties, support or liabilities of any kind.
00084     This software is derived from source code from
00085     "University of California at Berkeley" and
00086     "Digital Equipment Corporation" protected by copyrights.
00087 
00088     Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
00089     is a federation of seven research units funded by the CNRS, National
00090     Polytechnic Institute of Grenoble and University Joseph Fourier.
00091     The research unit in Software, Systems, Networks (LSR) is member of IMAG.
00092 */
00093 
00094 /*
00095  * Derived from :
00096  *
00097  *
00098  * ipcp.c - PPP IP Control Protocol.
00099  *
00100  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
00101  *
00102  * Redistribution and use in source and binary forms, with or without
00103  * modification, are permitted provided that the following conditions
00104  * are met:
00105  *
00106  * 1. Redistributions of source code must retain the above copyright
00107  *    notice, this list of conditions and the following disclaimer.
00108  *
00109  * 2. Redistributions in binary form must reproduce the above copyright
00110  *    notice, this list of conditions and the following disclaimer in
00111  *    the documentation and/or other materials provided with the
00112  *    distribution.
00113  *
00114  * 3. The name "Carnegie Mellon University" must not be used to
00115  *    endorse or promote products derived from this software without
00116  *    prior written permission. For permission or any legal
00117  *    details, please contact
00118  *      Office of Technology Transfer
00119  *      Carnegie Mellon University
00120  *      5000 Forbes Avenue
00121  *      Pittsburgh, PA  15213-3890
00122  *      (412) 268-4387, fax: (412) 268-7395
00123  *      tech-transfer@andrew.cmu.edu
00124  *
00125  * 4. Redistributions of any form whatsoever must retain the following
00126  *    acknowledgment:
00127  *    "This product includes software developed by Computing Services
00128  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
00129  *
00130  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
00131  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00132  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
00133  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00134  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00135  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00136  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00137  *
00138  * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ 
00139  */
00140 
00141 /*
00142  * @todo: 
00143  *
00144  * Proxy Neighbour Discovery.
00145  *
00146  * Better defines for selecting the ordering of
00147  *   interface up / set address.
00148  */
00149 
00150 #include "netif/ppp/ppp_opts.h"
00151 #if PPP_SUPPORT && PPP_IPV6_SUPPORT  /* don't build if not configured for use in lwipopts.h */
00152 
00153 #if 0 /* UNUSED */
00154 #include <stdio.h>
00155 #include <string.h>
00156 #include <unistd.h>
00157 #include <netdb.h>
00158 #include <sys/param.h>
00159 #include <sys/types.h>
00160 #include <sys/socket.h>
00161 #include <netinet/in.h>
00162 #include <arpa/inet.h>
00163 #endif /* UNUSED */
00164 
00165 #include "netif/ppp/ppp_impl.h"
00166 #include "netif/ppp/fsm.h"
00167 #include "netif/ppp/ipcp.h"
00168 #include "netif/ppp/ipv6cp.h"
00169 #include "netif/ppp/magic.h"
00170 
00171 /* global vars */
00172 #if 0 /* UNUSED */
00173 int no_ifaceid_neg = 0;
00174 #endif /* UNUSED */
00175 
00176 /*
00177  * Callbacks for fsm code.  (CI = Configuration Information)
00178  */
00179 static void ipv6cp_resetci(fsm *f); /* Reset our CI */
00180 static int  ipv6cp_cilen(fsm *f); /* Return length of our CI */
00181 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */
00182 static int  ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */
00183 static int  ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */
00184 static int  ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */
00185 static int  ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */
00186 static void ipv6cp_up(fsm *f); /* We're UP */
00187 static void ipv6cp_down(fsm *f); /* We're DOWN */
00188 static void ipv6cp_finished(fsm *f); /* Don't need lower layer */
00189 
00190 static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
00191     ipv6cp_resetci,     /* Reset our Configuration Information */
00192     ipv6cp_cilen,       /* Length of our Configuration Information */
00193     ipv6cp_addci,       /* Add our Configuration Information */
00194     ipv6cp_ackci,       /* ACK our Configuration Information */
00195     ipv6cp_nakci,       /* NAK our Configuration Information */
00196     ipv6cp_rejci,       /* Reject our Configuration Information */
00197     ipv6cp_reqci,       /* Request peer's Configuration Information */
00198     ipv6cp_up,          /* Called when fsm reaches OPENED state */
00199     ipv6cp_down,        /* Called when fsm leaves OPENED state */
00200     NULL,           /* Called when we want the lower layer up */
00201     ipv6cp_finished,        /* Called when we want the lower layer down */
00202     NULL,           /* Called when Protocol-Reject received */
00203     NULL,           /* Retransmission is necessary */
00204     NULL,           /* Called to handle protocol-specific codes */
00205     "IPV6CP"            /* String name of protocol */
00206 };
00207 
00208 #if PPP_OPTIONS
00209 /*
00210  * Command-line options.
00211  */
00212 static int setifaceid(char **arg));
00213 static void printifaceid(option_t *,
00214                   void (*)(void *, char *, ...), void *));
00215 
00216 static option_t ipv6cp_option_list[] = {
00217     { "ipv6", o_special, (void *)setifaceid,
00218       "Set interface identifiers for IPV6",
00219       OPT_A2PRINTER, (void *)printifaceid },
00220 
00221     { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
00222       "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
00223     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
00224       "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
00225     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
00226       "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
00227 
00228     { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
00229       "Accept peer's interface identifier for us", 1 },
00230 
00231     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
00232       "Use (default) IPv4 address as interface identifier", 1 },
00233 
00234     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
00235       "Use uniquely-available persistent value for link local address", 1 },
00236 
00237     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
00238       "Set timeout for IPv6CP", OPT_PRIO },
00239     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
00240       "Set max #xmits for term-reqs", OPT_PRIO },
00241     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
00242       "Set max #xmits for conf-reqs", OPT_PRIO },
00243     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
00244       "Set max #conf-naks for IPv6CP", OPT_PRIO },
00245 
00246    { NULL }
00247 };
00248 #endif /* PPP_OPTIONS */
00249 
00250 /*
00251  * Protocol entry points from main code.
00252  */
00253 static void ipv6cp_init(ppp_pcb *pcb);
00254 static void ipv6cp_open(ppp_pcb *pcb);
00255 static void ipv6cp_close(ppp_pcb *pcb, const char *reason);
00256 static void ipv6cp_lowerup(ppp_pcb *pcb);
00257 static void ipv6cp_lowerdown(ppp_pcb *pcb);
00258 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len);
00259 static void ipv6cp_protrej(ppp_pcb *pcb);
00260 #if PPP_OPTIONS
00261 static void ipv6_check_options(void);
00262 #endif /* PPP_OPTIONS */
00263 #if DEMAND_SUPPORT
00264 static int  ipv6_demand_conf(int u);
00265 #endif /* DEMAND_SUPPORT */
00266 #if PRINTPKT_SUPPORT
00267 static int ipv6cp_printpkt(const u_char *p, int plen,
00268         void (*printer)(void *, const char *, ...), void *arg);
00269 #endif /* PRINTPKT_SUPPORT */
00270 #if DEMAND_SUPPORT
00271 static int ipv6_active_pkt(u_char *pkt, int len);
00272 #endif /* DEMAND_SUPPORT */
00273 
00274 const struct protent ipv6cp_protent = {
00275     PPP_IPV6CP,
00276     ipv6cp_init,
00277     ipv6cp_input,
00278     ipv6cp_protrej,
00279     ipv6cp_lowerup,
00280     ipv6cp_lowerdown,
00281     ipv6cp_open,
00282     ipv6cp_close,
00283 #if PRINTPKT_SUPPORT
00284     ipv6cp_printpkt,
00285 #endif /* PRINTPKT_SUPPORT */
00286 #if PPP_DATAINPUT
00287     NULL,
00288 #endif /* PPP_DATAINPUT */
00289 #if PRINTPKT_SUPPORT
00290     "IPV6CP",
00291     "IPV6",
00292 #endif /* PRINTPKT_SUPPORT */
00293 #if PPP_OPTIONS
00294     ipv6cp_option_list,
00295     ipv6_check_options,
00296 #endif /* PPP_OPTIONS */
00297 #if DEMAND_SUPPORT
00298     ipv6_demand_conf,
00299     ipv6_active_pkt
00300 #endif /* DEMAND_SUPPORT */
00301 };
00302 
00303 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid);
00304 #if 0 /* UNUSED */
00305 static void ipv6cp_script(char *));
00306 static void ipv6cp_script_done(void *));
00307 #endif /* UNUSED */
00308 
00309 /*
00310  * Lengths of configuration options.
00311  */
00312 #define CILEN_VOID  2
00313 #define CILEN_COMPRESS  4   /* length for RFC2023 compress opt. */
00314 #define CILEN_IFACEID   10  /* RFC2472, interface identifier    */
00315 
00316 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
00317              (x) == CONFNAK ? "NAK" : "REJ")
00318 
00319 #if 0 /* UNUSED */
00320 /*
00321  * This state variable is used to ensure that we don't
00322  * run an ipcp-up/down script while one is already running.
00323  */
00324 static enum script_state {
00325     s_down,
00326     s_up,
00327 } ipv6cp_script_state;
00328 static pid_t ipv6cp_script_pid;
00329 #endif /* UNUSED */
00330 
00331 static char *llv6_ntoa(eui64_t ifaceid);
00332 
00333 #if PPP_OPTIONS
00334 /*
00335  * setifaceid - set the interface identifiers manually
00336  */
00337 static int
00338 setifaceid(argv)
00339     char **argv;
00340 {
00341     char *comma, *arg, c;
00342     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
00343     struct in6_addr addr;
00344     static int prio_local, prio_remote;
00345 
00346 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
00347             (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
00348     
00349     arg = *argv;
00350     if ((comma = strchr(arg, ',')) == NULL)
00351     comma = arg + strlen(arg);
00352     
00353     /* 
00354      * If comma first character, then no local identifier
00355      */
00356     if (comma != arg) {
00357     c = *comma;
00358     *comma = '\0';
00359 
00360     if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
00361         option_error("Illegal interface identifier (local): %s", arg);
00362         return 0;
00363     }
00364 
00365     if (option_priority >= prio_local) {
00366         eui64_copy(addr.s6_addr32[2], wo->ourid);
00367         wo->opt_local = 1;
00368         prio_local = option_priority;
00369     }
00370     *comma = c;
00371     }
00372     
00373     /*
00374      * If comma last character, the no remote identifier
00375      */
00376     if (*comma != 0 && *++comma != '\0') {
00377     if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
00378         option_error("Illegal interface identifier (remote): %s", comma);
00379         return 0;
00380     }
00381     if (option_priority >= prio_remote) {
00382         eui64_copy(addr.s6_addr32[2], wo->hisid);
00383         wo->opt_remote = 1;
00384         prio_remote = option_priority;
00385     }
00386     }
00387 
00388     if (override_value("+ipv6", option_priority, option_source))
00389     ipv6cp_protent.enabled_flag = 1;
00390     return 1;
00391 }
00392 
00393 static void
00394 printifaceid(opt, printer, arg)
00395     option_t *opt;
00396     void (*printer)(void *, char *, ...));
00397     void *arg;
00398 {
00399     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
00400 
00401     if (wo->opt_local)
00402         printer(arg, "%s", llv6_ntoa(wo->ourid));
00403     printer(arg, ",");
00404     if (wo->opt_remote)
00405         printer(arg, "%s", llv6_ntoa(wo->hisid));
00406 }
00407 #endif /* PPP_OPTIONS */
00408 
00409 /*
00410  * Make a string representation of a network address.
00411  */
00412 static char *
00413 llv6_ntoa(eui64_t ifaceid)
00414 {
00415     static char b[26];
00416 
00417     sprintf(b, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x",
00418       ifaceid.e8[0], ifaceid.e8[1], ifaceid.e8[2], ifaceid.e8[3],
00419       ifaceid.e8[4], ifaceid.e8[5], ifaceid.e8[6], ifaceid.e8[7]);
00420 
00421     return b;
00422 }
00423 
00424 
00425 /*
00426  * ipv6cp_init - Initialize IPV6CP.
00427  */
00428 static void ipv6cp_init(ppp_pcb *pcb) {
00429     fsm *f = &pcb->ipv6cp_fsm;
00430     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
00431     ipv6cp_options *ao = &pcb->ipv6cp_allowoptions;
00432 
00433     f->pcb = pcb;
00434     f->protocol = PPP_IPV6CP;
00435     f->callbacks = &ipv6cp_callbacks;
00436     fsm_init(f);
00437 
00438 #if 0 /* Not necessary, everything is cleared in ppp_new() */
00439     memset(wo, 0, sizeof(*wo));
00440     memset(ao, 0, sizeof(*ao));
00441 #endif /* 0 */
00442 
00443     wo->accept_local = 1;
00444     wo->neg_ifaceid = 1;
00445     ao->neg_ifaceid = 1;
00446 
00447 #ifdef IPV6CP_COMP
00448     wo->neg_vj = 1;
00449     ao->neg_vj = 1;
00450     wo->vj_protocol = IPV6CP_COMP;
00451 #endif
00452 
00453 }
00454 
00455 
00456 /*
00457  * ipv6cp_open - IPV6CP is allowed to come up.
00458  */
00459 static void ipv6cp_open(ppp_pcb *pcb) {
00460     fsm_open(&pcb->ipv6cp_fsm);
00461 }
00462 
00463 
00464 /*
00465  * ipv6cp_close - Take IPV6CP down.
00466  */
00467 static void ipv6cp_close(ppp_pcb *pcb, const char *reason) {
00468     fsm_close(&pcb->ipv6cp_fsm, reason);
00469 }
00470 
00471 
00472 /*
00473  * ipv6cp_lowerup - The lower layer is up.
00474  */
00475 static void ipv6cp_lowerup(ppp_pcb *pcb) {
00476 #if PPP_IPV4_SUPPORT && PPP_IPV6_SUPPORT
00477     if (pcb->ipv6cp_disabled) {
00478         return;
00479     }
00480 #endif
00481     fsm_lowerup(&pcb->ipv6cp_fsm);
00482 }
00483 
00484 
00485 /*
00486  * ipv6cp_lowerdown - The lower layer is down.
00487  */
00488 static void ipv6cp_lowerdown(ppp_pcb *pcb) {
00489     fsm_lowerdown(&pcb->ipv6cp_fsm);
00490 }
00491 
00492 
00493 /*
00494  * ipv6cp_input - Input IPV6CP packet.
00495  */
00496 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) {
00497     fsm_input(&pcb->ipv6cp_fsm, p, len);
00498 }
00499 
00500 
00501 /*
00502  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
00503  *
00504  * Pretend the lower layer went down, so we shut up.
00505  */
00506 static void ipv6cp_protrej(ppp_pcb *pcb) {
00507     fsm_lowerdown(&pcb->ipv6cp_fsm);
00508 }
00509 
00510 
00511 /*
00512  * ipv6cp_resetci - Reset our CI.
00513  */
00514 static void ipv6cp_resetci(fsm *f) {
00515     ppp_pcb *pcb = f->pcb;
00516     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
00517     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00518     ipv6cp_options *ao = &pcb->ipv6cp_allowoptions;
00519 
00520     wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid;
00521     
00522     if (!wo->opt_local) {
00523     eui64_magic_nz(wo->ourid);
00524     }
00525     
00526     *go = *wo;
00527     eui64_zero(go->hisid);  /* last proposed interface identifier */
00528 }
00529 
00530 
00531 /*
00532  * ipv6cp_cilen - Return length of our CI.
00533  */
00534 static int ipv6cp_cilen(fsm *f) {
00535     ppp_pcb *pcb = f->pcb;
00536     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00537 
00538 #ifdef IPV6CP_COMP
00539 #define LENCIVJ(neg)        (neg ? CILEN_COMPRESS : 0)
00540 #endif /* IPV6CP_COMP */
00541 #define LENCIIFACEID(neg)   (neg ? CILEN_IFACEID : 0)
00542 
00543     return (LENCIIFACEID(go->neg_ifaceid) +
00544 #ifdef IPV6CP_COMP
00545         LENCIVJ(go->neg_vj) +
00546 #endif /* IPV6CP_COMP */
00547         0);
00548 }
00549 
00550 
00551 /*
00552  * ipv6cp_addci - Add our desired CIs to a packet.
00553  */
00554 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) {
00555     ppp_pcb *pcb = f->pcb;
00556     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00557     int len = *lenp;
00558 
00559 #ifdef IPV6CP_COMP
00560 #define ADDCIVJ(opt, neg, val) \
00561     if (neg) { \
00562     int vjlen = CILEN_COMPRESS; \
00563     if (len >= vjlen) { \
00564         PUTCHAR(opt, ucp); \
00565         PUTCHAR(vjlen, ucp); \
00566         PUTSHORT(val, ucp); \
00567         len -= vjlen; \
00568     } else \
00569         neg = 0; \
00570     }
00571 #endif /* IPV6CP_COMP */
00572 
00573 #define ADDCIIFACEID(opt, neg, val1) \
00574     if (neg) { \
00575     int idlen = CILEN_IFACEID; \
00576     if (len >= idlen) { \
00577         PUTCHAR(opt, ucp); \
00578         PUTCHAR(idlen, ucp); \
00579         eui64_put(val1, ucp); \
00580         len -= idlen; \
00581     } else \
00582         neg = 0; \
00583     }
00584 
00585     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
00586 
00587 #ifdef IPV6CP_COMP
00588     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
00589 #endif /* IPV6CP_COMP */
00590 
00591     *lenp -= len;
00592 }
00593 
00594 
00595 /*
00596  * ipv6cp_ackci - Ack our CIs.
00597  *
00598  * Returns:
00599  *  0 - Ack was bad.
00600  *  1 - Ack was good.
00601  */
00602 static int ipv6cp_ackci(fsm *f, u_char *p, int len) {
00603     ppp_pcb *pcb = f->pcb;
00604     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00605     u_short cilen, citype;
00606 #ifdef IPV6CP_COMP
00607     u_short cishort;
00608 #endif /* IPV6CP_COMP */
00609     eui64_t ifaceid;
00610 
00611     /*
00612      * CIs must be in exactly the same order that we sent...
00613      * Check packet length and CI length at each step.
00614      * If we find any deviations, then this packet is bad.
00615      */
00616 
00617 #ifdef IPV6CP_COMP
00618 #define ACKCIVJ(opt, neg, val) \
00619     if (neg) { \
00620     int vjlen = CILEN_COMPRESS; \
00621     if ((len -= vjlen) < 0) \
00622         goto bad; \
00623     GETCHAR(citype, p); \
00624     GETCHAR(cilen, p); \
00625     if (cilen != vjlen || \
00626         citype != opt)  \
00627         goto bad; \
00628     GETSHORT(cishort, p); \
00629     if (cishort != val) \
00630         goto bad; \
00631     }
00632 #endif /* IPV6CP_COMP */
00633 
00634 #define ACKCIIFACEID(opt, neg, val1) \
00635     if (neg) { \
00636     int idlen = CILEN_IFACEID; \
00637     if ((len -= idlen) < 0) \
00638         goto bad; \
00639     GETCHAR(citype, p); \
00640     GETCHAR(cilen, p); \
00641     if (cilen != idlen || \
00642         citype != opt) \
00643         goto bad; \
00644     eui64_get(ifaceid, p); \
00645     if (! eui64_equals(val1, ifaceid)) \
00646         goto bad; \
00647     }
00648 
00649     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
00650 
00651 #ifdef IPV6CP_COMP
00652     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
00653 #endif /* IPV6CP_COMP */
00654 
00655     /*
00656      * If there are any remaining CIs, then this packet is bad.
00657      */
00658     if (len != 0)
00659     goto bad;
00660     return (1);
00661 
00662 bad:
00663     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
00664     return (0);
00665 }
00666 
00667 /*
00668  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
00669  * This should not modify any state if the Nak is bad
00670  * or if IPV6CP is in the OPENED state.
00671  *
00672  * Returns:
00673  *  0 - Nak was bad.
00674  *  1 - Nak was good.
00675  */
00676 static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
00677     ppp_pcb *pcb = f->pcb;
00678     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00679     u_char citype, cilen, *next;
00680 #ifdef IPV6CP_COMP
00681     u_short cishort;
00682 #endif /* IPV6CP_COMP */
00683     eui64_t ifaceid;
00684     ipv6cp_options no;      /* options we've seen Naks for */
00685     ipv6cp_options try_;    /* options to request next time */
00686 
00687     BZERO(&no, sizeof(no));
00688     try_ = *go;
00689 
00690     /*
00691      * Any Nak'd CIs must be in exactly the same order that we sent.
00692      * Check packet length and CI length at each step.
00693      * If we find any deviations, then this packet is bad.
00694      */
00695 #define NAKCIIFACEID(opt, neg, code) \
00696     if (go->neg && \
00697     len >= (cilen = CILEN_IFACEID) && \
00698     p[1] == cilen && \
00699     p[0] == opt) { \
00700     len -= cilen; \
00701     INCPTR(2, p); \
00702     eui64_get(ifaceid, p); \
00703     no.neg = 1; \
00704     code \
00705     }
00706 
00707 #ifdef IPV6CP_COMP
00708 #define NAKCIVJ(opt, neg, code) \
00709     if (go->neg && \
00710     ((cilen = p[1]) == CILEN_COMPRESS) && \
00711     len >= cilen && \
00712     p[0] == opt) { \
00713     len -= cilen; \
00714     INCPTR(2, p); \
00715     GETSHORT(cishort, p); \
00716     no.neg = 1; \
00717         code \
00718     }
00719 #endif /* IPV6CP_COMP */
00720 
00721     /*
00722      * Accept the peer's idea of {our,his} interface identifier, if different
00723      * from our idea, only if the accept_{local,remote} flag is set.
00724      */
00725     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
00726          if (treat_as_reject) {
00727              try_.neg_ifaceid = 0;
00728          } else if (go->accept_local) {
00729              while (eui64_iszero(ifaceid) || 
00730                 eui64_equals(ifaceid, go->hisid)) /* bad luck */
00731              eui64_magic(ifaceid);
00732              try_.ourid = ifaceid;
00733              IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
00734          }
00735          );
00736 
00737 #ifdef IPV6CP_COMP
00738     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
00739         {
00740         if (cishort == IPV6CP_COMP && !treat_as_reject) {
00741             try_.vj_protocol = cishort;
00742         } else {
00743             try_.neg_vj = 0;
00744         }
00745         }
00746         );
00747 #endif /* IPV6CP_COMP */
00748 
00749     /*
00750      * There may be remaining CIs, if the peer is requesting negotiation
00751      * on an option that we didn't include in our request packet.
00752      * If they want to negotiate about interface identifier, we comply.
00753      * If they want us to ask for compression, we refuse.
00754      */
00755     while (len >= CILEN_VOID) {
00756     GETCHAR(citype, p);
00757     GETCHAR(cilen, p);
00758     if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
00759         goto bad;
00760     next = p + cilen - 2;
00761 
00762     switch (citype) {
00763 #ifdef IPV6CP_COMP
00764     case CI_COMPRESSTYPE:
00765         if (go->neg_vj || no.neg_vj ||
00766         (cilen != CILEN_COMPRESS))
00767         goto bad;
00768         no.neg_vj = 1;
00769         break;
00770 #endif /* IPV6CP_COMP */
00771     case CI_IFACEID:
00772         if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
00773         goto bad;
00774         try_.neg_ifaceid = 1;
00775         eui64_get(ifaceid, p);
00776         if (go->accept_local) {
00777         while (eui64_iszero(ifaceid) || 
00778                eui64_equals(ifaceid, go->hisid)) /* bad luck */
00779             eui64_magic(ifaceid);
00780         try_.ourid = ifaceid;
00781         }
00782         no.neg_ifaceid = 1;
00783         break;
00784     default:
00785         break;
00786     }
00787     p = next;
00788     }
00789 
00790     /* If there is still anything left, this packet is bad. */
00791     if (len != 0)
00792     goto bad;
00793 
00794     /*
00795      * OK, the Nak is good.  Now we can update state.
00796      */
00797     if (f->state != PPP_FSM_OPENED)
00798     *go = try_;
00799 
00800     return 1;
00801 
00802 bad:
00803     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
00804     return 0;
00805 }
00806 
00807 
00808 /*
00809  * ipv6cp_rejci - Reject some of our CIs.
00810  */
00811 static int ipv6cp_rejci(fsm *f, u_char *p, int len) {
00812     ppp_pcb *pcb = f->pcb;
00813     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00814     u_char cilen;
00815 #ifdef IPV6CP_COMP
00816     u_short cishort;
00817 #endif /* IPV6CP_COMP */
00818     eui64_t ifaceid;
00819     ipv6cp_options try_;        /* options to request next time */
00820 
00821     try_ = *go;
00822     /*
00823      * Any Rejected CIs must be in exactly the same order that we sent.
00824      * Check packet length and CI length at each step.
00825      * If we find any deviations, then this packet is bad.
00826      */
00827 #define REJCIIFACEID(opt, neg, val1) \
00828     if (go->neg && \
00829     len >= (cilen = CILEN_IFACEID) && \
00830     p[1] == cilen && \
00831     p[0] == opt) { \
00832     len -= cilen; \
00833     INCPTR(2, p); \
00834     eui64_get(ifaceid, p); \
00835     /* Check rejected value. */ \
00836     if (! eui64_equals(ifaceid, val1)) \
00837         goto bad; \
00838     try_.neg = 0; \
00839     }
00840 
00841 #ifdef IPV6CP_COMP
00842 #define REJCIVJ(opt, neg, val) \
00843     if (go->neg && \
00844     p[1] == CILEN_COMPRESS && \
00845     len >= p[1] && \
00846     p[0] == opt) { \
00847     len -= p[1]; \
00848     INCPTR(2, p); \
00849     GETSHORT(cishort, p); \
00850     /* Check rejected value. */  \
00851     if (cishort != val) \
00852         goto bad; \
00853     try_.neg = 0; \
00854      }
00855 #endif /* IPV6CP_COMP */
00856 
00857     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
00858 
00859 #ifdef IPV6CP_COMP
00860     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
00861 #endif /* IPV6CP_COMP */
00862 
00863     /*
00864      * If there are any remaining CIs, then this packet is bad.
00865      */
00866     if (len != 0)
00867     goto bad;
00868     /*
00869      * Now we can update state.
00870      */
00871     if (f->state != PPP_FSM_OPENED)
00872     *go = try_;
00873     return 1;
00874 
00875 bad:
00876     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
00877     return 0;
00878 }
00879 
00880 
00881 /*
00882  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
00883  *
00884  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
00885  * appropriately.  If reject_if_disagree is non-zero, doesn't return
00886  * CONFNAK; returns CONFREJ if it can't return CONFACK.
00887  *
00888  * inp = Requested CIs
00889  * len = Length of requested CIs
00890  *
00891  */
00892 static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) {
00893     ppp_pcb *pcb = f->pcb;
00894     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
00895     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
00896     ipv6cp_options *ao = &pcb->ipv6cp_allowoptions;
00897     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00898     u_char *cip, *next;     /* Pointer to current and next CIs */
00899     u_short cilen, citype;  /* Parsed len, type */
00900 #ifdef IPV6CP_COMP
00901     u_short cishort;        /* Parsed short value */
00902 #endif /* IPV6CP_COMP */
00903     eui64_t ifaceid;        /* Parsed interface identifier */
00904     int rc = CONFACK;       /* Final packet return code */
00905     int orc;            /* Individual option return code */
00906     u_char *p;          /* Pointer to next char to parse */
00907     u_char *ucp = inp;      /* Pointer to current output char */
00908     int l = *len;       /* Length left */
00909 
00910     /*
00911      * Reset all his options.
00912      */
00913     BZERO(ho, sizeof(*ho));
00914     
00915     /*
00916      * Process all his options.
00917      */
00918     next = inp;
00919     while (l) {
00920     orc = CONFACK;          /* Assume success */
00921     cip = p = next;         /* Remember begining of CI */
00922     if (l < 2 ||            /* Not enough data for CI header or */
00923         p[1] < 2 ||         /*  CI length too small or */
00924         p[1] > l) {         /*  CI length too big? */
00925         IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
00926         orc = CONFREJ;      /* Reject bad CI */
00927         cilen = l;          /* Reject till end of packet */
00928         l = 0;          /* Don't loop again */
00929         goto endswitch;
00930     }
00931     GETCHAR(citype, p);     /* Parse CI type */
00932     GETCHAR(cilen, p);      /* Parse CI length */
00933     l -= cilen;         /* Adjust remaining length */
00934     next += cilen;          /* Step to next CI */
00935 
00936     switch (citype) {       /* Check CI type */
00937     case CI_IFACEID:
00938         IPV6CPDEBUG(("ipv6cp: received interface identifier "));
00939 
00940         if (!ao->neg_ifaceid ||
00941         cilen != CILEN_IFACEID) {   /* Check CI length */
00942         orc = CONFREJ;      /* Reject CI */
00943         break;
00944         }
00945 
00946         /*
00947          * If he has no interface identifier, or if we both have same 
00948          * identifier then NAK it with new idea.
00949          * In particular, if we don't know his identifier, but he does,
00950          * then accept it.
00951          */
00952         eui64_get(ifaceid, p);
00953         IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
00954         if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
00955         orc = CONFREJ;      /* Reject CI */
00956         break;
00957         }
00958         if (!eui64_iszero(wo->hisid) && 
00959         !eui64_equals(ifaceid, wo->hisid) && 
00960         eui64_iszero(go->hisid)) {
00961             
00962         orc = CONFNAK;
00963         ifaceid = wo->hisid;
00964         go->hisid = ifaceid;
00965         DECPTR(sizeof(ifaceid), p);
00966         eui64_put(ifaceid, p);
00967         } else
00968         if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
00969         orc = CONFNAK;
00970         if (eui64_iszero(go->hisid))    /* first time, try option */
00971             ifaceid = wo->hisid;
00972         while (eui64_iszero(ifaceid) || 
00973                eui64_equals(ifaceid, go->ourid)) /* bad luck */
00974             eui64_magic(ifaceid);
00975         go->hisid = ifaceid;
00976         DECPTR(sizeof(ifaceid), p);
00977         eui64_put(ifaceid, p);
00978         }
00979 
00980         ho->neg_ifaceid = 1;
00981         ho->hisid = ifaceid;
00982         break;
00983 
00984 #ifdef IPV6CP_COMP
00985     case CI_COMPRESSTYPE:
00986         IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
00987         if (!ao->neg_vj ||
00988         (cilen != CILEN_COMPRESS)) {
00989         orc = CONFREJ;
00990         break;
00991         }
00992         GETSHORT(cishort, p);
00993         IPV6CPDEBUG(("(%d)", cishort));
00994 
00995         if (!(cishort == IPV6CP_COMP)) {
00996         orc = CONFREJ;
00997         break;
00998         }
00999 
01000         ho->neg_vj = 1;
01001         ho->vj_protocol = cishort;
01002         break;
01003 #endif /* IPV6CP_COMP */
01004 
01005     default:
01006         orc = CONFREJ;
01007         break;
01008     }
01009 
01010 endswitch:
01011     IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
01012 
01013     if (orc == CONFACK &&       /* Good CI */
01014         rc != CONFACK)      /*  but prior CI wasnt? */
01015         continue;           /* Don't send this one */
01016 
01017     if (orc == CONFNAK) {       /* Nak this CI? */
01018         if (reject_if_disagree) /* Getting fed up with sending NAKs? */
01019         orc = CONFREJ;      /* Get tough if so */
01020         else {
01021         if (rc == CONFREJ)  /* Rejecting prior CI? */
01022             continue;       /* Don't send this one */
01023         if (rc == CONFACK) {    /* Ack'd all prior CIs? */
01024             rc = CONFNAK;   /* Not anymore... */
01025             ucp = inp;      /* Backup */
01026         }
01027         }
01028     }
01029 
01030     if (orc == CONFREJ &&       /* Reject this CI */
01031         rc != CONFREJ) {        /*  but no prior ones? */
01032         rc = CONFREJ;
01033         ucp = inp;          /* Backup */
01034     }
01035 
01036     /* Need to move CI? */
01037     if (ucp != cip)
01038         MEMCPY(ucp, cip, cilen);    /* Move it */
01039 
01040     /* Update output pointer */
01041     INCPTR(cilen, ucp);
01042     }
01043 
01044     /*
01045      * If we aren't rejecting this packet, and we want to negotiate
01046      * their identifier and they didn't send their identifier, then we
01047      * send a NAK with a CI_IFACEID option appended.  We assume the
01048      * input buffer is long enough that we can append the extra
01049      * option safely.
01050      */
01051     if (rc != CONFREJ && !ho->neg_ifaceid &&
01052     wo->req_ifaceid && !reject_if_disagree) {
01053     if (rc == CONFACK) {
01054         rc = CONFNAK;
01055         ucp = inp;              /* reset pointer */
01056         wo->req_ifaceid = 0;        /* don't ask again */
01057     }
01058     PUTCHAR(CI_IFACEID, ucp);
01059     PUTCHAR(CILEN_IFACEID, ucp);
01060     eui64_put(wo->hisid, ucp);
01061     }
01062 
01063     *len = ucp - inp;           /* Compute output length */
01064     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
01065     return (rc);            /* Return final code */
01066 }
01067 
01068 #if PPP_OPTIONS
01069 /*
01070  * ipv6_check_options - check that any IP-related options are OK,
01071  * and assign appropriate defaults.
01072  */
01073 static void ipv6_check_options() {
01074     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
01075 
01076     if (!ipv6cp_protent.enabled_flag)
01077     return;
01078 
01079     /*
01080      * Persistent link-local id is only used when user has not explicitly
01081      * configure/hard-code the id
01082      */
01083     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
01084 
01085     /* 
01086      * On systems where there are no Ethernet interfaces used, there
01087      * may be other ways to obtain a persistent id. Right now, it
01088      * will fall back to using magic [see eui64_magic] below when
01089      * an EUI-48 from MAC address can't be obtained. Other possibilities
01090      * include obtaining EEPROM serial numbers, or some other unique
01091      * yet persistent number. On Sparc platforms, this is possible,
01092      * but too bad there's no standards yet for x86 machines.
01093      */
01094     if (ether_to_eui64(&wo->ourid)) {
01095         wo->opt_local = 1;
01096     }
01097     }
01098 
01099     if (!wo->opt_local) {   /* init interface identifier */
01100     if (wo->use_ip && eui64_iszero(wo->ourid)) {
01101         eui64_setlo32(wo->ourid, lwip_ntohl(ipcp_wantoptions[0].ouraddr));
01102         if (!eui64_iszero(wo->ourid))
01103         wo->opt_local = 1;
01104     }
01105     
01106     while (eui64_iszero(wo->ourid))
01107         eui64_magic(wo->ourid);
01108     }
01109 
01110     if (!wo->opt_remote) {
01111     if (wo->use_ip && eui64_iszero(wo->hisid)) {
01112         eui64_setlo32(wo->hisid, lwip_ntohl(ipcp_wantoptions[0].hisaddr));
01113         if (!eui64_iszero(wo->hisid))
01114         wo->opt_remote = 1;
01115     }
01116     }
01117 
01118     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
01119     option_error("local/remote LL address required for demand-dialling\n");
01120     exit(1);
01121     }
01122 }
01123 #endif /* PPP_OPTIONS */
01124 
01125 #if DEMAND_SUPPORT
01126 /*
01127  * ipv6_demand_conf - configure the interface as though
01128  * IPV6CP were up, for use with dial-on-demand.
01129  */
01130 static int ipv6_demand_conf(int u) {
01131     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
01132 
01133     if (!sif6up(u))
01134     return 0;
01135 
01136     if (!sif6addr(u, wo->ourid, wo->hisid))
01137     return 0;
01138 
01139     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
01140     return 0;
01141 
01142     ppp_notice("ipv6_demand_conf");
01143     ppp_notice("local  LL address %s", llv6_ntoa(wo->ourid));
01144     ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid));
01145 
01146     return 1;
01147 }
01148 #endif /* DEMAND_SUPPORT */
01149 
01150 
01151 /*
01152  * ipv6cp_up - IPV6CP has come UP.
01153  *
01154  * Configure the IPv6 network interface appropriately and bring it up.
01155  */
01156 static void ipv6cp_up(fsm *f) {
01157     ppp_pcb *pcb = f->pcb;
01158     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
01159     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
01160     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
01161 
01162     IPV6CPDEBUG(("ipv6cp: up"));
01163 
01164     /*
01165      * We must have a non-zero LL address for both ends of the link.
01166      */
01167     if (!ho->neg_ifaceid)
01168     ho->hisid = wo->hisid;
01169 
01170 #if 0 /* UNUSED */
01171     if(!no_ifaceid_neg) {
01172 #endif /* UNUSED */
01173     if (eui64_iszero(ho->hisid)) {
01174         ppp_error("Could not determine remote LL address");
01175         ipv6cp_close(f->pcb, "Could not determine remote LL address");
01176         return;
01177     }
01178     if (eui64_iszero(go->ourid)) {
01179         ppp_error("Could not determine local LL address");
01180         ipv6cp_close(f->pcb, "Could not determine local LL address");
01181         return;
01182     }
01183     if (eui64_equals(go->ourid, ho->hisid)) {
01184         ppp_error("local and remote LL addresses are equal");
01185         ipv6cp_close(f->pcb, "local and remote LL addresses are equal");
01186         return;
01187     }
01188 #if 0 /* UNUSED */
01189     }
01190 #endif /* UNUSED */
01191 #if 0 /* UNUSED */
01192     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
01193     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
01194 #endif /* UNUSED */
01195 
01196 #ifdef IPV6CP_COMP
01197     /* set tcp compression */
01198     sif6comp(f->unit, ho->neg_vj);
01199 #endif
01200 
01201 #if DEMAND_SUPPORT
01202     /*
01203      * If we are doing dial-on-demand, the interface is already
01204      * configured, so we put out any saved-up packets, then set the
01205      * interface to pass IPv6 packets.
01206      */
01207     if (demand) {
01208     if (! eui64_equals(go->ourid, wo->ourid) || 
01209         ! eui64_equals(ho->hisid, wo->hisid)) {
01210         if (! eui64_equals(go->ourid, wo->ourid))
01211         warn("Local LL address changed to %s", 
01212              llv6_ntoa(go->ourid));
01213         if (! eui64_equals(ho->hisid, wo->hisid))
01214         warn("Remote LL address changed to %s", 
01215              llv6_ntoa(ho->hisid));
01216         ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid);
01217 
01218         /* Set the interface to the new addresses */
01219         if (!sif6addr(f->pcb, go->ourid, ho->hisid)) {
01220         if (debug)
01221             warn("sif6addr failed");
01222         ipv6cp_close(f->unit, "Interface configuration failed");
01223         return;
01224         }
01225 
01226     }
01227     demand_rexmit(PPP_IPV6);
01228     sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
01229 
01230     } else
01231 #endif /* DEMAND_SUPPORT */
01232     {
01233     /*
01234      * Set LL addresses
01235      */
01236     if (!sif6addr(f->pcb, go->ourid, ho->hisid)) {
01237         PPPDEBUG(LOG_DEBUG, ("sif6addr failed"));
01238         ipv6cp_close(f->pcb, "Interface configuration failed");
01239         return;
01240     }
01241 
01242     /* bring the interface up for IPv6 */
01243     if (!sif6up(f->pcb)) {
01244         PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)"));
01245         ipv6cp_close(f->pcb, "Interface configuration failed");
01246         return;
01247     }
01248 #if DEMAND_SUPPORT
01249     sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS);
01250 #endif /* DEMAND_SUPPORT */
01251 
01252     ppp_notice("local  LL address %s", llv6_ntoa(go->ourid));
01253     ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid));
01254     }
01255 
01256     np_up(f->pcb, PPP_IPV6);
01257     pcb->ipv6cp_is_up = 1;
01258 
01259 #if 0 /* UNUSED */
01260     /*
01261      * Execute the ipv6-up script, like this:
01262      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
01263      */
01264     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
01265     ipv6cp_script_state = s_up;
01266     ipv6cp_script(_PATH_IPV6UP);
01267     }
01268 #endif /* UNUSED */
01269 }
01270 
01271 
01272 /*
01273  * ipv6cp_down - IPV6CP has gone DOWN.
01274  *
01275  * Take the IPv6 network interface down, clear its addresses
01276  * and delete routes through it.
01277  */
01278 static void ipv6cp_down(fsm *f) {
01279     ppp_pcb *pcb = f->pcb;
01280     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
01281     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
01282 
01283     IPV6CPDEBUG(("ipv6cp: down"));
01284 #if PPP_STATS_SUPPORT
01285     update_link_stats(f->unit);
01286 #endif /* PPP_STATS_SUPPORT */
01287     if (pcb->ipv6cp_is_up) {
01288     pcb->ipv6cp_is_up = 0;
01289     np_down(f->pcb, PPP_IPV6);
01290     }
01291 #ifdef IPV6CP_COMP
01292     sif6comp(f->unit, 0);
01293 #endif
01294 
01295 #if DEMAND_SUPPORT
01296     /*
01297      * If we are doing dial-on-demand, set the interface
01298      * to queue up outgoing packets (for now).
01299      */
01300     if (demand) {
01301     sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE);
01302     } else
01303 #endif /* DEMAND_SUPPORT */
01304     {
01305 #if DEMAND_SUPPORT
01306     sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP);
01307 #endif /* DEMAND_SUPPORT */
01308     ipv6cp_clear_addrs(f->pcb,
01309                go->ourid,
01310                ho->hisid);
01311     sif6down(f->pcb);
01312     }
01313 
01314 #if 0 /* UNUSED */
01315     /* Execute the ipv6-down script */
01316     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
01317     ipv6cp_script_state = s_down;
01318     ipv6cp_script(_PATH_IPV6DOWN);
01319     }
01320 #endif /* UNUSED */
01321 }
01322 
01323 
01324 /*
01325  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
01326  * proxy neighbour discovery entries, etc.
01327  */
01328 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) {
01329     cif6addr(pcb, ourid, hisid);
01330 }
01331 
01332 
01333 /*
01334  * ipv6cp_finished - possibly shut down the lower layers.
01335  */
01336 static void ipv6cp_finished(fsm *f) {
01337     np_finished(f->pcb, PPP_IPV6);
01338 }
01339 
01340 
01341 #if 0 /* UNUSED */
01342 /*
01343  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
01344  * has finished.
01345  */
01346 static void
01347 ipv6cp_script_done(arg)
01348     void *arg;
01349 {
01350     ipv6cp_script_pid = 0;
01351     switch (ipv6cp_script_state) {
01352     case s_up:
01353     if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) {
01354         ipv6cp_script_state = s_down;
01355         ipv6cp_script(_PATH_IPV6DOWN);
01356     }
01357     break;
01358     case s_down:
01359     if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) {
01360         ipv6cp_script_state = s_up;
01361         ipv6cp_script(_PATH_IPV6UP);
01362     }
01363     break;
01364     }
01365 }
01366 
01367 
01368 /*
01369  * ipv6cp_script - Execute a script with arguments
01370  * interface-name tty-name speed local-LL remote-LL.
01371  */
01372 static void
01373 ipv6cp_script(script)
01374     char *script;
01375 {
01376     char strspeed[32], strlocal[32], strremote[32];
01377     char *argv[8];
01378 
01379     sprintf(strspeed, "%d", baud_rate);
01380     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
01381     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
01382 
01383     argv[0] = script;
01384     argv[1] = ifname;
01385     argv[2] = devnam;
01386     argv[3] = strspeed;
01387     argv[4] = strlocal;
01388     argv[5] = strremote;
01389     argv[6] = ipparam;
01390     argv[7] = NULL;
01391 
01392     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
01393                     NULL, 0);
01394 }
01395 #endif /* UNUSED */
01396 
01397 #if PRINTPKT_SUPPORT
01398 /*
01399  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
01400  */
01401 static const char* const ipv6cp_codenames[] = {
01402     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
01403     "TermReq", "TermAck", "CodeRej"
01404 };
01405 
01406 static int ipv6cp_printpkt(const u_char *p, int plen,
01407         void (*printer)(void *, const char *, ...), void *arg) {
01408     int code, id, len, olen;
01409     const u_char *pstart, *optend;
01410 #ifdef IPV6CP_COMP
01411     u_short cishort;
01412 #endif /* IPV6CP_COMP */
01413     eui64_t ifaceid;
01414 
01415     if (plen < HEADERLEN)
01416     return 0;
01417     pstart = p;
01418     GETCHAR(code, p);
01419     GETCHAR(id, p);
01420     GETSHORT(len, p);
01421     if (len < HEADERLEN || len > plen)
01422     return 0;
01423 
01424     if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames))
01425     printer(arg, " %s", ipv6cp_codenames[code-1]);
01426     else
01427     printer(arg, " code=0x%x", code);
01428     printer(arg, " id=0x%x", id);
01429     len -= HEADERLEN;
01430     switch (code) {
01431     case CONFREQ:
01432     case CONFACK:
01433     case CONFNAK:
01434     case CONFREJ:
01435     /* print option list */
01436     while (len >= 2) {
01437         GETCHAR(code, p);
01438         GETCHAR(olen, p);
01439         p -= 2;
01440         if (olen < 2 || olen > len) {
01441         break;
01442         }
01443         printer(arg, " <");
01444         len -= olen;
01445         optend = p + olen;
01446         switch (code) {
01447 #ifdef IPV6CP_COMP
01448         case CI_COMPRESSTYPE:
01449         if (olen >= CILEN_COMPRESS) {
01450             p += 2;
01451             GETSHORT(cishort, p);
01452             printer(arg, "compress ");
01453             printer(arg, "0x%x", cishort);
01454         }
01455         break;
01456 #endif /* IPV6CP_COMP */
01457         case CI_IFACEID:
01458         if (olen == CILEN_IFACEID) {
01459             p += 2;
01460             eui64_get(ifaceid, p);
01461             printer(arg, "addr %s", llv6_ntoa(ifaceid));
01462         }
01463         break;
01464         default:
01465         break;
01466         }
01467         while (p < optend) {
01468         GETCHAR(code, p);
01469         printer(arg, " %.2x", code);
01470         }
01471         printer(arg, ">");
01472     }
01473     break;
01474 
01475     case TERMACK:
01476     case TERMREQ:
01477     if (len > 0 && *p >= ' ' && *p < 0x7f) {
01478         printer(arg, " ");
01479         ppp_print_string(p, len, printer, arg);
01480         p += len;
01481         len = 0;
01482     }
01483     break;
01484     default:
01485     break;
01486     }
01487 
01488     /* print the rest of the bytes in the packet */
01489     for (; len > 0; --len) {
01490     GETCHAR(code, p);
01491     printer(arg, " %.2x", code);
01492     }
01493 
01494     return p - pstart;
01495 }
01496 #endif /* PRINTPKT_SUPPORT */
01497 
01498 #if DEMAND_SUPPORT
01499 /*
01500  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
01501  * We don't bring the link up for IP fragments or for TCP FIN packets
01502  * with no data.
01503  */
01504 #define IP6_HDRLEN  40  /* bytes */
01505 #define IP6_NHDR_FRAG   44  /* fragment IPv6 header */
01506 #define TCP_HDRLEN  20
01507 #define TH_FIN      0x01
01508 
01509 /*
01510  * We use these macros because the IP header may be at an odd address,
01511  * and some compilers might use word loads to get th_off or ip_hl.
01512  */
01513 
01514 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
01515 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
01516 #define get_tcpflags(x) (((unsigned char *)(x))[13])
01517 
01518 static int ipv6_active_pkt(u_char *pkt, int len) {
01519     u_char *tcp;
01520 
01521     len -= PPP_HDRLEN;
01522     pkt += PPP_HDRLEN;
01523     if (len < IP6_HDRLEN)
01524     return 0;
01525     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
01526     return 0;
01527     if (get_ip6nh(pkt) != IPPROTO_TCP)
01528     return 1;
01529     if (len < IP6_HDRLEN + TCP_HDRLEN)
01530     return 0;
01531     tcp = pkt + IP6_HDRLEN;
01532     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
01533     return 0;
01534     return 1;
01535 }
01536 #endif /* DEMAND_SUPPORT */
01537 
01538 #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */