1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate ipv6cp.c - PPP IPV6 Control Protocol. 6*7c478bd9Sstevel@tonic-gate Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi> 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate Redistribution and use in source and binary forms are permitted 9*7c478bd9Sstevel@tonic-gate provided that the above copyright notice and this paragraph are 10*7c478bd9Sstevel@tonic-gate duplicated in all such forms. The name of the author may not be 11*7c478bd9Sstevel@tonic-gate used to endorse or promote products derived from this software 12*7c478bd9Sstevel@tonic-gate without specific prior written permission. 13*7c478bd9Sstevel@tonic-gate THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*7c478bd9Sstevel@tonic-gate IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*7c478bd9Sstevel@tonic-gate WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*7c478bd9Sstevel@tonic-gate */ 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate /* Original version, based on RFC2023 : 19*7c478bd9Sstevel@tonic-gate 20*7c478bd9Sstevel@tonic-gate Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, 21*7c478bd9Sstevel@tonic-gate Alain.Durand@imag.fr, IMAG, 22*7c478bd9Sstevel@tonic-gate Jean-Luc.Richier@imag.fr, IMAG-LSR. 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, 25*7c478bd9Sstevel@tonic-gate Alain.Durand@imag.fr, IMAG, 26*7c478bd9Sstevel@tonic-gate Jean-Luc.Richier@imag.fr, IMAG-LSR. 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate Ce travail a �t� fait au sein du GIE DYADE (Groupement d'Int�r�t 29*7c478bd9Sstevel@tonic-gate �conomique ayant pour membres BULL S.A. et l'INRIA). 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate Ce logiciel informatique est disponible aux conditions 32*7c478bd9Sstevel@tonic-gate usuelles dans la recherche, c'est-�-dire qu'il peut 33*7c478bd9Sstevel@tonic-gate �tre utilis�, copi�, modifi�, distribu� � l'unique 34*7c478bd9Sstevel@tonic-gate condition que ce texte soit conserv� afin que 35*7c478bd9Sstevel@tonic-gate l'origine de ce logiciel soit reconnue. 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate Le nom de l'Institut National de Recherche en Informatique 38*7c478bd9Sstevel@tonic-gate et en Automatique (INRIA), de l'IMAG, ou d'une personne morale 39*7c478bd9Sstevel@tonic-gate ou physique ayant particip� � l'�laboration de ce logiciel ne peut 40*7c478bd9Sstevel@tonic-gate �tre utilis� sans son accord pr�alable explicite. 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate Ce logiciel est fourni tel quel sans aucune garantie, 43*7c478bd9Sstevel@tonic-gate support ou responsabilit� d'aucune sorte. 44*7c478bd9Sstevel@tonic-gate Ce logiciel est d�riv� de sources d'origine 45*7c478bd9Sstevel@tonic-gate "University of California at Berkeley" et 46*7c478bd9Sstevel@tonic-gate "Digital Equipment Corporation" couvertes par des copyrights. 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate L'Institut d'Informatique et de Math�matiques Appliqu�es de Grenoble (IMAG) 49*7c478bd9Sstevel@tonic-gate est une f�d�ration d'unit�s mixtes de recherche du CNRS, de l'Institut National 50*7c478bd9Sstevel@tonic-gate Polytechnique de Grenoble et de l'Universit� Joseph Fourier regroupant 51*7c478bd9Sstevel@tonic-gate sept laboratoires dont le laboratoire Logiciels, Syst�mes, R�seaux (LSR). 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate This work has been done in the context of GIE DYADE (joint R & D venture 54*7c478bd9Sstevel@tonic-gate between BULL S.A. and INRIA). 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate This software is available with usual "research" terms 57*7c478bd9Sstevel@tonic-gate with the aim of retain credits of the software. 58*7c478bd9Sstevel@tonic-gate Permission to use, copy, modify and distribute this software for any 59*7c478bd9Sstevel@tonic-gate purpose and without fee is hereby granted, provided that the above 60*7c478bd9Sstevel@tonic-gate copyright notice and this permission notice appear in all copies, 61*7c478bd9Sstevel@tonic-gate and the name of INRIA, IMAG, or any contributor not be used in advertising 62*7c478bd9Sstevel@tonic-gate or publicity pertaining to this material without the prior explicit 63*7c478bd9Sstevel@tonic-gate permission. The software is provided "as is" without any 64*7c478bd9Sstevel@tonic-gate warranties, support or liabilities of any kind. 65*7c478bd9Sstevel@tonic-gate This software is derived from source code from 66*7c478bd9Sstevel@tonic-gate "University of California at Berkeley" and 67*7c478bd9Sstevel@tonic-gate "Digital Equipment Corporation" protected by copyrights. 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) 70*7c478bd9Sstevel@tonic-gate is a federation of seven research units funded by the CNRS, National 71*7c478bd9Sstevel@tonic-gate Polytechnic Institute of Grenoble and University Joseph Fourier. 72*7c478bd9Sstevel@tonic-gate The research unit in Software, Systems, Networks (LSR) is member of IMAG. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * Derived from : 77*7c478bd9Sstevel@tonic-gate * 78*7c478bd9Sstevel@tonic-gate * 79*7c478bd9Sstevel@tonic-gate * ipcp.c - PPP IP Control Protocol. 80*7c478bd9Sstevel@tonic-gate * 81*7c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Carnegie Mellon University. 82*7c478bd9Sstevel@tonic-gate * All rights reserved. 83*7c478bd9Sstevel@tonic-gate * 84*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 85*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 86*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 87*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 88*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 89*7c478bd9Sstevel@tonic-gate * by Carnegie Mellon University. The name of the 90*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 91*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 92*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 93*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 94*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 95*7c478bd9Sstevel@tonic-gate * 96*7c478bd9Sstevel@tonic-gate * $Id: ipv6cp.c,v 1.9 2000/04/15 01:27:11 masputra Exp $ 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 100*7c478bd9Sstevel@tonic-gate #define RCSID "$Id: ipv6cp.c,v 1.9 2000/04/15 01:27:11 masputra Exp $" 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * TODO: 104*7c478bd9Sstevel@tonic-gate * 105*7c478bd9Sstevel@tonic-gate * Proxy Neighbour Discovery. 106*7c478bd9Sstevel@tonic-gate * 107*7c478bd9Sstevel@tonic-gate * Better defines for selecting the ordering of 108*7c478bd9Sstevel@tonic-gate * interface up / set address. (currently checks for __linux__, 109*7c478bd9Sstevel@tonic-gate * since SVR4 && (SNI || __USLC__) didn't work properly) 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #include <stdio.h> 113*7c478bd9Sstevel@tonic-gate #include <string.h> 114*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 115*7c478bd9Sstevel@tonic-gate #include <unistd.h> 116*7c478bd9Sstevel@tonic-gate #include <netdb.h> 117*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 118*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 119*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 120*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 121*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate #include "pppd.h" 124*7c478bd9Sstevel@tonic-gate #include "eui64.h" 125*7c478bd9Sstevel@tonic-gate #include "fsm.h" 126*7c478bd9Sstevel@tonic-gate #include "ipcp.h" 127*7c478bd9Sstevel@tonic-gate #include "ipv6cp.h" 128*7c478bd9Sstevel@tonic-gate #include "magic.h" 129*7c478bd9Sstevel@tonic-gate #include "pathnames.h" 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 132*7c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 133*7c478bd9Sstevel@tonic-gate #endif 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* global vars */ 136*7c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */ 137*7c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ 138*7c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ 139*7c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */ 140*7c478bd9Sstevel@tonic-gate int no_ifaceid_neg = 0; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* local vars */ 143*7c478bd9Sstevel@tonic-gate static bool ipv6cp_is_up; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Callbacks for fsm code. (CI = Configuration Information) 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */ 149*7c478bd9Sstevel@tonic-gate static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */ 150*7c478bd9Sstevel@tonic-gate static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ 151*7c478bd9Sstevel@tonic-gate static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ 152*7c478bd9Sstevel@tonic-gate static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ 153*7c478bd9Sstevel@tonic-gate static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ 154*7c478bd9Sstevel@tonic-gate static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ 155*7c478bd9Sstevel@tonic-gate static void ipv6cp_up __P((fsm *)); /* We're UP */ 156*7c478bd9Sstevel@tonic-gate static void ipv6cp_down __P((fsm *)); /* We're DOWN */ 157*7c478bd9Sstevel@tonic-gate static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */ 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */ 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ 162*7c478bd9Sstevel@tonic-gate ipv6cp_resetci, /* Reset our Configuration Information */ 163*7c478bd9Sstevel@tonic-gate ipv6cp_cilen, /* Length of our Configuration Information */ 164*7c478bd9Sstevel@tonic-gate ipv6cp_addci, /* Add our Configuration Information */ 165*7c478bd9Sstevel@tonic-gate ipv6cp_ackci, /* ACK our Configuration Information */ 166*7c478bd9Sstevel@tonic-gate ipv6cp_nakci, /* NAK our Configuration Information */ 167*7c478bd9Sstevel@tonic-gate ipv6cp_rejci, /* Reject our Configuration Information */ 168*7c478bd9Sstevel@tonic-gate ipv6cp_reqci, /* Request peer's Configuration Information */ 169*7c478bd9Sstevel@tonic-gate ipv6cp_up, /* Called when fsm reaches OPENED state */ 170*7c478bd9Sstevel@tonic-gate ipv6cp_down, /* Called when fsm leaves OPENED state */ 171*7c478bd9Sstevel@tonic-gate NULL, /* Called when we want the lower layer up */ 172*7c478bd9Sstevel@tonic-gate ipv6cp_finished, /* Called when we want the lower layer down */ 173*7c478bd9Sstevel@tonic-gate NULL, /* Retransmission is necessary */ 174*7c478bd9Sstevel@tonic-gate NULL, /* Called to handle protocol-specific codes */ 175*7c478bd9Sstevel@tonic-gate "IPV6CP", /* String name of protocol */ 176*7c478bd9Sstevel@tonic-gate NULL /* Peer rejected a code number */ 177*7c478bd9Sstevel@tonic-gate }; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate static int setifaceid __P((char **arg, option_t *)); 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * Command-line options. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate static option_t ipv6cp_option_list[] = { 185*7c478bd9Sstevel@tonic-gate { "ipv6", o_special, (void *)setifaceid, 186*7c478bd9Sstevel@tonic-gate "Set interface identifiers for IPV6" }, 187*7c478bd9Sstevel@tonic-gate { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, 188*7c478bd9Sstevel@tonic-gate "Disable IPv6 and IPv6CP" }, 189*7c478bd9Sstevel@tonic-gate { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, 190*7c478bd9Sstevel@tonic-gate "Disable IPv6 and IPv6CP" }, 191*7c478bd9Sstevel@tonic-gate { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, 192*7c478bd9Sstevel@tonic-gate "Enable IPv6 and IPv6CP", 1 }, 193*7c478bd9Sstevel@tonic-gate { "ipv6cp-accept-local", o_bool, &ipv6cp_wantoptions[0].accept_local, 194*7c478bd9Sstevel@tonic-gate "Accept peer's interface identifier for us", 1 }, 195*7c478bd9Sstevel@tonic-gate { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_wantoptions[0].use_ip, 196*7c478bd9Sstevel@tonic-gate "Use (default) IPv4 address as interface identifier", 1 }, 197*7c478bd9Sstevel@tonic-gate #if defined(SOL2) 198*7c478bd9Sstevel@tonic-gate { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, 199*7c478bd9Sstevel@tonic-gate "Use unique persistent value for link local address", 1 }, 200*7c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */ 201*7c478bd9Sstevel@tonic-gate { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, 202*7c478bd9Sstevel@tonic-gate "Set timeout for IPv6CP" }, 203*7c478bd9Sstevel@tonic-gate { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, 204*7c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Terminate-Request" }, 205*7c478bd9Sstevel@tonic-gate { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, 206*7c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Configure-Request" }, 207*7c478bd9Sstevel@tonic-gate { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, 208*7c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Configure-Nak" }, 209*7c478bd9Sstevel@tonic-gate { NULL } 210*7c478bd9Sstevel@tonic-gate }; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* 214*7c478bd9Sstevel@tonic-gate * Protocol entry points from main code. 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate static void ipv6cp_init __P((int)); 217*7c478bd9Sstevel@tonic-gate static void ipv6cp_open __P((int)); 218*7c478bd9Sstevel@tonic-gate static void ipv6cp_close __P((int, char *)); 219*7c478bd9Sstevel@tonic-gate static void ipv6cp_lowerup __P((int)); 220*7c478bd9Sstevel@tonic-gate static void ipv6cp_lowerdown __P((int)); 221*7c478bd9Sstevel@tonic-gate static void ipv6cp_input __P((int, u_char *, int)); 222*7c478bd9Sstevel@tonic-gate static void ipv6cp_protrej __P((int)); 223*7c478bd9Sstevel@tonic-gate static int ipv6cp_printpkt __P((u_char *, int, 224*7c478bd9Sstevel@tonic-gate void (*) __P((void *, const char *, ...)), void *)); 225*7c478bd9Sstevel@tonic-gate static void ipv6_check_options __P((void)); 226*7c478bd9Sstevel@tonic-gate static int ipv6_demand_conf __P((int)); 227*7c478bd9Sstevel@tonic-gate static int ipv6_active_pkt __P((u_char *, int)); 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate struct protent ipv6cp_protent = { 230*7c478bd9Sstevel@tonic-gate PPP_IPV6CP, /* Protocol Number for IPV6CP */ 231*7c478bd9Sstevel@tonic-gate ipv6cp_init, /* Initializes IPV6CP */ 232*7c478bd9Sstevel@tonic-gate ipv6cp_input, /* Processes a received IPV6CP packet */ 233*7c478bd9Sstevel@tonic-gate ipv6cp_protrej, /* Process a received Protocol-reject */ 234*7c478bd9Sstevel@tonic-gate ipv6cp_lowerup, /* Called when LCP is brought up */ 235*7c478bd9Sstevel@tonic-gate ipv6cp_lowerdown, /* Called when LCP has gone down */ 236*7c478bd9Sstevel@tonic-gate ipv6cp_open, /* Called when link is established */ 237*7c478bd9Sstevel@tonic-gate ipv6cp_close, /* Called when link has gone down */ 238*7c478bd9Sstevel@tonic-gate ipv6cp_printpkt, /* Print a packet in human readable form */ 239*7c478bd9Sstevel@tonic-gate NULL, /* Process a received data packet */ 240*7c478bd9Sstevel@tonic-gate 0, /* IPV6CP is disabled by default */ 241*7c478bd9Sstevel@tonic-gate "IPV6CP", /* Name of the protocol */ 242*7c478bd9Sstevel@tonic-gate "IPV6", /* Name of the corresponding data protocol */ 243*7c478bd9Sstevel@tonic-gate ipv6cp_option_list, /* List of IPV6CP command-line options */ 244*7c478bd9Sstevel@tonic-gate ipv6_check_options, /* Assigns default values for options */ 245*7c478bd9Sstevel@tonic-gate ipv6_demand_conf, /* Configures demand-dial */ 246*7c478bd9Sstevel@tonic-gate ipv6_active_pkt /* Bring up the link for this packet? */ 247*7c478bd9Sstevel@tonic-gate }; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * Local forward function declarations. 251*7c478bd9Sstevel@tonic-gate */ 252*7c478bd9Sstevel@tonic-gate static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t)); 253*7c478bd9Sstevel@tonic-gate static void ipv6cp_script __P((char *)); 254*7c478bd9Sstevel@tonic-gate static void ipv6cp_script_done __P((void *, int)); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * Lengths of configuration options. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate #define CILEN_VOID 2 260*7c478bd9Sstevel@tonic-gate #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ 261*7c478bd9Sstevel@tonic-gate #define CILEN_IFACEID 10 /* RFC2472, interface identifier */ 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate #define CODENAME(x) ((x) == CODE_CONFACK ? "ACK" : \ 264*7c478bd9Sstevel@tonic-gate (x) == CODE_CONFNAK ? "NAK" : "REJ") 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate /* 267*7c478bd9Sstevel@tonic-gate * This state variable is used to ensure that we don't 268*7c478bd9Sstevel@tonic-gate * run an ipcp-up/down script while one is already running. 269*7c478bd9Sstevel@tonic-gate */ 270*7c478bd9Sstevel@tonic-gate static enum script_state { 271*7c478bd9Sstevel@tonic-gate s_down, 272*7c478bd9Sstevel@tonic-gate s_up 273*7c478bd9Sstevel@tonic-gate } ipv6cp_script_state; 274*7c478bd9Sstevel@tonic-gate static pid_t ipv6cp_script_pid; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * setifaceid - set the interface identifiers manually 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 280*7c478bd9Sstevel@tonic-gate static int 281*7c478bd9Sstevel@tonic-gate setifaceid(argv, opt) 282*7c478bd9Sstevel@tonic-gate char **argv; 283*7c478bd9Sstevel@tonic-gate option_t *opt; 284*7c478bd9Sstevel@tonic-gate { 285*7c478bd9Sstevel@tonic-gate char *comma, *arg; 286*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 287*7c478bd9Sstevel@tonic-gate struct in6_addr addr; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ 290*7c478bd9Sstevel@tonic-gate (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate arg = *argv; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate comma = strchr(arg, ','); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate * If comma first character, then no local identifier 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate if (comma != arg) { 301*7c478bd9Sstevel@tonic-gate if (comma != NULL) 302*7c478bd9Sstevel@tonic-gate *comma = '\0'; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, arg, &addr) != 1 || !VALIDID(addr)) { 305*7c478bd9Sstevel@tonic-gate option_error("Illegal interface identifier (local): %s", arg); 306*7c478bd9Sstevel@tonic-gate return 0; 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate eui64_copy(addr.s6_addr32[2], wo->ourid); 310*7c478bd9Sstevel@tonic-gate wo->opt_local = 1; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * If comma last character, then no remote identifier 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate if (comma != NULL && *++comma != '\0') { 317*7c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, comma, &addr) != 1 || !VALIDID(addr)) { 318*7c478bd9Sstevel@tonic-gate option_error("Illegal interface identifier (remote): %s", comma); 319*7c478bd9Sstevel@tonic-gate return 0; 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate eui64_copy(addr.s6_addr32[2], wo->hisid); 322*7c478bd9Sstevel@tonic-gate wo->opt_remote = 1; 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate ipv6cp_protent.enabled_flag = 1; 326*7c478bd9Sstevel@tonic-gate return 1; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * Given an interface identifier, return a string representation of the 331*7c478bd9Sstevel@tonic-gate * link local address associated with that identifier. 332*7c478bd9Sstevel@tonic-gate * string will be at most 26 characters (including null terminator). 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate static char * 335*7c478bd9Sstevel@tonic-gate llv6_ntoa(ifaceid) 336*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 337*7c478bd9Sstevel@tonic-gate { 338*7c478bd9Sstevel@tonic-gate struct in6_addr addr; 339*7c478bd9Sstevel@tonic-gate static char addrstr[26]; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate BZERO(&addr, sizeof (addr)); 342*7c478bd9Sstevel@tonic-gate addr.s6_addr[0] = 0xfe; 343*7c478bd9Sstevel@tonic-gate addr.s6_addr[1] = 0x80; 344*7c478bd9Sstevel@tonic-gate eui64_copy(ifaceid, addr.s6_addr[8]); 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &addr, addrstr, 26); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate return addrstr; 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate /* 353*7c478bd9Sstevel@tonic-gate * ipv6cp_init - Initialize IPV6CP. 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate static void 356*7c478bd9Sstevel@tonic-gate ipv6cp_init(unit) 357*7c478bd9Sstevel@tonic-gate int unit; 358*7c478bd9Sstevel@tonic-gate { 359*7c478bd9Sstevel@tonic-gate fsm *f = &ipv6cp_fsm[unit]; 360*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[unit]; 361*7c478bd9Sstevel@tonic-gate ipv6cp_options *ao = &ipv6cp_allowoptions[unit]; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate f->unit = unit; 364*7c478bd9Sstevel@tonic-gate f->protocol = PPP_IPV6CP; 365*7c478bd9Sstevel@tonic-gate f->callbacks = &ipv6cp_callbacks; 366*7c478bd9Sstevel@tonic-gate fsm_init(&ipv6cp_fsm[unit]); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate BZERO(wo, sizeof(*wo)); 369*7c478bd9Sstevel@tonic-gate BZERO(ao, sizeof(*ao)); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate wo->neg_ifaceid = 1; 372*7c478bd9Sstevel@tonic-gate ao->neg_ifaceid = 1; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 375*7c478bd9Sstevel@tonic-gate wo->neg_vj = 1; 376*7c478bd9Sstevel@tonic-gate ao->neg_vj = 1; 377*7c478bd9Sstevel@tonic-gate wo->vj_protocol = IPV6CP_COMP; 378*7c478bd9Sstevel@tonic-gate #endif 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* 384*7c478bd9Sstevel@tonic-gate * ipv6cp_open - IPV6CP is allowed to come up. 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate static void 387*7c478bd9Sstevel@tonic-gate ipv6cp_open(unit) 388*7c478bd9Sstevel@tonic-gate int unit; 389*7c478bd9Sstevel@tonic-gate { 390*7c478bd9Sstevel@tonic-gate fsm_open(&ipv6cp_fsm[unit]); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * ipv6cp_close - Take IPV6CP down. 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate static void 398*7c478bd9Sstevel@tonic-gate ipv6cp_close(unit, reason) 399*7c478bd9Sstevel@tonic-gate int unit; 400*7c478bd9Sstevel@tonic-gate char *reason; 401*7c478bd9Sstevel@tonic-gate { 402*7c478bd9Sstevel@tonic-gate fsm_close(&ipv6cp_fsm[unit], reason); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * ipv6cp_lowerup - The lower layer is up. 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate static void 410*7c478bd9Sstevel@tonic-gate ipv6cp_lowerup(unit) 411*7c478bd9Sstevel@tonic-gate int unit; 412*7c478bd9Sstevel@tonic-gate { 413*7c478bd9Sstevel@tonic-gate fsm_lowerup(&ipv6cp_fsm[unit]); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * ipv6cp_lowerdown - The lower layer is down. 419*7c478bd9Sstevel@tonic-gate */ 420*7c478bd9Sstevel@tonic-gate static void 421*7c478bd9Sstevel@tonic-gate ipv6cp_lowerdown(unit) 422*7c478bd9Sstevel@tonic-gate int unit; 423*7c478bd9Sstevel@tonic-gate { 424*7c478bd9Sstevel@tonic-gate fsm_lowerdown(&ipv6cp_fsm[unit]); 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* 429*7c478bd9Sstevel@tonic-gate * ipv6cp_input - Input IPV6CP packet. 430*7c478bd9Sstevel@tonic-gate */ 431*7c478bd9Sstevel@tonic-gate static void 432*7c478bd9Sstevel@tonic-gate ipv6cp_input(unit, p, len) 433*7c478bd9Sstevel@tonic-gate int unit; 434*7c478bd9Sstevel@tonic-gate u_char *p; 435*7c478bd9Sstevel@tonic-gate int len; 436*7c478bd9Sstevel@tonic-gate { 437*7c478bd9Sstevel@tonic-gate fsm_input(&ipv6cp_fsm[unit], p, len); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate static void 445*7c478bd9Sstevel@tonic-gate ipv6cp_protrej(unit) 446*7c478bd9Sstevel@tonic-gate int unit; 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate fsm_protreject(&ipv6cp_fsm[unit]); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate /* 453*7c478bd9Sstevel@tonic-gate * ipv6cp_resetci - Reset our CI. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate static void 456*7c478bd9Sstevel@tonic-gate ipv6cp_resetci(f) 457*7c478bd9Sstevel@tonic-gate fsm *f; 458*7c478bd9Sstevel@tonic-gate { 459*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 460*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate if (!wo->opt_local) { 465*7c478bd9Sstevel@tonic-gate eui64_magic_nz(wo->ourid); 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate *go = *wo; 469*7c478bd9Sstevel@tonic-gate eui64_zero(go->hisid); /* last proposed interface identifier */ 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * ipv6cp_cilen - Return length of our CI. 475*7c478bd9Sstevel@tonic-gate */ 476*7c478bd9Sstevel@tonic-gate static int 477*7c478bd9Sstevel@tonic-gate ipv6cp_cilen(f) 478*7c478bd9Sstevel@tonic-gate fsm *f; 479*7c478bd9Sstevel@tonic-gate { 480*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) 483*7c478bd9Sstevel@tonic-gate #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate return (LENCIIFACEID(go->neg_ifaceid) + 486*7c478bd9Sstevel@tonic-gate LENCIVJ(go->neg_vj)); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * ipv6cp_addci - Add our desired CIs to a packet. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate static void 494*7c478bd9Sstevel@tonic-gate ipv6cp_addci(f, ucp, lenp) 495*7c478bd9Sstevel@tonic-gate fsm *f; 496*7c478bd9Sstevel@tonic-gate u_char *ucp; 497*7c478bd9Sstevel@tonic-gate int *lenp; 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 500*7c478bd9Sstevel@tonic-gate int len = *lenp; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate #define ADDCIVJ(opt, neg, val) \ 503*7c478bd9Sstevel@tonic-gate if (neg) { \ 504*7c478bd9Sstevel@tonic-gate int vjlen = CILEN_COMPRESS; \ 505*7c478bd9Sstevel@tonic-gate if (len >= vjlen) { \ 506*7c478bd9Sstevel@tonic-gate PUTCHAR(opt, ucp); \ 507*7c478bd9Sstevel@tonic-gate PUTCHAR(vjlen, ucp); \ 508*7c478bd9Sstevel@tonic-gate PUTSHORT(val, ucp); \ 509*7c478bd9Sstevel@tonic-gate len -= vjlen; \ 510*7c478bd9Sstevel@tonic-gate } else \ 511*7c478bd9Sstevel@tonic-gate neg = 0; \ 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate #define ADDCIIFACEID(opt, neg, val1) \ 515*7c478bd9Sstevel@tonic-gate if (neg) { \ 516*7c478bd9Sstevel@tonic-gate int idlen = CILEN_IFACEID; \ 517*7c478bd9Sstevel@tonic-gate if (len >= idlen) { \ 518*7c478bd9Sstevel@tonic-gate PUTCHAR(opt, ucp); \ 519*7c478bd9Sstevel@tonic-gate PUTCHAR(idlen, ucp); \ 520*7c478bd9Sstevel@tonic-gate eui64_put(val1, ucp); \ 521*7c478bd9Sstevel@tonic-gate len -= idlen; \ 522*7c478bd9Sstevel@tonic-gate } else \ 523*7c478bd9Sstevel@tonic-gate neg = 0; \ 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate *lenp -= len; 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate /* 535*7c478bd9Sstevel@tonic-gate * ipv6cp_ackci - Ack our CIs. 536*7c478bd9Sstevel@tonic-gate * 537*7c478bd9Sstevel@tonic-gate * Returns: 538*7c478bd9Sstevel@tonic-gate * 0 - Ack was bad. 539*7c478bd9Sstevel@tonic-gate * 1 - Ack was good. 540*7c478bd9Sstevel@tonic-gate */ 541*7c478bd9Sstevel@tonic-gate static int 542*7c478bd9Sstevel@tonic-gate ipv6cp_ackci(f, p, len) 543*7c478bd9Sstevel@tonic-gate fsm *f; 544*7c478bd9Sstevel@tonic-gate u_char *p; 545*7c478bd9Sstevel@tonic-gate int len; 546*7c478bd9Sstevel@tonic-gate { 547*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 548*7c478bd9Sstevel@tonic-gate u_short cilen, citype, cishort; 549*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * CIs must be in exactly the same order that we sent... 553*7c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 554*7c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate #define ACKCIVJ(opt, neg, val) \ 558*7c478bd9Sstevel@tonic-gate if (neg) { \ 559*7c478bd9Sstevel@tonic-gate int vjlen = CILEN_COMPRESS; \ 560*7c478bd9Sstevel@tonic-gate if ((len -= vjlen) < 0) \ 561*7c478bd9Sstevel@tonic-gate goto bad; \ 562*7c478bd9Sstevel@tonic-gate GETCHAR(citype, p); \ 563*7c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); \ 564*7c478bd9Sstevel@tonic-gate if (cilen != vjlen || \ 565*7c478bd9Sstevel@tonic-gate citype != opt) \ 566*7c478bd9Sstevel@tonic-gate goto bad; \ 567*7c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 568*7c478bd9Sstevel@tonic-gate if (cishort != val) \ 569*7c478bd9Sstevel@tonic-gate goto bad; \ 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate #define ACKCIIFACEID(opt, neg, val1) \ 573*7c478bd9Sstevel@tonic-gate if (neg) { \ 574*7c478bd9Sstevel@tonic-gate int idlen = CILEN_IFACEID; \ 575*7c478bd9Sstevel@tonic-gate if ((len -= idlen) < 0) \ 576*7c478bd9Sstevel@tonic-gate goto bad; \ 577*7c478bd9Sstevel@tonic-gate GETCHAR(citype, p); \ 578*7c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); \ 579*7c478bd9Sstevel@tonic-gate if (cilen != idlen || \ 580*7c478bd9Sstevel@tonic-gate citype != opt) \ 581*7c478bd9Sstevel@tonic-gate goto bad; \ 582*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 583*7c478bd9Sstevel@tonic-gate if (! eui64_equals(val1, ifaceid)) \ 584*7c478bd9Sstevel@tonic-gate goto bad; \ 585*7c478bd9Sstevel@tonic-gate } 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * If there are any remaining CIs, then this packet is bad. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate if (len != 0) 595*7c478bd9Sstevel@tonic-gate goto bad; 596*7c478bd9Sstevel@tonic-gate return (1); 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate bad: 599*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); 600*7c478bd9Sstevel@tonic-gate return (0); 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. 605*7c478bd9Sstevel@tonic-gate * This should not modify any state if the Nak is bad 606*7c478bd9Sstevel@tonic-gate * or if IPV6CP is in the OPENED state. 607*7c478bd9Sstevel@tonic-gate * 608*7c478bd9Sstevel@tonic-gate * Returns: 609*7c478bd9Sstevel@tonic-gate * 0 - Nak was bad. 610*7c478bd9Sstevel@tonic-gate * 1 - Nak was good. 611*7c478bd9Sstevel@tonic-gate */ 612*7c478bd9Sstevel@tonic-gate static int 613*7c478bd9Sstevel@tonic-gate ipv6cp_nakci(f, p, len) 614*7c478bd9Sstevel@tonic-gate fsm *f; 615*7c478bd9Sstevel@tonic-gate u_char *p; 616*7c478bd9Sstevel@tonic-gate int len; 617*7c478bd9Sstevel@tonic-gate { 618*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 619*7c478bd9Sstevel@tonic-gate u_char citype, cilen, *next; 620*7c478bd9Sstevel@tonic-gate u_short cishort; 621*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 622*7c478bd9Sstevel@tonic-gate ipv6cp_options no; /* options we've seen Naks for */ 623*7c478bd9Sstevel@tonic-gate ipv6cp_options try; /* options to request next time */ 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate BZERO(&no, sizeof(no)); 626*7c478bd9Sstevel@tonic-gate try = *go; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate /* 629*7c478bd9Sstevel@tonic-gate * Any Nak'd CIs must be in exactly the same order that we sent. 630*7c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 631*7c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 632*7c478bd9Sstevel@tonic-gate */ 633*7c478bd9Sstevel@tonic-gate #define NAKCIIFACEID(opt, neg, code) \ 634*7c478bd9Sstevel@tonic-gate if (go->neg && \ 635*7c478bd9Sstevel@tonic-gate len >= (cilen = CILEN_IFACEID) && \ 636*7c478bd9Sstevel@tonic-gate p[1] == cilen && \ 637*7c478bd9Sstevel@tonic-gate p[0] == opt) { \ 638*7c478bd9Sstevel@tonic-gate len -= cilen; \ 639*7c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 640*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 641*7c478bd9Sstevel@tonic-gate no.neg = 1; \ 642*7c478bd9Sstevel@tonic-gate code \ 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate #define NAKCIVJ(opt, neg, code) \ 646*7c478bd9Sstevel@tonic-gate if (go->neg && \ 647*7c478bd9Sstevel@tonic-gate ((cilen = p[1]) == CILEN_COMPRESS) && \ 648*7c478bd9Sstevel@tonic-gate len >= cilen && \ 649*7c478bd9Sstevel@tonic-gate p[0] == opt) { \ 650*7c478bd9Sstevel@tonic-gate len -= cilen; \ 651*7c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 652*7c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 653*7c478bd9Sstevel@tonic-gate no.neg = 1; \ 654*7c478bd9Sstevel@tonic-gate code \ 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate * Accept the peer's idea of {our,his} interface identifier, if different 659*7c478bd9Sstevel@tonic-gate * from our idea, only if the accept_{local,remote} flag is set. 660*7c478bd9Sstevel@tonic-gate */ 661*7c478bd9Sstevel@tonic-gate NAKCIIFACEID(CI_IFACEID, neg_ifaceid, 662*7c478bd9Sstevel@tonic-gate if (go->accept_local) { 663*7c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 664*7c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->hisid)) /* bad luck */ 665*7c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 666*7c478bd9Sstevel@tonic-gate try.ourid = ifaceid; 667*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate ); 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 672*7c478bd9Sstevel@tonic-gate NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 673*7c478bd9Sstevel@tonic-gate { 674*7c478bd9Sstevel@tonic-gate if (cishort == IPV6CP_COMP) { 675*7c478bd9Sstevel@tonic-gate try.vj_protocol = cishort; 676*7c478bd9Sstevel@tonic-gate } else { 677*7c478bd9Sstevel@tonic-gate try.neg_vj = 0; 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate ); 681*7c478bd9Sstevel@tonic-gate #else 682*7c478bd9Sstevel@tonic-gate NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 683*7c478bd9Sstevel@tonic-gate { 684*7c478bd9Sstevel@tonic-gate try.neg_vj = 0; 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate ); 687*7c478bd9Sstevel@tonic-gate #endif 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate /* 690*7c478bd9Sstevel@tonic-gate * There may be remaining CIs, if the peer is requesting negotiation 691*7c478bd9Sstevel@tonic-gate * on an option that we didn't include in our request packet. 692*7c478bd9Sstevel@tonic-gate * If they want to negotiate about interface identifier, we comply. 693*7c478bd9Sstevel@tonic-gate * If they want us to ask for compression, we refuse. 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate while (len > CILEN_VOID) { 696*7c478bd9Sstevel@tonic-gate GETCHAR(citype, p); 697*7c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); 698*7c478bd9Sstevel@tonic-gate if( (len -= cilen) < 0 ) 699*7c478bd9Sstevel@tonic-gate goto bad; 700*7c478bd9Sstevel@tonic-gate next = p + cilen - 2; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate switch (citype) { 703*7c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 704*7c478bd9Sstevel@tonic-gate if (go->neg_vj || no.neg_vj || 705*7c478bd9Sstevel@tonic-gate (cilen != CILEN_COMPRESS)) 706*7c478bd9Sstevel@tonic-gate goto bad; 707*7c478bd9Sstevel@tonic-gate no.neg_vj = 1; 708*7c478bd9Sstevel@tonic-gate break; 709*7c478bd9Sstevel@tonic-gate case CI_IFACEID: 710*7c478bd9Sstevel@tonic-gate if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) 711*7c478bd9Sstevel@tonic-gate goto bad; 712*7c478bd9Sstevel@tonic-gate try.neg_ifaceid = 1; 713*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 714*7c478bd9Sstevel@tonic-gate if (go->accept_local) { 715*7c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 716*7c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->hisid)) /* bad luck */ 717*7c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 718*7c478bd9Sstevel@tonic-gate try.ourid = ifaceid; 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate no.neg_ifaceid = 1; 721*7c478bd9Sstevel@tonic-gate break; 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate p = next; 724*7c478bd9Sstevel@tonic-gate } 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* If there is still anything left, this packet is bad. */ 727*7c478bd9Sstevel@tonic-gate if (len != 0) 728*7c478bd9Sstevel@tonic-gate goto bad; 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate /* 731*7c478bd9Sstevel@tonic-gate * OK, the Nak is good. Now we can update state. 732*7c478bd9Sstevel@tonic-gate */ 733*7c478bd9Sstevel@tonic-gate if (f->state != OPENED) 734*7c478bd9Sstevel@tonic-gate *go = try; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate return 1; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate bad: 739*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); 740*7c478bd9Sstevel@tonic-gate return 0; 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate /* 745*7c478bd9Sstevel@tonic-gate * ipv6cp_rejci - Reject some of our CIs. 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate static int 748*7c478bd9Sstevel@tonic-gate ipv6cp_rejci(f, p, len) 749*7c478bd9Sstevel@tonic-gate fsm *f; 750*7c478bd9Sstevel@tonic-gate u_char *p; 751*7c478bd9Sstevel@tonic-gate int len; 752*7c478bd9Sstevel@tonic-gate { 753*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 754*7c478bd9Sstevel@tonic-gate u_char cilen; 755*7c478bd9Sstevel@tonic-gate u_short cishort; 756*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 757*7c478bd9Sstevel@tonic-gate ipv6cp_options try; /* options to request next time */ 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate try = *go; 760*7c478bd9Sstevel@tonic-gate /* 761*7c478bd9Sstevel@tonic-gate * Any Rejected CIs must be in exactly the same order that we sent. 762*7c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 763*7c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate #define REJCIIFACEID(opt, neg, val1) \ 766*7c478bd9Sstevel@tonic-gate if (go->neg && \ 767*7c478bd9Sstevel@tonic-gate len >= (cilen = CILEN_IFACEID) && \ 768*7c478bd9Sstevel@tonic-gate p[1] == cilen && \ 769*7c478bd9Sstevel@tonic-gate p[0] == opt) { \ 770*7c478bd9Sstevel@tonic-gate len -= cilen; \ 771*7c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 772*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 773*7c478bd9Sstevel@tonic-gate /* Check rejected value. */ \ 774*7c478bd9Sstevel@tonic-gate if (! eui64_equals(ifaceid, val1)) \ 775*7c478bd9Sstevel@tonic-gate goto bad; \ 776*7c478bd9Sstevel@tonic-gate try.neg = 0; \ 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate #define REJCIVJ(opt, neg, val) \ 780*7c478bd9Sstevel@tonic-gate if (go->neg && \ 781*7c478bd9Sstevel@tonic-gate p[1] == CILEN_COMPRESS && \ 782*7c478bd9Sstevel@tonic-gate len >= p[1] && \ 783*7c478bd9Sstevel@tonic-gate p[0] == opt) { \ 784*7c478bd9Sstevel@tonic-gate len -= p[1]; \ 785*7c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 786*7c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 787*7c478bd9Sstevel@tonic-gate /* Check rejected value. */ \ 788*7c478bd9Sstevel@tonic-gate if (cishort != val) \ 789*7c478bd9Sstevel@tonic-gate goto bad; \ 790*7c478bd9Sstevel@tonic-gate try.neg = 0; \ 791*7c478bd9Sstevel@tonic-gate } 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate /* 798*7c478bd9Sstevel@tonic-gate * If there are any remaining CIs, then this packet is bad. 799*7c478bd9Sstevel@tonic-gate */ 800*7c478bd9Sstevel@tonic-gate if (len != 0) 801*7c478bd9Sstevel@tonic-gate goto bad; 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * Now we can update state. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate if (f->state != OPENED) 806*7c478bd9Sstevel@tonic-gate *go = try; 807*7c478bd9Sstevel@tonic-gate return 1; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate bad: 810*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); 811*7c478bd9Sstevel@tonic-gate return 0; 812*7c478bd9Sstevel@tonic-gate } 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate /* 816*7c478bd9Sstevel@tonic-gate * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. 817*7c478bd9Sstevel@tonic-gate * 818*7c478bd9Sstevel@tonic-gate * Returns: CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and input packet modified 819*7c478bd9Sstevel@tonic-gate * appropriately. If reject_if_disagree is non-zero, doesn't return 820*7c478bd9Sstevel@tonic-gate * CODE_CONFNAK; returns CODE_CONFREJ if it can't return CODE_CONFACK. 821*7c478bd9Sstevel@tonic-gate */ 822*7c478bd9Sstevel@tonic-gate static int 823*7c478bd9Sstevel@tonic-gate ipv6cp_reqci(f, p, lenp, dont_nak) 824*7c478bd9Sstevel@tonic-gate fsm *f; 825*7c478bd9Sstevel@tonic-gate u_char *p; /* Requested CIs */ 826*7c478bd9Sstevel@tonic-gate int *lenp; /* Length of requested CIs */ 827*7c478bd9Sstevel@tonic-gate int dont_nak; 828*7c478bd9Sstevel@tonic-gate { 829*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 830*7c478bd9Sstevel@tonic-gate ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 831*7c478bd9Sstevel@tonic-gate ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit]; 832*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 833*7c478bd9Sstevel@tonic-gate u_char *p0, *nakp, *rejp, *prev; 834*7c478bd9Sstevel@tonic-gate int ret, newret; 835*7c478bd9Sstevel@tonic-gate int len, cilen, type; 836*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 837*7c478bd9Sstevel@tonic-gate u_short cishort; 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate ret = CODE_CONFACK; 840*7c478bd9Sstevel@tonic-gate rejp = p0 = p; 841*7c478bd9Sstevel@tonic-gate nakp = nak_buffer; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * Reset all his options. 845*7c478bd9Sstevel@tonic-gate */ 846*7c478bd9Sstevel@tonic-gate BZERO(ho, sizeof(*ho)); 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * Process all his options. 850*7c478bd9Sstevel@tonic-gate */ 851*7c478bd9Sstevel@tonic-gate for (len = *lenp; len > 0; len -= cilen, p = prev + cilen) { 852*7c478bd9Sstevel@tonic-gate newret = CODE_CONFACK; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate if ((len < 2) || p[1] > len) { 855*7c478bd9Sstevel@tonic-gate /* 856*7c478bd9Sstevel@tonic-gate * RFC 1661 page 40 -- if the option extends beyond the 857*7c478bd9Sstevel@tonic-gate * packet, then discard the entire packet. 858*7c478bd9Sstevel@tonic-gate */ 859*7c478bd9Sstevel@tonic-gate return (0); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate prev = p; 863*7c478bd9Sstevel@tonic-gate GETCHAR(type, p); 864*7c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate switch (type) { /* Check CI type */ 867*7c478bd9Sstevel@tonic-gate case CI_IFACEID: 868*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: received interface identifier ")); 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate if (!ao->neg_ifaceid) { 871*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 872*7c478bd9Sstevel@tonic-gate break; 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if (cilen != CILEN_IFACEID) { 876*7c478bd9Sstevel@tonic-gate /* 877*7c478bd9Sstevel@tonic-gate * rfc1661, page 40 -- a recongnized option with an 878*7c478bd9Sstevel@tonic-gate * invalid length should be Nak'ed. 879*7c478bd9Sstevel@tonic-gate */ 880*7c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 881*7c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 882*7c478bd9Sstevel@tonic-gate } else { 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate /* 885*7c478bd9Sstevel@tonic-gate * If he has no interface identifier, or if we both 886*7c478bd9Sstevel@tonic-gate * have same identifier then NAK it with new idea. In 887*7c478bd9Sstevel@tonic-gate * particular, if we don't know his identifier, but he 888*7c478bd9Sstevel@tonic-gate * does, then accept it. 889*7c478bd9Sstevel@tonic-gate */ 890*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 891*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); 892*7c478bd9Sstevel@tonic-gate if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { 893*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; /* Reject CI */ 894*7c478bd9Sstevel@tonic-gate break; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate /* If we don't like his ID, then nak it. */ 897*7c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->hisid) && 898*7c478bd9Sstevel@tonic-gate !eui64_equals(ifaceid, wo->hisid) && 899*7c478bd9Sstevel@tonic-gate eui64_iszero(go->hisid)) { 900*7c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 901*7c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 902*7c478bd9Sstevel@tonic-gate } else if (eui64_iszero(ifaceid) || 903*7c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->ourid)) { 904*7c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 905*7c478bd9Sstevel@tonic-gate /* first time, try option */ 906*7c478bd9Sstevel@tonic-gate if (eui64_iszero(go->hisid)) 907*7c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 908*7c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 909*7c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->ourid)) /* bad luck */ 910*7c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate if (newret == CODE_CONFNAK) { 914*7c478bd9Sstevel@tonic-gate PUTCHAR(type, nakp); 915*7c478bd9Sstevel@tonic-gate PUTCHAR(CILEN_IFACEID, nakp); 916*7c478bd9Sstevel@tonic-gate eui64_put(ifaceid, nakp); 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate ho->neg_ifaceid = 1; 920*7c478bd9Sstevel@tonic-gate eui64_copy(ifaceid, ho->hisid); 921*7c478bd9Sstevel@tonic-gate break; 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 924*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate if (!ao->neg_vj) { 927*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 928*7c478bd9Sstevel@tonic-gate break; 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate if (cilen != CILEN_COMPRESS) { 932*7c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 933*7c478bd9Sstevel@tonic-gate cishort = ao->vj_protocol; 934*7c478bd9Sstevel@tonic-gate } else { 935*7c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); 936*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("(%d)", cishort)); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 939*7c478bd9Sstevel@tonic-gate if (cishort != IPV6CP_COMP) { 940*7c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 941*7c478bd9Sstevel@tonic-gate cishort = IPV6CP_COMP; 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate #else 944*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 945*7c478bd9Sstevel@tonic-gate break; 946*7c478bd9Sstevel@tonic-gate #endif 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate ho->neg_vj = 1; 950*7c478bd9Sstevel@tonic-gate ho->vj_protocol = cishort; 951*7c478bd9Sstevel@tonic-gate break; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate default: 954*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 955*7c478bd9Sstevel@tonic-gate break; 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG((" (%s)\n", CODENAME(newret))); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate /* Cope with confused peers. */ 961*7c478bd9Sstevel@tonic-gate if (cilen < 2) 962*7c478bd9Sstevel@tonic-gate cilen = 2; 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate /* 965*7c478bd9Sstevel@tonic-gate * If this is an Ack'able CI, but we're sending back a Nak, 966*7c478bd9Sstevel@tonic-gate * don't include this CI. 967*7c478bd9Sstevel@tonic-gate */ 968*7c478bd9Sstevel@tonic-gate if (newret == CODE_CONFACK && ret != CODE_CONFACK) 969*7c478bd9Sstevel@tonic-gate continue; 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate if (newret == CODE_CONFNAK) { 972*7c478bd9Sstevel@tonic-gate if (dont_nak) { 973*7c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 974*7c478bd9Sstevel@tonic-gate } else { 975*7c478bd9Sstevel@tonic-gate /* Ignore subsequent Nak'able things if rejecting. */ 976*7c478bd9Sstevel@tonic-gate if (ret == CODE_CONFREJ) 977*7c478bd9Sstevel@tonic-gate continue; 978*7c478bd9Sstevel@tonic-gate ret = CODE_CONFNAK; 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate } 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate if (newret == CODE_CONFREJ) { 983*7c478bd9Sstevel@tonic-gate ret = CODE_CONFREJ; 984*7c478bd9Sstevel@tonic-gate if (prev != rejp) 985*7c478bd9Sstevel@tonic-gate (void) BCOPY(prev, rejp, cilen); 986*7c478bd9Sstevel@tonic-gate rejp += cilen; 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* 991*7c478bd9Sstevel@tonic-gate * If we aren't rejecting this packet, and we want to negotiate 992*7c478bd9Sstevel@tonic-gate * their identifier and they didn't send their identifier, then we 993*7c478bd9Sstevel@tonic-gate * send a NAK with a CI_IFACEID option appended. We assume the 994*7c478bd9Sstevel@tonic-gate * input buffer is long enough that we can append the extra 995*7c478bd9Sstevel@tonic-gate * option safely. 996*7c478bd9Sstevel@tonic-gate */ 997*7c478bd9Sstevel@tonic-gate if (ret != CODE_CONFREJ && !ho->neg_ifaceid && 998*7c478bd9Sstevel@tonic-gate wo->req_ifaceid && !dont_nak) { 999*7c478bd9Sstevel@tonic-gate if (ret == CODE_CONFACK) 1000*7c478bd9Sstevel@tonic-gate wo->req_ifaceid = 0; 1001*7c478bd9Sstevel@tonic-gate ret = CODE_CONFNAK; 1002*7c478bd9Sstevel@tonic-gate PUTCHAR(CI_IFACEID, nakp); 1003*7c478bd9Sstevel@tonic-gate PUTCHAR(CILEN_IFACEID, nakp); 1004*7c478bd9Sstevel@tonic-gate eui64_put(wo->hisid, nakp); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate switch (ret) { 1008*7c478bd9Sstevel@tonic-gate case CODE_CONFACK: 1009*7c478bd9Sstevel@tonic-gate *lenp = p - p0; 1010*7c478bd9Sstevel@tonic-gate sys_block_proto(PPP_IPV6); 1011*7c478bd9Sstevel@tonic-gate break; 1012*7c478bd9Sstevel@tonic-gate case CODE_CONFNAK: 1013*7c478bd9Sstevel@tonic-gate *lenp = nakp - nak_buffer; 1014*7c478bd9Sstevel@tonic-gate (void) BCOPY(nak_buffer, p0, *lenp); 1015*7c478bd9Sstevel@tonic-gate break; 1016*7c478bd9Sstevel@tonic-gate case CODE_CONFREJ: 1017*7c478bd9Sstevel@tonic-gate *lenp = rejp - p0; 1018*7c478bd9Sstevel@tonic-gate break; 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(ret))); 1022*7c478bd9Sstevel@tonic-gate return (ret); /* Return final code */ 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate /* 1027*7c478bd9Sstevel@tonic-gate * ipv6_check_options - check that any IP-related options are OK, 1028*7c478bd9Sstevel@tonic-gate * and assign appropriate defaults. 1029*7c478bd9Sstevel@tonic-gate */ 1030*7c478bd9Sstevel@tonic-gate static void 1031*7c478bd9Sstevel@tonic-gate ipv6_check_options() 1032*7c478bd9Sstevel@tonic-gate { 1033*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate #if defined(SOL2) 1036*7c478bd9Sstevel@tonic-gate /* 1037*7c478bd9Sstevel@tonic-gate * Persistent link-local id is only used when user has not explicitly 1038*7c478bd9Sstevel@tonic-gate * configure/hard-code the id 1039*7c478bd9Sstevel@tonic-gate */ 1040*7c478bd9Sstevel@tonic-gate if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate /* 1043*7c478bd9Sstevel@tonic-gate * On systems where there are no Ethernet interfaces used, there 1044*7c478bd9Sstevel@tonic-gate * may be other ways to obtain a persistent id. Right now, it 1045*7c478bd9Sstevel@tonic-gate * will fall back to using magic [see eui64_magic] below when 1046*7c478bd9Sstevel@tonic-gate * an EUI-48 from MAC address can't be obtained. Other possibilities 1047*7c478bd9Sstevel@tonic-gate * include obtaining EEPROM serial numbers, or some other unique 1048*7c478bd9Sstevel@tonic-gate * yet persistent number. On Sparc platforms, this is possible, 1049*7c478bd9Sstevel@tonic-gate * but too bad there's no standards yet for x86 machines. 1050*7c478bd9Sstevel@tonic-gate */ 1051*7c478bd9Sstevel@tonic-gate if (ether_to_eui64(&wo->ourid)) { 1052*7c478bd9Sstevel@tonic-gate wo->opt_local = 1; 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate #endif 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* 1058*7c478bd9Sstevel@tonic-gate * If ipv6cp-use-ipaddr is used, then both local and remote IPv4 1059*7c478bd9Sstevel@tonic-gate * addresses should be specified as options. Otherwise, since 1060*7c478bd9Sstevel@tonic-gate * ipcp has yet to negotiate the IPv4 addresses, the interface 1061*7c478bd9Sstevel@tonic-gate * identifiers will be based on meaningless values. 1062*7c478bd9Sstevel@tonic-gate */ 1063*7c478bd9Sstevel@tonic-gate if (wo->use_ip) { 1064*7c478bd9Sstevel@tonic-gate if ((ipcp_wantoptions[0].accept_local || 1065*7c478bd9Sstevel@tonic-gate ipcp_wantoptions[0].ouraddr == 0) && eui64_iszero(wo->ourid)) { 1066*7c478bd9Sstevel@tonic-gate warn("either IPv4 or IPv6 local address should be non-zero for ipv6cp-use-ipaddr"); 1067*7c478bd9Sstevel@tonic-gate } 1068*7c478bd9Sstevel@tonic-gate if ((ipcp_wantoptions[0].accept_remote || 1069*7c478bd9Sstevel@tonic-gate ipcp_wantoptions[0].hisaddr == 0) && eui64_iszero(wo->hisid)) { 1070*7c478bd9Sstevel@tonic-gate warn("either IPv4 or IPv6 remote address should be non-zero for ipv6cp-use-ipaddr"); 1071*7c478bd9Sstevel@tonic-gate } 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate if (!wo->opt_local) { /* init interface identifier */ 1075*7c478bd9Sstevel@tonic-gate if (wo->use_ip && eui64_iszero(wo->ourid)) { 1076*7c478bd9Sstevel@tonic-gate eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); 1077*7c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->ourid)) 1078*7c478bd9Sstevel@tonic-gate wo->opt_local = 1; 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate while (eui64_iszero(wo->ourid)) 1082*7c478bd9Sstevel@tonic-gate eui64_magic(wo->ourid); 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate if (!wo->opt_remote) { 1086*7c478bd9Sstevel@tonic-gate if (wo->use_ip && eui64_iszero(wo->hisid)) { 1087*7c478bd9Sstevel@tonic-gate eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); 1088*7c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->hisid)) 1089*7c478bd9Sstevel@tonic-gate wo->opt_remote = 1; 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate } 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { 1094*7c478bd9Sstevel@tonic-gate fatal("local/remote LL address required for demand-dialling\n"); 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate /* 1100*7c478bd9Sstevel@tonic-gate * ipv6_demand_conf - configure the interface as though 1101*7c478bd9Sstevel@tonic-gate * IPV6CP were up, for use with dial-on-demand. 1102*7c478bd9Sstevel@tonic-gate */ 1103*7c478bd9Sstevel@tonic-gate static int 1104*7c478bd9Sstevel@tonic-gate ipv6_demand_conf(u) 1105*7c478bd9Sstevel@tonic-gate int u; 1106*7c478bd9Sstevel@tonic-gate { 1107*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[u]; 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate #if SIF6UPFIRST 1110*7c478bd9Sstevel@tonic-gate if (!sif6up(u)) 1111*7c478bd9Sstevel@tonic-gate return 0; 1112*7c478bd9Sstevel@tonic-gate #endif 1113*7c478bd9Sstevel@tonic-gate if (!sif6addr(u, wo->ourid, wo->hisid)) 1114*7c478bd9Sstevel@tonic-gate return 0; 1115*7c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST 1116*7c478bd9Sstevel@tonic-gate if (!sif6up(u)) 1117*7c478bd9Sstevel@tonic-gate return 0; 1118*7c478bd9Sstevel@tonic-gate #endif 1119*7c478bd9Sstevel@tonic-gate if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) 1120*7c478bd9Sstevel@tonic-gate return 0; 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate notice("ipv6_demand_conf"); 1123*7c478bd9Sstevel@tonic-gate notice("local LL address %s", llv6_ntoa(wo->ourid)); 1124*7c478bd9Sstevel@tonic-gate notice("remote LL address %s", llv6_ntoa(wo->hisid)); 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate return 1; 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate /* 1131*7c478bd9Sstevel@tonic-gate * ipv6cp_up - IPV6CP has come UP. 1132*7c478bd9Sstevel@tonic-gate * 1133*7c478bd9Sstevel@tonic-gate * Configure the IPv6 network interface appropriately and bring it up. 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate static void 1136*7c478bd9Sstevel@tonic-gate ipv6cp_up(f) 1137*7c478bd9Sstevel@tonic-gate fsm *f; 1138*7c478bd9Sstevel@tonic-gate { 1139*7c478bd9Sstevel@tonic-gate ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 1140*7c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 1141*7c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: up")); 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate /* 1146*7c478bd9Sstevel@tonic-gate * We must have a non-zero LL address for both ends of the link. 1147*7c478bd9Sstevel@tonic-gate */ 1148*7c478bd9Sstevel@tonic-gate if (!ho->neg_ifaceid) 1149*7c478bd9Sstevel@tonic-gate ho->hisid = wo->hisid; 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate if(!no_ifaceid_neg) { 1152*7c478bd9Sstevel@tonic-gate if (eui64_iszero(ho->hisid)) { 1153*7c478bd9Sstevel@tonic-gate error("Could not determine remote LL address"); 1154*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not determine remote LL address"); 1155*7c478bd9Sstevel@tonic-gate return; 1156*7c478bd9Sstevel@tonic-gate } 1157*7c478bd9Sstevel@tonic-gate if (eui64_iszero(go->ourid)) { 1158*7c478bd9Sstevel@tonic-gate error("Could not determine local LL address"); 1159*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not determine local LL address"); 1160*7c478bd9Sstevel@tonic-gate return; 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate if (eui64_equals(go->ourid, ho->hisid)) { 1163*7c478bd9Sstevel@tonic-gate error("local and remote LL addresses are equal"); 1164*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "local and remote LL addresses are equal"); 1165*7c478bd9Sstevel@tonic-gate return; 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 1170*7c478bd9Sstevel@tonic-gate /* set tcp compression */ 1171*7c478bd9Sstevel@tonic-gate if (sif6comp(f->unit, ho->neg_vj) != 1) { 1172*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not enable TCP compression"); 1173*7c478bd9Sstevel@tonic-gate return; 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate #endif 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate /* 1178*7c478bd9Sstevel@tonic-gate * If we are doing dial-on-demand, the interface is already 1179*7c478bd9Sstevel@tonic-gate * configured, so we put out any saved-up packets, then set the 1180*7c478bd9Sstevel@tonic-gate * interface to pass IPv6 packets. 1181*7c478bd9Sstevel@tonic-gate */ 1182*7c478bd9Sstevel@tonic-gate if (demand) { 1183*7c478bd9Sstevel@tonic-gate if (! eui64_equals(go->ourid, wo->ourid) || 1184*7c478bd9Sstevel@tonic-gate ! eui64_equals(ho->hisid, wo->hisid)) { 1185*7c478bd9Sstevel@tonic-gate if (! eui64_equals(go->ourid, wo->ourid)) 1186*7c478bd9Sstevel@tonic-gate warn("Local LL address changed to %s", 1187*7c478bd9Sstevel@tonic-gate llv6_ntoa(go->ourid)); 1188*7c478bd9Sstevel@tonic-gate if (! eui64_equals(ho->hisid, wo->hisid)) 1189*7c478bd9Sstevel@tonic-gate warn("Remote LL address changed to %s", 1190*7c478bd9Sstevel@tonic-gate llv6_ntoa(ho->hisid)); 1191*7c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid); 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate /* Set the interface to the new addresses */ 1194*7c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 1195*7c478bd9Sstevel@tonic-gate if (debug) 1196*7c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 1197*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1198*7c478bd9Sstevel@tonic-gate return; 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate demand_rexmit(PPP_IPV6); 1203*7c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) { 1204*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1205*7c478bd9Sstevel@tonic-gate return; 1206*7c478bd9Sstevel@tonic-gate } 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate } else { 1209*7c478bd9Sstevel@tonic-gate /* 1210*7c478bd9Sstevel@tonic-gate * Set LL addresses 1211*7c478bd9Sstevel@tonic-gate */ 1212*7c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST 1213*7c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 1214*7c478bd9Sstevel@tonic-gate if (debug) 1215*7c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 1216*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1217*7c478bd9Sstevel@tonic-gate return; 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate #endif 1220*7c478bd9Sstevel@tonic-gate #if defined(SOL2) 1221*7c478bd9Sstevel@tonic-gate /* bring the interface up for IPv6 */ 1222*7c478bd9Sstevel@tonic-gate if (!sif6up(f->unit)) { 1223*7c478bd9Sstevel@tonic-gate if (debug) 1224*7c478bd9Sstevel@tonic-gate warn("sifup failed (IPV6)"); 1225*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1226*7c478bd9Sstevel@tonic-gate return; 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate #else 1229*7c478bd9Sstevel@tonic-gate if (!sifup(f->unit)) { 1230*7c478bd9Sstevel@tonic-gate if (debug) 1231*7c478bd9Sstevel@tonic-gate warn("sifup failed (IPV6)"); 1232*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1233*7c478bd9Sstevel@tonic-gate return; 1234*7c478bd9Sstevel@tonic-gate } 1235*7c478bd9Sstevel@tonic-gate #endif 1236*7c478bd9Sstevel@tonic-gate #if SIF6UPFIRST 1237*7c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 1238*7c478bd9Sstevel@tonic-gate if (debug) 1239*7c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 1240*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1241*7c478bd9Sstevel@tonic-gate return; 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate #endif 1244*7c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) { 1245*7c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 1246*7c478bd9Sstevel@tonic-gate return; 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate notice("local LL address %s", llv6_ntoa(go->ourid)); 1250*7c478bd9Sstevel@tonic-gate notice("remote LL address %s", llv6_ntoa(ho->hisid)); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate np_up(f->unit, PPP_IPV6); 1254*7c478bd9Sstevel@tonic-gate ipv6cp_is_up = 1; 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate /* 1257*7c478bd9Sstevel@tonic-gate * Execute the ipv6-up script, like this: 1258*7c478bd9Sstevel@tonic-gate * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); 1261*7c478bd9Sstevel@tonic-gate script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); 1262*7c478bd9Sstevel@tonic-gate if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { 1263*7c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_up; 1264*7c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6UP); 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate sys_unblock_proto(PPP_IPV6); 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate /* 1271*7c478bd9Sstevel@tonic-gate * ipv6cp_down - IPV6CP has gone DOWN. 1272*7c478bd9Sstevel@tonic-gate * 1273*7c478bd9Sstevel@tonic-gate * Take the IPv6 network interface down, clear its addresses 1274*7c478bd9Sstevel@tonic-gate * and delete routes through it. 1275*7c478bd9Sstevel@tonic-gate */ 1276*7c478bd9Sstevel@tonic-gate static void 1277*7c478bd9Sstevel@tonic-gate ipv6cp_down(f) 1278*7c478bd9Sstevel@tonic-gate fsm *f; 1279*7c478bd9Sstevel@tonic-gate { 1280*7c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: down")); 1281*7c478bd9Sstevel@tonic-gate update_link_stats(f->unit); 1282*7c478bd9Sstevel@tonic-gate if (ipv6cp_is_up) { 1283*7c478bd9Sstevel@tonic-gate ipv6cp_is_up = 0; 1284*7c478bd9Sstevel@tonic-gate np_down(f->unit, PPP_IPV6); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 1287*7c478bd9Sstevel@tonic-gate if (sif6comp(f->unit, 0) != 1) { 1288*7c478bd9Sstevel@tonic-gate if (debug) 1289*7c478bd9Sstevel@tonic-gate warn("Failed to disable TCP compression."); 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate #endif 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /* 1294*7c478bd9Sstevel@tonic-gate * If we are doing dial-on-demand, set the interface 1295*7c478bd9Sstevel@tonic-gate * to queue up outgoing packets (for now). 1296*7c478bd9Sstevel@tonic-gate */ 1297*7c478bd9Sstevel@tonic-gate if (demand) { 1298*7c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE) != 1) { 1299*7c478bd9Sstevel@tonic-gate if (debug) 1300*7c478bd9Sstevel@tonic-gate warn("Failed to enable queueing on outgoing packets."); 1301*7c478bd9Sstevel@tonic-gate } 1302*7c478bd9Sstevel@tonic-gate } else { 1303*7c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_ERROR) != 1) { 1304*7c478bd9Sstevel@tonic-gate if (debug) 1305*7c478bd9Sstevel@tonic-gate warn("Could not set interface to drop packets."); 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC))) 1308*7c478bd9Sstevel@tonic-gate #if defined(SOL2) 1309*7c478bd9Sstevel@tonic-gate if (sif6down(f->unit) != 1) 1310*7c478bd9Sstevel@tonic-gate warn("Couldn not bring interface down."); 1311*7c478bd9Sstevel@tonic-gate #else 1312*7c478bd9Sstevel@tonic-gate if (sifdown(f->unit) != 1) 1313*7c478bd9Sstevel@tonic-gate warn("Could not bring interface down."); 1314*7c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */ 1315*7c478bd9Sstevel@tonic-gate #endif 1316*7c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(f->unit, 1317*7c478bd9Sstevel@tonic-gate ipv6cp_gotoptions[f->unit].ourid, 1318*7c478bd9Sstevel@tonic-gate ipv6cp_hisoptions[f->unit].hisid); 1319*7c478bd9Sstevel@tonic-gate #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC))) 1320*7c478bd9Sstevel@tonic-gate if (sifdown(f->unit) != 1) 1321*7c478bd9Sstevel@tonic-gate warn("Could not bring interface down."); 1322*7c478bd9Sstevel@tonic-gate #endif 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate 1325*7c478bd9Sstevel@tonic-gate /* Execute the ipv6-down script */ 1326*7c478bd9Sstevel@tonic-gate if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { 1327*7c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_down; 1328*7c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6DOWN); 1329*7c478bd9Sstevel@tonic-gate } 1330*7c478bd9Sstevel@tonic-gate } 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate /* 1334*7c478bd9Sstevel@tonic-gate * ipv6cp_clear_addrs() - clear the interface addresses, routes, 1335*7c478bd9Sstevel@tonic-gate * proxy neighbour discovery entries, etc. 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate static void 1338*7c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(unit, ourid, hisid) 1339*7c478bd9Sstevel@tonic-gate int unit; 1340*7c478bd9Sstevel@tonic-gate eui64_t ourid; 1341*7c478bd9Sstevel@tonic-gate eui64_t hisid; 1342*7c478bd9Sstevel@tonic-gate { 1343*7c478bd9Sstevel@tonic-gate if (cif6addr(unit, ourid, hisid) != 1) 1344*7c478bd9Sstevel@tonic-gate warn("Could not clear addresses"); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate /* 1349*7c478bd9Sstevel@tonic-gate * ipv6cp_finished - possibly shut down the lower layers. 1350*7c478bd9Sstevel@tonic-gate */ 1351*7c478bd9Sstevel@tonic-gate static void 1352*7c478bd9Sstevel@tonic-gate ipv6cp_finished(f) 1353*7c478bd9Sstevel@tonic-gate fsm *f; 1354*7c478bd9Sstevel@tonic-gate { 1355*7c478bd9Sstevel@tonic-gate np_finished(f->unit, PPP_IPV6); 1356*7c478bd9Sstevel@tonic-gate } 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate /* 1360*7c478bd9Sstevel@tonic-gate * ipv6cp_script_done - called when the ipv6-up or ipv6-down script 1361*7c478bd9Sstevel@tonic-gate * has finished. 1362*7c478bd9Sstevel@tonic-gate */ 1363*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1364*7c478bd9Sstevel@tonic-gate static void 1365*7c478bd9Sstevel@tonic-gate ipv6cp_script_done(arg, status) 1366*7c478bd9Sstevel@tonic-gate void *arg; 1367*7c478bd9Sstevel@tonic-gate int status; 1368*7c478bd9Sstevel@tonic-gate { 1369*7c478bd9Sstevel@tonic-gate ipv6cp_script_pid = 0; 1370*7c478bd9Sstevel@tonic-gate switch (ipv6cp_script_state) { 1371*7c478bd9Sstevel@tonic-gate case s_up: 1372*7c478bd9Sstevel@tonic-gate if (ipv6cp_fsm[0].state != OPENED) { 1373*7c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_down; 1374*7c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6DOWN); 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate break; 1377*7c478bd9Sstevel@tonic-gate case s_down: 1378*7c478bd9Sstevel@tonic-gate if (ipv6cp_fsm[0].state == OPENED) { 1379*7c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_up; 1380*7c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6UP); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate break; 1383*7c478bd9Sstevel@tonic-gate } 1384*7c478bd9Sstevel@tonic-gate } 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate 1387*7c478bd9Sstevel@tonic-gate /* 1388*7c478bd9Sstevel@tonic-gate * ipv6cp_script - Execute a script with arguments 1389*7c478bd9Sstevel@tonic-gate * interface-name tty-name speed local-LL remote-LL. 1390*7c478bd9Sstevel@tonic-gate */ 1391*7c478bd9Sstevel@tonic-gate static void 1392*7c478bd9Sstevel@tonic-gate ipv6cp_script(script) 1393*7c478bd9Sstevel@tonic-gate char *script; 1394*7c478bd9Sstevel@tonic-gate { 1395*7c478bd9Sstevel@tonic-gate char strspeed[32], strlocal[26], strremote[26]; 1396*7c478bd9Sstevel@tonic-gate char *argv[8]; 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate (void) slprintf(strspeed, sizeof (strspeed), "%d", baud_rate); 1399*7c478bd9Sstevel@tonic-gate (void) strlcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid), 1400*7c478bd9Sstevel@tonic-gate sizeof (strlocal)); 1401*7c478bd9Sstevel@tonic-gate (void) strlcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid), 1402*7c478bd9Sstevel@tonic-gate sizeof (strremote)); 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate argv[0] = script; 1405*7c478bd9Sstevel@tonic-gate argv[1] = ifname; 1406*7c478bd9Sstevel@tonic-gate argv[2] = devnam; 1407*7c478bd9Sstevel@tonic-gate argv[3] = strspeed; 1408*7c478bd9Sstevel@tonic-gate argv[4] = strlocal; 1409*7c478bd9Sstevel@tonic-gate argv[5] = strremote; 1410*7c478bd9Sstevel@tonic-gate argv[6] = ipparam; 1411*7c478bd9Sstevel@tonic-gate argv[7] = NULL; 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL); 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate static int 1417*7c478bd9Sstevel@tonic-gate ipv6cp_printpkt(p, plen, printer, arg) 1418*7c478bd9Sstevel@tonic-gate u_char *p; 1419*7c478bd9Sstevel@tonic-gate int plen; 1420*7c478bd9Sstevel@tonic-gate void (*printer) __P((void *, const char *, ...)); 1421*7c478bd9Sstevel@tonic-gate void *arg; 1422*7c478bd9Sstevel@tonic-gate { 1423*7c478bd9Sstevel@tonic-gate int code, id, len, olen; 1424*7c478bd9Sstevel@tonic-gate u_char *pstart, *optend; 1425*7c478bd9Sstevel@tonic-gate u_short cishort; 1426*7c478bd9Sstevel@tonic-gate eui64_t ifaceid; 1427*7c478bd9Sstevel@tonic-gate 1428*7c478bd9Sstevel@tonic-gate if (plen < HEADERLEN) 1429*7c478bd9Sstevel@tonic-gate return 0; 1430*7c478bd9Sstevel@tonic-gate pstart = p; 1431*7c478bd9Sstevel@tonic-gate GETCHAR(code, p); 1432*7c478bd9Sstevel@tonic-gate GETCHAR(id, p); 1433*7c478bd9Sstevel@tonic-gate GETSHORT(len, p); 1434*7c478bd9Sstevel@tonic-gate if (len < HEADERLEN || len > plen) 1435*7c478bd9Sstevel@tonic-gate return 0; 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate printer(arg, " %s id=0x%x", code_name(code, 1), id); 1439*7c478bd9Sstevel@tonic-gate len -= HEADERLEN; 1440*7c478bd9Sstevel@tonic-gate switch (code) { 1441*7c478bd9Sstevel@tonic-gate case CODE_CONFREQ: 1442*7c478bd9Sstevel@tonic-gate case CODE_CONFACK: 1443*7c478bd9Sstevel@tonic-gate case CODE_CONFNAK: 1444*7c478bd9Sstevel@tonic-gate case CODE_CONFREJ: 1445*7c478bd9Sstevel@tonic-gate /* print option list */ 1446*7c478bd9Sstevel@tonic-gate while (len >= 2) { 1447*7c478bd9Sstevel@tonic-gate GETCHAR(code, p); 1448*7c478bd9Sstevel@tonic-gate GETCHAR(olen, p); 1449*7c478bd9Sstevel@tonic-gate p -= 2; 1450*7c478bd9Sstevel@tonic-gate if (olen < 2 || olen > len) { 1451*7c478bd9Sstevel@tonic-gate break; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate printer(arg, " <"); 1454*7c478bd9Sstevel@tonic-gate len -= olen; 1455*7c478bd9Sstevel@tonic-gate optend = p + olen; 1456*7c478bd9Sstevel@tonic-gate switch (code) { 1457*7c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 1458*7c478bd9Sstevel@tonic-gate if (olen >= CILEN_COMPRESS) { 1459*7c478bd9Sstevel@tonic-gate p += 2; 1460*7c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); 1461*7c478bd9Sstevel@tonic-gate printer(arg, "compress 0x%x", cishort); 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate break; 1464*7c478bd9Sstevel@tonic-gate case CI_IFACEID: 1465*7c478bd9Sstevel@tonic-gate if (olen == CILEN_IFACEID) { 1466*7c478bd9Sstevel@tonic-gate p += 2; 1467*7c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 1468*7c478bd9Sstevel@tonic-gate printer(arg, "addr %s", llv6_ntoa(ifaceid)); 1469*7c478bd9Sstevel@tonic-gate } 1470*7c478bd9Sstevel@tonic-gate break; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate printer(arg, "%8.*B>", optend-p, p); 1473*7c478bd9Sstevel@tonic-gate p = optend; 1474*7c478bd9Sstevel@tonic-gate } 1475*7c478bd9Sstevel@tonic-gate break; 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate case CODE_TERMACK: 1478*7c478bd9Sstevel@tonic-gate case CODE_TERMREQ: 1479*7c478bd9Sstevel@tonic-gate if (len > 0 && *p >= ' ' && *p < 0x7f) { 1480*7c478bd9Sstevel@tonic-gate printer(arg, " "); 1481*7c478bd9Sstevel@tonic-gate print_string((char *)p, len, printer, arg); 1482*7c478bd9Sstevel@tonic-gate p += len; 1483*7c478bd9Sstevel@tonic-gate len = 0; 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate break; 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate /* print the rest of the bytes in the packet */ 1489*7c478bd9Sstevel@tonic-gate printer(arg, " %32.*B", len, p); 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate return p - pstart; 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate /* 1495*7c478bd9Sstevel@tonic-gate * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. 1496*7c478bd9Sstevel@tonic-gate * We don't bring the link up for IP fragments or for TCP FIN packets 1497*7c478bd9Sstevel@tonic-gate * with no data. 1498*7c478bd9Sstevel@tonic-gate */ 1499*7c478bd9Sstevel@tonic-gate #define IP6_HDRLEN 40 /* bytes */ 1500*7c478bd9Sstevel@tonic-gate #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ 1501*7c478bd9Sstevel@tonic-gate #define IPPROTO_TCP 6 1502*7c478bd9Sstevel@tonic-gate #define TCP_HDRLEN 20 1503*7c478bd9Sstevel@tonic-gate #define TH_FIN 0x01 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate /* 1506*7c478bd9Sstevel@tonic-gate * We use these macros because the IP header may be at an odd address, 1507*7c478bd9Sstevel@tonic-gate * and some compilers might use word loads to get th_off or ip_hl. 1508*7c478bd9Sstevel@tonic-gate */ 1509*7c478bd9Sstevel@tonic-gate 1510*7c478bd9Sstevel@tonic-gate #define get_ip6nh(x) (((unsigned char *)(x))[6]) 1511*7c478bd9Sstevel@tonic-gate #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) 1512*7c478bd9Sstevel@tonic-gate #define get_tcpflags(x) (((unsigned char *)(x))[13]) 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate static int 1515*7c478bd9Sstevel@tonic-gate ipv6_active_pkt(pkt, len) 1516*7c478bd9Sstevel@tonic-gate u_char *pkt; 1517*7c478bd9Sstevel@tonic-gate int len; 1518*7c478bd9Sstevel@tonic-gate { 1519*7c478bd9Sstevel@tonic-gate u_char *tcp; 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate len -= PPP_HDRLEN; 1522*7c478bd9Sstevel@tonic-gate pkt += PPP_HDRLEN; 1523*7c478bd9Sstevel@tonic-gate if (len < IP6_HDRLEN) 1524*7c478bd9Sstevel@tonic-gate return 0; 1525*7c478bd9Sstevel@tonic-gate if (get_ip6nh(pkt) == IP6_NHDR_FRAG) 1526*7c478bd9Sstevel@tonic-gate return 0; 1527*7c478bd9Sstevel@tonic-gate if (get_ip6nh(pkt) != IPPROTO_TCP) 1528*7c478bd9Sstevel@tonic-gate return 1; 1529*7c478bd9Sstevel@tonic-gate if (len < IP6_HDRLEN + TCP_HDRLEN) 1530*7c478bd9Sstevel@tonic-gate return 0; 1531*7c478bd9Sstevel@tonic-gate tcp = pkt + IP6_HDRLEN; 1532*7c478bd9Sstevel@tonic-gate if ((get_tcpflags(tcp) & TH_FIN) != 0 && 1533*7c478bd9Sstevel@tonic-gate len == IP6_HDRLEN + get_tcpoff(tcp) * 4) 1534*7c478bd9Sstevel@tonic-gate return 0; 1535*7c478bd9Sstevel@tonic-gate return 1; 1536*7c478bd9Sstevel@tonic-gate } 1537