ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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     fsm_lowerup(&pcb->ipv6cp_fsm);
00477 }
00478 
00479 
00480 /*
00481  * ipv6cp_lowerdown - The lower layer is down.
00482  */
00483 static void ipv6cp_lowerdown(ppp_pcb *pcb) {
00484     fsm_lowerdown(&pcb->ipv6cp_fsm);
00485 }
00486 
00487 
00488 /*
00489  * ipv6cp_input - Input IPV6CP packet.
00490  */
00491 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) {
00492     fsm_input(&pcb->ipv6cp_fsm, p, len);
00493 }
00494 
00495 
00496 /*
00497  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
00498  *
00499  * Pretend the lower layer went down, so we shut up.
00500  */
00501 static void ipv6cp_protrej(ppp_pcb *pcb) {
00502     fsm_lowerdown(&pcb->ipv6cp_fsm);
00503 }
00504 
00505 
00506 /*
00507  * ipv6cp_resetci - Reset our CI.
00508  */
00509 static void ipv6cp_resetci(fsm *f) {
00510     ppp_pcb *pcb = f->pcb;
00511     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
00512     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00513     ipv6cp_options *ao = &pcb->ipv6cp_allowoptions;
00514 
00515     wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid;
00516     
00517     if (!wo->opt_local) {
00518     eui64_magic_nz(wo->ourid);
00519     }
00520     
00521     *go = *wo;
00522     eui64_zero(go->hisid);  /* last proposed interface identifier */
00523 }
00524 
00525 
00526 /*
00527  * ipv6cp_cilen - Return length of our CI.
00528  */
00529 static int ipv6cp_cilen(fsm *f) {
00530     ppp_pcb *pcb = f->pcb;
00531     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00532 
00533 #ifdef IPV6CP_COMP
00534 #define LENCIVJ(neg)        (neg ? CILEN_COMPRESS : 0)
00535 #endif /* IPV6CP_COMP */
00536 #define LENCIIFACEID(neg)   (neg ? CILEN_IFACEID : 0)
00537 
00538     return (LENCIIFACEID(go->neg_ifaceid) +
00539 #ifdef IPV6CP_COMP
00540         LENCIVJ(go->neg_vj) +
00541 #endif /* IPV6CP_COMP */
00542         0);
00543 }
00544 
00545 
00546 /*
00547  * ipv6cp_addci - Add our desired CIs to a packet.
00548  */
00549 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) {
00550     ppp_pcb *pcb = f->pcb;
00551     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00552     int len = *lenp;
00553 
00554 #ifdef IPV6CP_COMP
00555 #define ADDCIVJ(opt, neg, val) \
00556     if (neg) { \
00557     int vjlen = CILEN_COMPRESS; \
00558     if (len >= vjlen) { \
00559         PUTCHAR(opt, ucp); \
00560         PUTCHAR(vjlen, ucp); \
00561         PUTSHORT(val, ucp); \
00562         len -= vjlen; \
00563     } else \
00564         neg = 0; \
00565     }
00566 #endif /* IPV6CP_COMP */
00567 
00568 #define ADDCIIFACEID(opt, neg, val1) \
00569     if (neg) { \
00570     int idlen = CILEN_IFACEID; \
00571     if (len >= idlen) { \
00572         PUTCHAR(opt, ucp); \
00573         PUTCHAR(idlen, ucp); \
00574         eui64_put(val1, ucp); \
00575         len -= idlen; \
00576     } else \
00577         neg = 0; \
00578     }
00579 
00580     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
00581 
00582 #ifdef IPV6CP_COMP
00583     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
00584 #endif /* IPV6CP_COMP */
00585 
00586     *lenp -= len;
00587 }
00588 
00589 
00590 /*
00591  * ipv6cp_ackci - Ack our CIs.
00592  *
00593  * Returns:
00594  *  0 - Ack was bad.
00595  *  1 - Ack was good.
00596  */
00597 static int ipv6cp_ackci(fsm *f, u_char *p, int len) {
00598     ppp_pcb *pcb = f->pcb;
00599     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00600     u_short cilen, citype;
00601 #ifdef IPV6CP_COMP
00602     u_short cishort;
00603 #endif /* IPV6CP_COMP */
00604     eui64_t ifaceid;
00605 
00606     /*
00607      * CIs must be in exactly the same order that we sent...
00608      * Check packet length and CI length at each step.
00609      * If we find any deviations, then this packet is bad.
00610      */
00611 
00612 #ifdef IPV6CP_COMP
00613 #define ACKCIVJ(opt, neg, val) \
00614     if (neg) { \
00615     int vjlen = CILEN_COMPRESS; \
00616     if ((len -= vjlen) < 0) \
00617         goto bad; \
00618     GETCHAR(citype, p); \
00619     GETCHAR(cilen, p); \
00620     if (cilen != vjlen || \
00621         citype != opt)  \
00622         goto bad; \
00623     GETSHORT(cishort, p); \
00624     if (cishort != val) \
00625         goto bad; \
00626     }
00627 #endif /* IPV6CP_COMP */
00628 
00629 #define ACKCIIFACEID(opt, neg, val1) \
00630     if (neg) { \
00631     int idlen = CILEN_IFACEID; \
00632     if ((len -= idlen) < 0) \
00633         goto bad; \
00634     GETCHAR(citype, p); \
00635     GETCHAR(cilen, p); \
00636     if (cilen != idlen || \
00637         citype != opt) \
00638         goto bad; \
00639     eui64_get(ifaceid, p); \
00640     if (! eui64_equals(val1, ifaceid)) \
00641         goto bad; \
00642     }
00643 
00644     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
00645 
00646 #ifdef IPV6CP_COMP
00647     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
00648 #endif /* IPV6CP_COMP */
00649 
00650     /*
00651      * If there are any remaining CIs, then this packet is bad.
00652      */
00653     if (len != 0)
00654     goto bad;
00655     return (1);
00656 
00657 bad:
00658     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
00659     return (0);
00660 }
00661 
00662 /*
00663  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
00664  * This should not modify any state if the Nak is bad
00665  * or if IPV6CP is in the OPENED state.
00666  *
00667  * Returns:
00668  *  0 - Nak was bad.
00669  *  1 - Nak was good.
00670  */
00671 static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
00672     ppp_pcb *pcb = f->pcb;
00673     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00674     u_char citype, cilen, *next;
00675 #ifdef IPV6CP_COMP
00676     u_short cishort;
00677 #endif /* IPV6CP_COMP */
00678     eui64_t ifaceid;
00679     ipv6cp_options no;      /* options we've seen Naks for */
00680     ipv6cp_options try_;    /* options to request next time */
00681 
00682     BZERO(&no, sizeof(no));
00683     try_ = *go;
00684 
00685     /*
00686      * Any Nak'd CIs must be in exactly the same order that we sent.
00687      * Check packet length and CI length at each step.
00688      * If we find any deviations, then this packet is bad.
00689      */
00690 #define NAKCIIFACEID(opt, neg, code) \
00691     if (go->neg && \
00692     len >= (cilen = CILEN_IFACEID) && \
00693     p[1] == cilen && \
00694     p[0] == opt) { \
00695     len -= cilen; \
00696     INCPTR(2, p); \
00697     eui64_get(ifaceid, p); \
00698     no.neg = 1; \
00699     code \
00700     }
00701 
00702 #ifdef IPV6CP_COMP
00703 #define NAKCIVJ(opt, neg, code) \
00704     if (go->neg && \
00705     ((cilen = p[1]) == CILEN_COMPRESS) && \
00706     len >= cilen && \
00707     p[0] == opt) { \
00708     len -= cilen; \
00709     INCPTR(2, p); \
00710     GETSHORT(cishort, p); \
00711     no.neg = 1; \
00712         code \
00713     }
00714 #endif /* IPV6CP_COMP */
00715 
00716     /*
00717      * Accept the peer's idea of {our,his} interface identifier, if different
00718      * from our idea, only if the accept_{local,remote} flag is set.
00719      */
00720     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
00721          if (treat_as_reject) {
00722              try_.neg_ifaceid = 0;
00723          } else if (go->accept_local) {
00724              while (eui64_iszero(ifaceid) || 
00725                 eui64_equals(ifaceid, go->hisid)) /* bad luck */
00726              eui64_magic(ifaceid);
00727              try_.ourid = ifaceid;
00728              IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
00729          }
00730          );
00731 
00732 #ifdef IPV6CP_COMP
00733     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
00734         {
00735         if (cishort == IPV6CP_COMP && !treat_as_reject) {
00736             try_.vj_protocol = cishort;
00737         } else {
00738             try_.neg_vj = 0;
00739         }
00740         }
00741         );
00742 #endif /* IPV6CP_COMP */
00743 
00744     /*
00745      * There may be remaining CIs, if the peer is requesting negotiation
00746      * on an option that we didn't include in our request packet.
00747      * If they want to negotiate about interface identifier, we comply.
00748      * If they want us to ask for compression, we refuse.
00749      */
00750     while (len >= CILEN_VOID) {
00751     GETCHAR(citype, p);
00752     GETCHAR(cilen, p);
00753     if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
00754         goto bad;
00755     next = p + cilen - 2;
00756 
00757     switch (citype) {
00758 #ifdef IPV6CP_COMP
00759     case CI_COMPRESSTYPE:
00760         if (go->neg_vj || no.neg_vj ||
00761         (cilen != CILEN_COMPRESS))
00762         goto bad;
00763         no.neg_vj = 1;
00764         break;
00765 #endif /* IPV6CP_COMP */
00766     case CI_IFACEID:
00767         if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
00768         goto bad;
00769         try_.neg_ifaceid = 1;
00770         eui64_get(ifaceid, p);
00771         if (go->accept_local) {
00772         while (eui64_iszero(ifaceid) || 
00773                eui64_equals(ifaceid, go->hisid)) /* bad luck */
00774             eui64_magic(ifaceid);
00775         try_.ourid = ifaceid;
00776         }
00777         no.neg_ifaceid = 1;
00778         break;
00779     default:
00780         break;
00781     }
00782     p = next;
00783     }
00784 
00785     /* If there is still anything left, this packet is bad. */
00786     if (len != 0)
00787     goto bad;
00788 
00789     /*
00790      * OK, the Nak is good.  Now we can update state.
00791      */
00792     if (f->state != PPP_FSM_OPENED)
00793     *go = try_;
00794 
00795     return 1;
00796 
00797 bad:
00798     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
00799     return 0;
00800 }
00801 
00802 
00803 /*
00804  * ipv6cp_rejci - Reject some of our CIs.
00805  */
00806 static int ipv6cp_rejci(fsm *f, u_char *p, int len) {
00807     ppp_pcb *pcb = f->pcb;
00808     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00809     u_char cilen;
00810 #ifdef IPV6CP_COMP
00811     u_short cishort;
00812 #endif /* IPV6CP_COMP */
00813     eui64_t ifaceid;
00814     ipv6cp_options try_;        /* options to request next time */
00815 
00816     try_ = *go;
00817     /*
00818      * Any Rejected CIs must be in exactly the same order that we sent.
00819      * Check packet length and CI length at each step.
00820      * If we find any deviations, then this packet is bad.
00821      */
00822 #define REJCIIFACEID(opt, neg, val1) \
00823     if (go->neg && \
00824     len >= (cilen = CILEN_IFACEID) && \
00825     p[1] == cilen && \
00826     p[0] == opt) { \
00827     len -= cilen; \
00828     INCPTR(2, p); \
00829     eui64_get(ifaceid, p); \
00830     /* Check rejected value. */ \
00831     if (! eui64_equals(ifaceid, val1)) \
00832         goto bad; \
00833     try_.neg = 0; \
00834     }
00835 
00836 #ifdef IPV6CP_COMP
00837 #define REJCIVJ(opt, neg, val) \
00838     if (go->neg && \
00839     p[1] == CILEN_COMPRESS && \
00840     len >= p[1] && \
00841     p[0] == opt) { \
00842     len -= p[1]; \
00843     INCPTR(2, p); \
00844     GETSHORT(cishort, p); \
00845     /* Check rejected value. */  \
00846     if (cishort != val) \
00847         goto bad; \
00848     try_.neg = 0; \
00849      }
00850 #endif /* IPV6CP_COMP */
00851 
00852     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
00853 
00854 #ifdef IPV6CP_COMP
00855     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
00856 #endif /* IPV6CP_COMP */
00857 
00858     /*
00859      * If there are any remaining CIs, then this packet is bad.
00860      */
00861     if (len != 0)
00862     goto bad;
00863     /*
00864      * Now we can update state.
00865      */
00866     if (f->state != PPP_FSM_OPENED)
00867     *go = try_;
00868     return 1;
00869 
00870 bad:
00871     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
00872     return 0;
00873 }
00874 
00875 
00876 /*
00877  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
00878  *
00879  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
00880  * appropriately.  If reject_if_disagree is non-zero, doesn't return
00881  * CONFNAK; returns CONFREJ if it can't return CONFACK.
00882  *
00883  * inp = Requested CIs
00884  * len = Length of requested CIs
00885  *
00886  */
00887 static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) {
00888     ppp_pcb *pcb = f->pcb;
00889     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
00890     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
00891     ipv6cp_options *ao = &pcb->ipv6cp_allowoptions;
00892     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
00893     u_char *cip, *next;     /* Pointer to current and next CIs */
00894     u_short cilen, citype;  /* Parsed len, type */
00895 #ifdef IPV6CP_COMP
00896     u_short cishort;        /* Parsed short value */
00897 #endif /* IPV6CP_COMP */
00898     eui64_t ifaceid;        /* Parsed interface identifier */
00899     int rc = CONFACK;       /* Final packet return code */
00900     int orc;            /* Individual option return code */
00901     u_char *p;          /* Pointer to next char to parse */
00902     u_char *ucp = inp;      /* Pointer to current output char */
00903     int l = *len;       /* Length left */
00904 
00905     /*
00906      * Reset all his options.
00907      */
00908     BZERO(ho, sizeof(*ho));
00909     
00910     /*
00911      * Process all his options.
00912      */
00913     next = inp;
00914     while (l) {
00915     orc = CONFACK;          /* Assume success */
00916     cip = p = next;         /* Remember begining of CI */
00917     if (l < 2 ||            /* Not enough data for CI header or */
00918         p[1] < 2 ||         /*  CI length too small or */
00919         p[1] > l) {         /*  CI length too big? */
00920         IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
00921         orc = CONFREJ;      /* Reject bad CI */
00922         cilen = l;          /* Reject till end of packet */
00923         l = 0;          /* Don't loop again */
00924         goto endswitch;
00925     }
00926     GETCHAR(citype, p);     /* Parse CI type */
00927     GETCHAR(cilen, p);      /* Parse CI length */
00928     l -= cilen;         /* Adjust remaining length */
00929     next += cilen;          /* Step to next CI */
00930 
00931     switch (citype) {       /* Check CI type */
00932     case CI_IFACEID:
00933         IPV6CPDEBUG(("ipv6cp: received interface identifier "));
00934 
00935         if (!ao->neg_ifaceid ||
00936         cilen != CILEN_IFACEID) {   /* Check CI length */
00937         orc = CONFREJ;      /* Reject CI */
00938         break;
00939         }
00940 
00941         /*
00942          * If he has no interface identifier, or if we both have same 
00943          * identifier then NAK it with new idea.
00944          * In particular, if we don't know his identifier, but he does,
00945          * then accept it.
00946          */
00947         eui64_get(ifaceid, p);
00948         IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
00949         if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
00950         orc = CONFREJ;      /* Reject CI */
00951         break;
00952         }
00953         if (!eui64_iszero(wo->hisid) && 
00954         !eui64_equals(ifaceid, wo->hisid) && 
00955         eui64_iszero(go->hisid)) {
00956             
00957         orc = CONFNAK;
00958         ifaceid = wo->hisid;
00959         go->hisid = ifaceid;
00960         DECPTR(sizeof(ifaceid), p);
00961         eui64_put(ifaceid, p);
00962         } else
00963         if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
00964         orc = CONFNAK;
00965         if (eui64_iszero(go->hisid))    /* first time, try option */
00966             ifaceid = wo->hisid;
00967         while (eui64_iszero(ifaceid) || 
00968                eui64_equals(ifaceid, go->ourid)) /* bad luck */
00969             eui64_magic(ifaceid);
00970         go->hisid = ifaceid;
00971         DECPTR(sizeof(ifaceid), p);
00972         eui64_put(ifaceid, p);
00973         }
00974 
00975         ho->neg_ifaceid = 1;
00976         ho->hisid = ifaceid;
00977         break;
00978 
00979 #ifdef IPV6CP_COMP
00980     case CI_COMPRESSTYPE:
00981         IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
00982         if (!ao->neg_vj ||
00983         (cilen != CILEN_COMPRESS)) {
00984         orc = CONFREJ;
00985         break;
00986         }
00987         GETSHORT(cishort, p);
00988         IPV6CPDEBUG(("(%d)", cishort));
00989 
00990         if (!(cishort == IPV6CP_COMP)) {
00991         orc = CONFREJ;
00992         break;
00993         }
00994 
00995         ho->neg_vj = 1;
00996         ho->vj_protocol = cishort;
00997         break;
00998 #endif /* IPV6CP_COMP */
00999 
01000     default:
01001         orc = CONFREJ;
01002         break;
01003     }
01004 
01005 endswitch:
01006     IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
01007 
01008     if (orc == CONFACK &&       /* Good CI */
01009         rc != CONFACK)      /*  but prior CI wasnt? */
01010         continue;           /* Don't send this one */
01011 
01012     if (orc == CONFNAK) {       /* Nak this CI? */
01013         if (reject_if_disagree) /* Getting fed up with sending NAKs? */
01014         orc = CONFREJ;      /* Get tough if so */
01015         else {
01016         if (rc == CONFREJ)  /* Rejecting prior CI? */
01017             continue;       /* Don't send this one */
01018         if (rc == CONFACK) {    /* Ack'd all prior CIs? */
01019             rc = CONFNAK;   /* Not anymore... */
01020             ucp = inp;      /* Backup */
01021         }
01022         }
01023     }
01024 
01025     if (orc == CONFREJ &&       /* Reject this CI */
01026         rc != CONFREJ) {        /*  but no prior ones? */
01027         rc = CONFREJ;
01028         ucp = inp;          /* Backup */
01029     }
01030 
01031     /* Need to move CI? */
01032     if (ucp != cip)
01033         MEMCPY(ucp, cip, cilen);    /* Move it */
01034 
01035     /* Update output pointer */
01036     INCPTR(cilen, ucp);
01037     }
01038 
01039     /*
01040      * If we aren't rejecting this packet, and we want to negotiate
01041      * their identifier and they didn't send their identifier, then we
01042      * send a NAK with a CI_IFACEID option appended.  We assume the
01043      * input buffer is long enough that we can append the extra
01044      * option safely.
01045      */
01046     if (rc != CONFREJ && !ho->neg_ifaceid &&
01047     wo->req_ifaceid && !reject_if_disagree) {
01048     if (rc == CONFACK) {
01049         rc = CONFNAK;
01050         ucp = inp;              /* reset pointer */
01051         wo->req_ifaceid = 0;        /* don't ask again */
01052     }
01053     PUTCHAR(CI_IFACEID, ucp);
01054     PUTCHAR(CILEN_IFACEID, ucp);
01055     eui64_put(wo->hisid, ucp);
01056     }
01057 
01058     *len = ucp - inp;           /* Compute output length */
01059     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
01060     return (rc);            /* Return final code */
01061 }
01062 
01063 #if PPP_OPTIONS
01064 /*
01065  * ipv6_check_options - check that any IP-related options are OK,
01066  * and assign appropriate defaults.
01067  */
01068 static void ipv6_check_options() {
01069     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
01070 
01071     if (!ipv6cp_protent.enabled_flag)
01072     return;
01073 
01074     /*
01075      * Persistent link-local id is only used when user has not explicitly
01076      * configure/hard-code the id
01077      */
01078     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
01079 
01080     /* 
01081      * On systems where there are no Ethernet interfaces used, there
01082      * may be other ways to obtain a persistent id. Right now, it
01083      * will fall back to using magic [see eui64_magic] below when
01084      * an EUI-48 from MAC address can't be obtained. Other possibilities
01085      * include obtaining EEPROM serial numbers, or some other unique
01086      * yet persistent number. On Sparc platforms, this is possible,
01087      * but too bad there's no standards yet for x86 machines.
01088      */
01089     if (ether_to_eui64(&wo->ourid)) {
01090         wo->opt_local = 1;
01091     }
01092     }
01093 
01094     if (!wo->opt_local) {   /* init interface identifier */
01095     if (wo->use_ip && eui64_iszero(wo->ourid)) {
01096         eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
01097         if (!eui64_iszero(wo->ourid))
01098         wo->opt_local = 1;
01099     }
01100     
01101     while (eui64_iszero(wo->ourid))
01102         eui64_magic(wo->ourid);
01103     }
01104 
01105     if (!wo->opt_remote) {
01106     if (wo->use_ip && eui64_iszero(wo->hisid)) {
01107         eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
01108         if (!eui64_iszero(wo->hisid))
01109         wo->opt_remote = 1;
01110     }
01111     }
01112 
01113     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
01114     option_error("local/remote LL address required for demand-dialling\n");
01115     exit(1);
01116     }
01117 }
01118 #endif /* PPP_OPTIONS */
01119 
01120 #if DEMAND_SUPPORT
01121 /*
01122  * ipv6_demand_conf - configure the interface as though
01123  * IPV6CP were up, for use with dial-on-demand.
01124  */
01125 static int ipv6_demand_conf(int u) {
01126     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
01127 
01128     if (!sif6up(u))
01129     return 0;
01130 
01131     if (!sif6addr(u, wo->ourid, wo->hisid))
01132     return 0;
01133 
01134     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
01135     return 0;
01136 
01137     ppp_notice("ipv6_demand_conf");
01138     ppp_notice("local  LL address %s", llv6_ntoa(wo->ourid));
01139     ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid));
01140 
01141     return 1;
01142 }
01143 #endif /* DEMAND_SUPPORT */
01144 
01145 
01146 /*
01147  * ipv6cp_up - IPV6CP has come UP.
01148  *
01149  * Configure the IPv6 network interface appropriately and bring it up.
01150  */
01151 static void ipv6cp_up(fsm *f) {
01152     ppp_pcb *pcb = f->pcb;
01153     ipv6cp_options *wo = &pcb->ipv6cp_wantoptions;
01154     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
01155     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
01156 
01157     IPV6CPDEBUG(("ipv6cp: up"));
01158 
01159     /*
01160      * We must have a non-zero LL address for both ends of the link.
01161      */
01162     if (!ho->neg_ifaceid)
01163     ho->hisid = wo->hisid;
01164 
01165 #if 0 /* UNUSED */
01166     if(!no_ifaceid_neg) {
01167 #endif /* UNUSED */
01168     if (eui64_iszero(ho->hisid)) {
01169         ppp_error("Could not determine remote LL address");
01170         ipv6cp_close(f->pcb, "Could not determine remote LL address");
01171         return;
01172     }
01173     if (eui64_iszero(go->ourid)) {
01174         ppp_error("Could not determine local LL address");
01175         ipv6cp_close(f->pcb, "Could not determine local LL address");
01176         return;
01177     }
01178     if (eui64_equals(go->ourid, ho->hisid)) {
01179         ppp_error("local and remote LL addresses are equal");
01180         ipv6cp_close(f->pcb, "local and remote LL addresses are equal");
01181         return;
01182     }
01183 #if 0 /* UNUSED */
01184     }
01185 #endif /* UNUSED */
01186 #if 0 /* UNUSED */
01187     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
01188     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
01189 #endif /* UNUSED */
01190 
01191 #ifdef IPV6CP_COMP
01192     /* set tcp compression */
01193     sif6comp(f->unit, ho->neg_vj);
01194 #endif
01195 
01196 #if DEMAND_SUPPORT
01197     /*
01198      * If we are doing dial-on-demand, the interface is already
01199      * configured, so we put out any saved-up packets, then set the
01200      * interface to pass IPv6 packets.
01201      */
01202     if (demand) {
01203     if (! eui64_equals(go->ourid, wo->ourid) || 
01204         ! eui64_equals(ho->hisid, wo->hisid)) {
01205         if (! eui64_equals(go->ourid, wo->ourid))
01206         warn("Local LL address changed to %s", 
01207              llv6_ntoa(go->ourid));
01208         if (! eui64_equals(ho->hisid, wo->hisid))
01209         warn("Remote LL address changed to %s", 
01210              llv6_ntoa(ho->hisid));
01211         ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid);
01212 
01213         /* Set the interface to the new addresses */
01214         if (!sif6addr(f->pcb, go->ourid, ho->hisid)) {
01215         if (debug)
01216             warn("sif6addr failed");
01217         ipv6cp_close(f->unit, "Interface configuration failed");
01218         return;
01219         }
01220 
01221     }
01222     demand_rexmit(PPP_IPV6);
01223     sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
01224 
01225     } else
01226 #endif /* DEMAND_SUPPORT */
01227     {
01228     /*
01229      * Set LL addresses
01230      */
01231     if (!sif6addr(f->pcb, go->ourid, ho->hisid)) {
01232         PPPDEBUG(LOG_DEBUG, ("sif6addr failed"));
01233         ipv6cp_close(f->pcb, "Interface configuration failed");
01234         return;
01235     }
01236 
01237     /* bring the interface up for IPv6 */
01238     if (!sif6up(f->pcb)) {
01239         PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)"));
01240         ipv6cp_close(f->pcb, "Interface configuration failed");
01241         return;
01242     }
01243 #if DEMAND_SUPPORT
01244     sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS);
01245 #endif /* DEMAND_SUPPORT */
01246 
01247     ppp_notice("local  LL address %s", llv6_ntoa(go->ourid));
01248     ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid));
01249     }
01250 
01251     np_up(f->pcb, PPP_IPV6);
01252     pcb->ipv6cp_is_up = 1;
01253 
01254 #if 0 /* UNUSED */
01255     /*
01256      * Execute the ipv6-up script, like this:
01257      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
01258      */
01259     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
01260     ipv6cp_script_state = s_up;
01261     ipv6cp_script(_PATH_IPV6UP);
01262     }
01263 #endif /* UNUSED */
01264 }
01265 
01266 
01267 /*
01268  * ipv6cp_down - IPV6CP has gone DOWN.
01269  *
01270  * Take the IPv6 network interface down, clear its addresses
01271  * and delete routes through it.
01272  */
01273 static void ipv6cp_down(fsm *f) {
01274     ppp_pcb *pcb = f->pcb;
01275     ipv6cp_options *go = &pcb->ipv6cp_gotoptions;
01276     ipv6cp_options *ho = &pcb->ipv6cp_hisoptions;
01277 
01278     IPV6CPDEBUG(("ipv6cp: down"));
01279 #if PPP_STATS_SUPPORT
01280     update_link_stats(f->unit);
01281 #endif /* PPP_STATS_SUPPORT */
01282     if (pcb->ipv6cp_is_up) {
01283     pcb->ipv6cp_is_up = 0;
01284     np_down(f->pcb, PPP_IPV6);
01285     }
01286 #ifdef IPV6CP_COMP
01287     sif6comp(f->unit, 0);
01288 #endif
01289 
01290 #if DEMAND_SUPPORT
01291     /*
01292      * If we are doing dial-on-demand, set the interface
01293      * to queue up outgoing packets (for now).
01294      */
01295     if (demand) {
01296     sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE);
01297     } else
01298 #endif /* DEMAND_SUPPORT */
01299     {
01300 #if DEMAND_SUPPORT
01301     sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP);
01302 #endif /* DEMAND_SUPPORT */
01303     ipv6cp_clear_addrs(f->pcb,
01304                go->ourid,
01305                ho->hisid);
01306     sif6down(f->pcb);
01307     }
01308 
01309 #if 0 /* UNUSED */
01310     /* Execute the ipv6-down script */
01311     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
01312     ipv6cp_script_state = s_down;
01313     ipv6cp_script(_PATH_IPV6DOWN);
01314     }
01315 #endif /* UNUSED */
01316 }
01317 
01318 
01319 /*
01320  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
01321  * proxy neighbour discovery entries, etc.
01322  */
01323 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) {
01324     cif6addr(pcb, ourid, hisid);
01325 }
01326 
01327 
01328 /*
01329  * ipv6cp_finished - possibly shut down the lower layers.
01330  */
01331 static void ipv6cp_finished(fsm *f) {
01332     np_finished(f->pcb, PPP_IPV6);
01333 }
01334 
01335 
01336 #if 0 /* UNUSED */
01337 /*
01338  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
01339  * has finished.
01340  */
01341 static void
01342 ipv6cp_script_done(arg)
01343     void *arg;
01344 {
01345     ipv6cp_script_pid = 0;
01346     switch (ipv6cp_script_state) {
01347     case s_up:
01348     if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) {
01349         ipv6cp_script_state = s_down;
01350         ipv6cp_script(_PATH_IPV6DOWN);
01351     }
01352     break;
01353     case s_down:
01354     if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) {
01355         ipv6cp_script_state = s_up;
01356         ipv6cp_script(_PATH_IPV6UP);
01357     }
01358     break;
01359     }
01360 }
01361 
01362 
01363 /*
01364  * ipv6cp_script - Execute a script with arguments
01365  * interface-name tty-name speed local-LL remote-LL.
01366  */
01367 static void
01368 ipv6cp_script(script)
01369     char *script;
01370 {
01371     char strspeed[32], strlocal[32], strremote[32];
01372     char *argv[8];
01373 
01374     sprintf(strspeed, "%d", baud_rate);
01375     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
01376     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
01377 
01378     argv[0] = script;
01379     argv[1] = ifname;
01380     argv[2] = devnam;
01381     argv[3] = strspeed;
01382     argv[4] = strlocal;
01383     argv[5] = strremote;
01384     argv[6] = ipparam;
01385     argv[7] = NULL;
01386 
01387     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
01388                     NULL, 0);
01389 }
01390 #endif /* UNUSED */
01391 
01392 #if PRINTPKT_SUPPORT
01393 /*
01394  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
01395  */
01396 static const char* const ipv6cp_codenames[] = {
01397     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
01398     "TermReq", "TermAck", "CodeRej"
01399 };
01400 
01401 static int ipv6cp_printpkt(const u_char *p, int plen,
01402         void (*printer)(void *, const char *, ...), void *arg) {
01403     int code, id, len, olen;
01404     const u_char *pstart, *optend;
01405 #ifdef IPV6CP_COMP
01406     u_short cishort;
01407 #endif /* IPV6CP_COMP */
01408     eui64_t ifaceid;
01409 
01410     if (plen < HEADERLEN)
01411     return 0;
01412     pstart = p;
01413     GETCHAR(code, p);
01414     GETCHAR(id, p);
01415     GETSHORT(len, p);
01416     if (len < HEADERLEN || len > plen)
01417     return 0;
01418 
01419     if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames))
01420     printer(arg, " %s", ipv6cp_codenames[code-1]);
01421     else
01422     printer(arg, " code=0x%x", code);
01423     printer(arg, " id=0x%x", id);
01424     len -= HEADERLEN;
01425     switch (code) {
01426     case CONFREQ:
01427     case CONFACK:
01428     case CONFNAK:
01429     case CONFREJ:
01430     /* print option list */
01431     while (len >= 2) {
01432         GETCHAR(code, p);
01433         GETCHAR(olen, p);
01434         p -= 2;
01435         if (olen < 2 || olen > len) {
01436         break;
01437         }
01438         printer(arg, " <");
01439         len -= olen;
01440         optend = p + olen;
01441         switch (code) {
01442 #ifdef IPV6CP_COMP
01443         case CI_COMPRESSTYPE:
01444         if (olen >= CILEN_COMPRESS) {
01445             p += 2;
01446             GETSHORT(cishort, p);
01447             printer(arg, "compress ");
01448             printer(arg, "0x%x", cishort);
01449         }
01450         break;
01451 #endif /* IPV6CP_COMP */
01452         case CI_IFACEID:
01453         if (olen == CILEN_IFACEID) {
01454             p += 2;
01455             eui64_get(ifaceid, p);
01456             printer(arg, "addr %s", llv6_ntoa(ifaceid));
01457         }
01458         break;
01459         default:
01460         break;
01461         }
01462         while (p < optend) {
01463         GETCHAR(code, p);
01464         printer(arg, " %.2x", code);
01465         }
01466         printer(arg, ">");
01467     }
01468     break;
01469 
01470     case TERMACK:
01471     case TERMREQ:
01472     if (len > 0 && *p >= ' ' && *p < 0x7f) {
01473         printer(arg, " ");
01474         ppp_print_string(p, len, printer, arg);
01475         p += len;
01476         len = 0;
01477     }
01478     break;
01479     default:
01480     break;
01481     }
01482 
01483     /* print the rest of the bytes in the packet */
01484     for (; len > 0; --len) {
01485     GETCHAR(code, p);
01486     printer(arg, " %.2x", code);
01487     }
01488 
01489     return p - pstart;
01490 }
01491 #endif /* PRINTPKT_SUPPORT */
01492 
01493 #if DEMAND_SUPPORT
01494 /*
01495  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
01496  * We don't bring the link up for IP fragments or for TCP FIN packets
01497  * with no data.
01498  */
01499 #define IP6_HDRLEN  40  /* bytes */
01500 #define IP6_NHDR_FRAG   44  /* fragment IPv6 header */
01501 #define TCP_HDRLEN  20
01502 #define TH_FIN      0x01
01503 
01504 /*
01505  * We use these macros because the IP header may be at an odd address,
01506  * and some compilers might use word loads to get th_off or ip_hl.
01507  */
01508 
01509 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
01510 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
01511 #define get_tcpflags(x) (((unsigned char *)(x))[13])
01512 
01513 static int ipv6_active_pkt(u_char *pkt, int len) {
01514     u_char *tcp;
01515 
01516     len -= PPP_HDRLEN;
01517     pkt += PPP_HDRLEN;
01518     if (len < IP6_HDRLEN)
01519     return 0;
01520     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
01521     return 0;
01522     if (get_ip6nh(pkt) != IPPROTO_TCP)
01523     return 1;
01524     if (len < IP6_HDRLEN + TCP_HDRLEN)
01525     return 0;
01526     tcp = pkt + IP6_HDRLEN;
01527     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
01528     return 0;
01529     return 1;
01530 }
01531 #endif /* DEMAND_SUPPORT */
01532 
01533 #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */