17c478bd9Sstevel@tonic-gate /* 2*f53eecf5SJames Carlson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate ipv6cp.c - PPP IPV6 Control Protocol. 67c478bd9Sstevel@tonic-gate Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi> 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate Redistribution and use in source and binary forms are permitted 97c478bd9Sstevel@tonic-gate provided that the above copyright notice and this paragraph are 107c478bd9Sstevel@tonic-gate duplicated in all such forms. The name of the author may not be 117c478bd9Sstevel@tonic-gate used to endorse or promote products derived from this software 127c478bd9Sstevel@tonic-gate without specific prior written permission. 137c478bd9Sstevel@tonic-gate THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 147c478bd9Sstevel@tonic-gate IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 157c478bd9Sstevel@tonic-gate WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 167c478bd9Sstevel@tonic-gate */ 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate /* Original version, based on RFC2023 : 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, 217c478bd9Sstevel@tonic-gate Alain.Durand@imag.fr, IMAG, 227c478bd9Sstevel@tonic-gate Jean-Luc.Richier@imag.fr, IMAG-LSR. 237c478bd9Sstevel@tonic-gate 247c478bd9Sstevel@tonic-gate Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, 257c478bd9Sstevel@tonic-gate Alain.Durand@imag.fr, IMAG, 267c478bd9Sstevel@tonic-gate Jean-Luc.Richier@imag.fr, IMAG-LSR. 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate Ce travail a �t� fait au sein du GIE DYADE (Groupement d'Int�r�t 297c478bd9Sstevel@tonic-gate �conomique ayant pour membres BULL S.A. et l'INRIA). 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate Ce logiciel informatique est disponible aux conditions 327c478bd9Sstevel@tonic-gate usuelles dans la recherche, c'est-�-dire qu'il peut 337c478bd9Sstevel@tonic-gate �tre utilis�, copi�, modifi�, distribu� � l'unique 347c478bd9Sstevel@tonic-gate condition que ce texte soit conserv� afin que 357c478bd9Sstevel@tonic-gate l'origine de ce logiciel soit reconnue. 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate Le nom de l'Institut National de Recherche en Informatique 387c478bd9Sstevel@tonic-gate et en Automatique (INRIA), de l'IMAG, ou d'une personne morale 397c478bd9Sstevel@tonic-gate ou physique ayant particip� � l'�laboration de ce logiciel ne peut 407c478bd9Sstevel@tonic-gate �tre utilis� sans son accord pr�alable explicite. 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate Ce logiciel est fourni tel quel sans aucune garantie, 437c478bd9Sstevel@tonic-gate support ou responsabilit� d'aucune sorte. 447c478bd9Sstevel@tonic-gate Ce logiciel est d�riv� de sources d'origine 457c478bd9Sstevel@tonic-gate "University of California at Berkeley" et 467c478bd9Sstevel@tonic-gate "Digital Equipment Corporation" couvertes par des copyrights. 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate L'Institut d'Informatique et de Math�matiques Appliqu�es de Grenoble (IMAG) 497c478bd9Sstevel@tonic-gate est une f�d�ration d'unit�s mixtes de recherche du CNRS, de l'Institut National 507c478bd9Sstevel@tonic-gate Polytechnique de Grenoble et de l'Universit� Joseph Fourier regroupant 517c478bd9Sstevel@tonic-gate sept laboratoires dont le laboratoire Logiciels, Syst�mes, R�seaux (LSR). 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate This work has been done in the context of GIE DYADE (joint R & D venture 547c478bd9Sstevel@tonic-gate between BULL S.A. and INRIA). 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate This software is available with usual "research" terms 577c478bd9Sstevel@tonic-gate with the aim of retain credits of the software. 587c478bd9Sstevel@tonic-gate Permission to use, copy, modify and distribute this software for any 597c478bd9Sstevel@tonic-gate purpose and without fee is hereby granted, provided that the above 607c478bd9Sstevel@tonic-gate copyright notice and this permission notice appear in all copies, 617c478bd9Sstevel@tonic-gate and the name of INRIA, IMAG, or any contributor not be used in advertising 627c478bd9Sstevel@tonic-gate or publicity pertaining to this material without the prior explicit 637c478bd9Sstevel@tonic-gate permission. The software is provided "as is" without any 647c478bd9Sstevel@tonic-gate warranties, support or liabilities of any kind. 657c478bd9Sstevel@tonic-gate This software is derived from source code from 667c478bd9Sstevel@tonic-gate "University of California at Berkeley" and 677c478bd9Sstevel@tonic-gate "Digital Equipment Corporation" protected by copyrights. 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) 707c478bd9Sstevel@tonic-gate is a federation of seven research units funded by the CNRS, National 717c478bd9Sstevel@tonic-gate Polytechnic Institute of Grenoble and University Joseph Fourier. 727c478bd9Sstevel@tonic-gate The research unit in Software, Systems, Networks (LSR) is member of IMAG. 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * Derived from : 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * ipcp.c - PPP IP Control Protocol. 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Carnegie Mellon University. 827c478bd9Sstevel@tonic-gate * All rights reserved. 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 857c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 867c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 877c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 887c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 897c478bd9Sstevel@tonic-gate * by Carnegie Mellon University. The name of the 907c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 917c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 927c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 937c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 947c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 957c478bd9Sstevel@tonic-gate * 967c478bd9Sstevel@tonic-gate * $Id: ipv6cp.c,v 1.9 2000/04/15 01:27:11 masputra Exp $ 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define RCSID "$Id: ipv6cp.c,v 1.9 2000/04/15 01:27:11 masputra Exp $" 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * TODO: 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * Proxy Neighbour Discovery. 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * Better defines for selecting the ordering of 1077c478bd9Sstevel@tonic-gate * interface up / set address. (currently checks for __linux__, 1087c478bd9Sstevel@tonic-gate * since SVR4 && (SNI || __USLC__) didn't work properly) 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate #include <stdio.h> 1127c478bd9Sstevel@tonic-gate #include <string.h> 1137c478bd9Sstevel@tonic-gate #include <stdlib.h> 1147c478bd9Sstevel@tonic-gate #include <unistd.h> 1157c478bd9Sstevel@tonic-gate #include <netdb.h> 1167c478bd9Sstevel@tonic-gate #include <sys/param.h> 1177c478bd9Sstevel@tonic-gate #include <sys/types.h> 1187c478bd9Sstevel@tonic-gate #include <sys/socket.h> 1197c478bd9Sstevel@tonic-gate #include <netinet/in.h> 1207c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate #include "pppd.h" 1237c478bd9Sstevel@tonic-gate #include "eui64.h" 1247c478bd9Sstevel@tonic-gate #include "fsm.h" 1257c478bd9Sstevel@tonic-gate #include "ipcp.h" 1267c478bd9Sstevel@tonic-gate #include "ipv6cp.h" 1277c478bd9Sstevel@tonic-gate #include "magic.h" 1287c478bd9Sstevel@tonic-gate #include "pathnames.h" 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 1317c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 1327c478bd9Sstevel@tonic-gate #endif 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* global vars */ 1357c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */ 1367c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ 1377c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ 1387c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */ 1397c478bd9Sstevel@tonic-gate int no_ifaceid_neg = 0; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* local vars */ 1427c478bd9Sstevel@tonic-gate static bool ipv6cp_is_up; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * Callbacks for fsm code. (CI = Configuration Information) 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */ 1487c478bd9Sstevel@tonic-gate static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */ 1497c478bd9Sstevel@tonic-gate static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ 1507c478bd9Sstevel@tonic-gate static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ 1517c478bd9Sstevel@tonic-gate static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ 1527c478bd9Sstevel@tonic-gate static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ 1537c478bd9Sstevel@tonic-gate static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ 1547c478bd9Sstevel@tonic-gate static void ipv6cp_up __P((fsm *)); /* We're UP */ 1557c478bd9Sstevel@tonic-gate static void ipv6cp_down __P((fsm *)); /* We're DOWN */ 1567c478bd9Sstevel@tonic-gate static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */ 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */ 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ 1617c478bd9Sstevel@tonic-gate ipv6cp_resetci, /* Reset our Configuration Information */ 1627c478bd9Sstevel@tonic-gate ipv6cp_cilen, /* Length of our Configuration Information */ 1637c478bd9Sstevel@tonic-gate ipv6cp_addci, /* Add our Configuration Information */ 1647c478bd9Sstevel@tonic-gate ipv6cp_ackci, /* ACK our Configuration Information */ 1657c478bd9Sstevel@tonic-gate ipv6cp_nakci, /* NAK our Configuration Information */ 1667c478bd9Sstevel@tonic-gate ipv6cp_rejci, /* Reject our Configuration Information */ 1677c478bd9Sstevel@tonic-gate ipv6cp_reqci, /* Request peer's Configuration Information */ 1687c478bd9Sstevel@tonic-gate ipv6cp_up, /* Called when fsm reaches OPENED state */ 1697c478bd9Sstevel@tonic-gate ipv6cp_down, /* Called when fsm leaves OPENED state */ 1707c478bd9Sstevel@tonic-gate NULL, /* Called when we want the lower layer up */ 1717c478bd9Sstevel@tonic-gate ipv6cp_finished, /* Called when we want the lower layer down */ 1727c478bd9Sstevel@tonic-gate NULL, /* Retransmission is necessary */ 1737c478bd9Sstevel@tonic-gate NULL, /* Called to handle protocol-specific codes */ 1747c478bd9Sstevel@tonic-gate "IPV6CP", /* String name of protocol */ 1757c478bd9Sstevel@tonic-gate NULL /* Peer rejected a code number */ 1767c478bd9Sstevel@tonic-gate }; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static int setifaceid __P((char **arg, option_t *)); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Command-line options. 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate static option_t ipv6cp_option_list[] = { 1847c478bd9Sstevel@tonic-gate { "ipv6", o_special, (void *)setifaceid, 1857c478bd9Sstevel@tonic-gate "Set interface identifiers for IPV6" }, 1867c478bd9Sstevel@tonic-gate { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, 1877c478bd9Sstevel@tonic-gate "Disable IPv6 and IPv6CP" }, 1887c478bd9Sstevel@tonic-gate { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, 1897c478bd9Sstevel@tonic-gate "Disable IPv6 and IPv6CP" }, 1907c478bd9Sstevel@tonic-gate { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, 1917c478bd9Sstevel@tonic-gate "Enable IPv6 and IPv6CP", 1 }, 1927c478bd9Sstevel@tonic-gate { "ipv6cp-accept-local", o_bool, &ipv6cp_wantoptions[0].accept_local, 1937c478bd9Sstevel@tonic-gate "Accept peer's interface identifier for us", 1 }, 1947c478bd9Sstevel@tonic-gate { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_wantoptions[0].use_ip, 1957c478bd9Sstevel@tonic-gate "Use (default) IPv4 address as interface identifier", 1 }, 1967c478bd9Sstevel@tonic-gate #if defined(SOL2) 1977c478bd9Sstevel@tonic-gate { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, 1987c478bd9Sstevel@tonic-gate "Use unique persistent value for link local address", 1 }, 1997c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */ 2007c478bd9Sstevel@tonic-gate { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, 2017c478bd9Sstevel@tonic-gate "Set timeout for IPv6CP" }, 2027c478bd9Sstevel@tonic-gate { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, 2037c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Terminate-Request" }, 2047c478bd9Sstevel@tonic-gate { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, 2057c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Configure-Request" }, 2067c478bd9Sstevel@tonic-gate { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, 2077c478bd9Sstevel@tonic-gate "Maximum number of IPV6CP Configure-Nak" }, 2087c478bd9Sstevel@tonic-gate { NULL } 2097c478bd9Sstevel@tonic-gate }; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * Protocol entry points from main code. 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate static void ipv6cp_init __P((int)); 2167c478bd9Sstevel@tonic-gate static void ipv6cp_open __P((int)); 2177c478bd9Sstevel@tonic-gate static void ipv6cp_close __P((int, char *)); 2187c478bd9Sstevel@tonic-gate static void ipv6cp_lowerup __P((int)); 2197c478bd9Sstevel@tonic-gate static void ipv6cp_lowerdown __P((int)); 2207c478bd9Sstevel@tonic-gate static void ipv6cp_input __P((int, u_char *, int)); 2217c478bd9Sstevel@tonic-gate static void ipv6cp_protrej __P((int)); 2227c478bd9Sstevel@tonic-gate static int ipv6cp_printpkt __P((u_char *, int, 2237c478bd9Sstevel@tonic-gate void (*) __P((void *, const char *, ...)), void *)); 2247c478bd9Sstevel@tonic-gate static void ipv6_check_options __P((void)); 2257c478bd9Sstevel@tonic-gate static int ipv6_demand_conf __P((int)); 2267c478bd9Sstevel@tonic-gate static int ipv6_active_pkt __P((u_char *, int)); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate struct protent ipv6cp_protent = { 2297c478bd9Sstevel@tonic-gate PPP_IPV6CP, /* Protocol Number for IPV6CP */ 2307c478bd9Sstevel@tonic-gate ipv6cp_init, /* Initializes IPV6CP */ 2317c478bd9Sstevel@tonic-gate ipv6cp_input, /* Processes a received IPV6CP packet */ 2327c478bd9Sstevel@tonic-gate ipv6cp_protrej, /* Process a received Protocol-reject */ 2337c478bd9Sstevel@tonic-gate ipv6cp_lowerup, /* Called when LCP is brought up */ 2347c478bd9Sstevel@tonic-gate ipv6cp_lowerdown, /* Called when LCP has gone down */ 2357c478bd9Sstevel@tonic-gate ipv6cp_open, /* Called when link is established */ 2367c478bd9Sstevel@tonic-gate ipv6cp_close, /* Called when link has gone down */ 2377c478bd9Sstevel@tonic-gate ipv6cp_printpkt, /* Print a packet in human readable form */ 2387c478bd9Sstevel@tonic-gate NULL, /* Process a received data packet */ 2397c478bd9Sstevel@tonic-gate 0, /* IPV6CP is disabled by default */ 2407c478bd9Sstevel@tonic-gate "IPV6CP", /* Name of the protocol */ 2417c478bd9Sstevel@tonic-gate "IPV6", /* Name of the corresponding data protocol */ 2427c478bd9Sstevel@tonic-gate ipv6cp_option_list, /* List of IPV6CP command-line options */ 2437c478bd9Sstevel@tonic-gate ipv6_check_options, /* Assigns default values for options */ 2447c478bd9Sstevel@tonic-gate ipv6_demand_conf, /* Configures demand-dial */ 2457c478bd9Sstevel@tonic-gate ipv6_active_pkt /* Bring up the link for this packet? */ 2467c478bd9Sstevel@tonic-gate }; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * Local forward function declarations. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t)); 2527c478bd9Sstevel@tonic-gate static void ipv6cp_script __P((char *)); 2537c478bd9Sstevel@tonic-gate static void ipv6cp_script_done __P((void *, int)); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * Lengths of configuration options. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate #define CILEN_VOID 2 2597c478bd9Sstevel@tonic-gate #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ 2607c478bd9Sstevel@tonic-gate #define CILEN_IFACEID 10 /* RFC2472, interface identifier */ 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate #define CODENAME(x) ((x) == CODE_CONFACK ? "ACK" : \ 2637c478bd9Sstevel@tonic-gate (x) == CODE_CONFNAK ? "NAK" : "REJ") 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * This state variable is used to ensure that we don't 2677c478bd9Sstevel@tonic-gate * run an ipcp-up/down script while one is already running. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate static enum script_state { 2707c478bd9Sstevel@tonic-gate s_down, 2717c478bd9Sstevel@tonic-gate s_up 2727c478bd9Sstevel@tonic-gate } ipv6cp_script_state; 2737c478bd9Sstevel@tonic-gate static pid_t ipv6cp_script_pid; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * setifaceid - set the interface identifiers manually 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2797c478bd9Sstevel@tonic-gate static int 2807c478bd9Sstevel@tonic-gate setifaceid(argv, opt) 2817c478bd9Sstevel@tonic-gate char **argv; 2827c478bd9Sstevel@tonic-gate option_t *opt; 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate char *comma, *arg; 2857c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 2867c478bd9Sstevel@tonic-gate struct in6_addr addr; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ 2897c478bd9Sstevel@tonic-gate (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate arg = *argv; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate comma = strchr(arg, ','); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * If comma first character, then no local identifier 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate if (comma != arg) { 3007c478bd9Sstevel@tonic-gate if (comma != NULL) 3017c478bd9Sstevel@tonic-gate *comma = '\0'; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, arg, &addr) != 1 || !VALIDID(addr)) { 3047c478bd9Sstevel@tonic-gate option_error("Illegal interface identifier (local): %s", arg); 3057c478bd9Sstevel@tonic-gate return 0; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate eui64_copy(addr.s6_addr32[2], wo->ourid); 3097c478bd9Sstevel@tonic-gate wo->opt_local = 1; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * If comma last character, then no remote identifier 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate if (comma != NULL && *++comma != '\0') { 3167c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, comma, &addr) != 1 || !VALIDID(addr)) { 3177c478bd9Sstevel@tonic-gate option_error("Illegal interface identifier (remote): %s", comma); 3187c478bd9Sstevel@tonic-gate return 0; 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate eui64_copy(addr.s6_addr32[2], wo->hisid); 3217c478bd9Sstevel@tonic-gate wo->opt_remote = 1; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate ipv6cp_protent.enabled_flag = 1; 3257c478bd9Sstevel@tonic-gate return 1; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * Given an interface identifier, return a string representation of the 3307c478bd9Sstevel@tonic-gate * link local address associated with that identifier. 3317c478bd9Sstevel@tonic-gate * string will be at most 26 characters (including null terminator). 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate static char * 3347c478bd9Sstevel@tonic-gate llv6_ntoa(ifaceid) 3357c478bd9Sstevel@tonic-gate eui64_t ifaceid; 3367c478bd9Sstevel@tonic-gate { 3377c478bd9Sstevel@tonic-gate struct in6_addr addr; 3387c478bd9Sstevel@tonic-gate static char addrstr[26]; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate BZERO(&addr, sizeof (addr)); 3417c478bd9Sstevel@tonic-gate addr.s6_addr[0] = 0xfe; 3427c478bd9Sstevel@tonic-gate addr.s6_addr[1] = 0x80; 3437c478bd9Sstevel@tonic-gate eui64_copy(ifaceid, addr.s6_addr[8]); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &addr, addrstr, 26); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate return addrstr; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * ipv6cp_init - Initialize IPV6CP. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate static void 3557c478bd9Sstevel@tonic-gate ipv6cp_init(unit) 3567c478bd9Sstevel@tonic-gate int unit; 3577c478bd9Sstevel@tonic-gate { 3587c478bd9Sstevel@tonic-gate fsm *f = &ipv6cp_fsm[unit]; 3597c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[unit]; 3607c478bd9Sstevel@tonic-gate ipv6cp_options *ao = &ipv6cp_allowoptions[unit]; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate f->unit = unit; 3637c478bd9Sstevel@tonic-gate f->protocol = PPP_IPV6CP; 3647c478bd9Sstevel@tonic-gate f->callbacks = &ipv6cp_callbacks; 3657c478bd9Sstevel@tonic-gate fsm_init(&ipv6cp_fsm[unit]); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate BZERO(wo, sizeof(*wo)); 3687c478bd9Sstevel@tonic-gate BZERO(ao, sizeof(*ao)); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate wo->neg_ifaceid = 1; 3717c478bd9Sstevel@tonic-gate ao->neg_ifaceid = 1; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 3747c478bd9Sstevel@tonic-gate wo->neg_vj = 1; 3757c478bd9Sstevel@tonic-gate ao->neg_vj = 1; 3767c478bd9Sstevel@tonic-gate wo->vj_protocol = IPV6CP_COMP; 3777c478bd9Sstevel@tonic-gate #endif 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * ipv6cp_open - IPV6CP is allowed to come up. 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate static void 3867c478bd9Sstevel@tonic-gate ipv6cp_open(unit) 3877c478bd9Sstevel@tonic-gate int unit; 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate fsm_open(&ipv6cp_fsm[unit]); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * ipv6cp_close - Take IPV6CP down. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate static void 3977c478bd9Sstevel@tonic-gate ipv6cp_close(unit, reason) 3987c478bd9Sstevel@tonic-gate int unit; 3997c478bd9Sstevel@tonic-gate char *reason; 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate fsm_close(&ipv6cp_fsm[unit], reason); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * ipv6cp_lowerup - The lower layer is up. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate static void 4097c478bd9Sstevel@tonic-gate ipv6cp_lowerup(unit) 4107c478bd9Sstevel@tonic-gate int unit; 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate fsm_lowerup(&ipv6cp_fsm[unit]); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * ipv6cp_lowerdown - The lower layer is down. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate static void 4207c478bd9Sstevel@tonic-gate ipv6cp_lowerdown(unit) 4217c478bd9Sstevel@tonic-gate int unit; 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate fsm_lowerdown(&ipv6cp_fsm[unit]); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * ipv6cp_input - Input IPV6CP packet. 4297c478bd9Sstevel@tonic-gate */ 4307c478bd9Sstevel@tonic-gate static void 4317c478bd9Sstevel@tonic-gate ipv6cp_input(unit, p, len) 4327c478bd9Sstevel@tonic-gate int unit; 4337c478bd9Sstevel@tonic-gate u_char *p; 4347c478bd9Sstevel@tonic-gate int len; 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate fsm_input(&ipv6cp_fsm[unit], p, len); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate static void 4447c478bd9Sstevel@tonic-gate ipv6cp_protrej(unit) 4457c478bd9Sstevel@tonic-gate int unit; 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate fsm_protreject(&ipv6cp_fsm[unit]); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * ipv6cp_resetci - Reset our CI. 4537c478bd9Sstevel@tonic-gate */ 4547c478bd9Sstevel@tonic-gate static void 4557c478bd9Sstevel@tonic-gate ipv6cp_resetci(f) 4567c478bd9Sstevel@tonic-gate fsm *f; 4577c478bd9Sstevel@tonic-gate { 4587c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 4597c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (!wo->opt_local) { 4647c478bd9Sstevel@tonic-gate eui64_magic_nz(wo->ourid); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate *go = *wo; 4687c478bd9Sstevel@tonic-gate eui64_zero(go->hisid); /* last proposed interface identifier */ 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * ipv6cp_cilen - Return length of our CI. 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate static int 4767c478bd9Sstevel@tonic-gate ipv6cp_cilen(f) 4777c478bd9Sstevel@tonic-gate fsm *f; 4787c478bd9Sstevel@tonic-gate { 4797c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) 4827c478bd9Sstevel@tonic-gate #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate return (LENCIIFACEID(go->neg_ifaceid) + 4857c478bd9Sstevel@tonic-gate LENCIVJ(go->neg_vj)); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * ipv6cp_addci - Add our desired CIs to a packet. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate static void 4937c478bd9Sstevel@tonic-gate ipv6cp_addci(f, ucp, lenp) 4947c478bd9Sstevel@tonic-gate fsm *f; 4957c478bd9Sstevel@tonic-gate u_char *ucp; 4967c478bd9Sstevel@tonic-gate int *lenp; 4977c478bd9Sstevel@tonic-gate { 4987c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 4997c478bd9Sstevel@tonic-gate int len = *lenp; 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate #define ADDCIVJ(opt, neg, val) \ 5027c478bd9Sstevel@tonic-gate if (neg) { \ 5037c478bd9Sstevel@tonic-gate int vjlen = CILEN_COMPRESS; \ 5047c478bd9Sstevel@tonic-gate if (len >= vjlen) { \ 5057c478bd9Sstevel@tonic-gate PUTCHAR(opt, ucp); \ 5067c478bd9Sstevel@tonic-gate PUTCHAR(vjlen, ucp); \ 5077c478bd9Sstevel@tonic-gate PUTSHORT(val, ucp); \ 5087c478bd9Sstevel@tonic-gate len -= vjlen; \ 5097c478bd9Sstevel@tonic-gate } else \ 5107c478bd9Sstevel@tonic-gate neg = 0; \ 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate #define ADDCIIFACEID(opt, neg, val1) \ 5147c478bd9Sstevel@tonic-gate if (neg) { \ 5157c478bd9Sstevel@tonic-gate int idlen = CILEN_IFACEID; \ 5167c478bd9Sstevel@tonic-gate if (len >= idlen) { \ 5177c478bd9Sstevel@tonic-gate PUTCHAR(opt, ucp); \ 5187c478bd9Sstevel@tonic-gate PUTCHAR(idlen, ucp); \ 5197c478bd9Sstevel@tonic-gate eui64_put(val1, ucp); \ 5207c478bd9Sstevel@tonic-gate len -= idlen; \ 5217c478bd9Sstevel@tonic-gate } else \ 5227c478bd9Sstevel@tonic-gate neg = 0; \ 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate *lenp -= len; 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * ipv6cp_ackci - Ack our CIs. 5357c478bd9Sstevel@tonic-gate * 5367c478bd9Sstevel@tonic-gate * Returns: 5377c478bd9Sstevel@tonic-gate * 0 - Ack was bad. 5387c478bd9Sstevel@tonic-gate * 1 - Ack was good. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate static int 5417c478bd9Sstevel@tonic-gate ipv6cp_ackci(f, p, len) 5427c478bd9Sstevel@tonic-gate fsm *f; 5437c478bd9Sstevel@tonic-gate u_char *p; 5447c478bd9Sstevel@tonic-gate int len; 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 5477c478bd9Sstevel@tonic-gate u_short cilen, citype, cishort; 5487c478bd9Sstevel@tonic-gate eui64_t ifaceid; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * CIs must be in exactly the same order that we sent... 5527c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 5537c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate #define ACKCIVJ(opt, neg, val) \ 5577c478bd9Sstevel@tonic-gate if (neg) { \ 5587c478bd9Sstevel@tonic-gate int vjlen = CILEN_COMPRESS; \ 5597c478bd9Sstevel@tonic-gate if ((len -= vjlen) < 0) \ 5607c478bd9Sstevel@tonic-gate goto bad; \ 5617c478bd9Sstevel@tonic-gate GETCHAR(citype, p); \ 5627c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); \ 5637c478bd9Sstevel@tonic-gate if (cilen != vjlen || \ 5647c478bd9Sstevel@tonic-gate citype != opt) \ 5657c478bd9Sstevel@tonic-gate goto bad; \ 5667c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 5677c478bd9Sstevel@tonic-gate if (cishort != val) \ 5687c478bd9Sstevel@tonic-gate goto bad; \ 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate #define ACKCIIFACEID(opt, neg, val1) \ 5727c478bd9Sstevel@tonic-gate if (neg) { \ 5737c478bd9Sstevel@tonic-gate int idlen = CILEN_IFACEID; \ 5747c478bd9Sstevel@tonic-gate if ((len -= idlen) < 0) \ 5757c478bd9Sstevel@tonic-gate goto bad; \ 5767c478bd9Sstevel@tonic-gate GETCHAR(citype, p); \ 5777c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); \ 5787c478bd9Sstevel@tonic-gate if (cilen != idlen || \ 5797c478bd9Sstevel@tonic-gate citype != opt) \ 5807c478bd9Sstevel@tonic-gate goto bad; \ 5817c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 5827c478bd9Sstevel@tonic-gate if (! eui64_equals(val1, ifaceid)) \ 5837c478bd9Sstevel@tonic-gate goto bad; \ 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * If there are any remaining CIs, then this packet is bad. 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate if (len != 0) 5947c478bd9Sstevel@tonic-gate goto bad; 5957c478bd9Sstevel@tonic-gate return (1); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate bad: 5987c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); 5997c478bd9Sstevel@tonic-gate return (0); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. 6047c478bd9Sstevel@tonic-gate * This should not modify any state if the Nak is bad 6057c478bd9Sstevel@tonic-gate * or if IPV6CP is in the OPENED state. 6067c478bd9Sstevel@tonic-gate * 6077c478bd9Sstevel@tonic-gate * Returns: 6087c478bd9Sstevel@tonic-gate * 0 - Nak was bad. 6097c478bd9Sstevel@tonic-gate * 1 - Nak was good. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate static int 6127c478bd9Sstevel@tonic-gate ipv6cp_nakci(f, p, len) 6137c478bd9Sstevel@tonic-gate fsm *f; 6147c478bd9Sstevel@tonic-gate u_char *p; 6157c478bd9Sstevel@tonic-gate int len; 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 6187c478bd9Sstevel@tonic-gate u_char citype, cilen, *next; 6197c478bd9Sstevel@tonic-gate u_short cishort; 6207c478bd9Sstevel@tonic-gate eui64_t ifaceid; 6217c478bd9Sstevel@tonic-gate ipv6cp_options no; /* options we've seen Naks for */ 6227c478bd9Sstevel@tonic-gate ipv6cp_options try; /* options to request next time */ 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate BZERO(&no, sizeof(no)); 6257c478bd9Sstevel@tonic-gate try = *go; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * Any Nak'd CIs must be in exactly the same order that we sent. 6297c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 6307c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate #define NAKCIIFACEID(opt, neg, code) \ 6337c478bd9Sstevel@tonic-gate if (go->neg && \ 6347c478bd9Sstevel@tonic-gate len >= (cilen = CILEN_IFACEID) && \ 6357c478bd9Sstevel@tonic-gate p[1] == cilen && \ 6367c478bd9Sstevel@tonic-gate p[0] == opt) { \ 6377c478bd9Sstevel@tonic-gate len -= cilen; \ 6387c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 6397c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 6407c478bd9Sstevel@tonic-gate no.neg = 1; \ 6417c478bd9Sstevel@tonic-gate code \ 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate #define NAKCIVJ(opt, neg, code) \ 6457c478bd9Sstevel@tonic-gate if (go->neg && \ 6467c478bd9Sstevel@tonic-gate ((cilen = p[1]) == CILEN_COMPRESS) && \ 6477c478bd9Sstevel@tonic-gate len >= cilen && \ 6487c478bd9Sstevel@tonic-gate p[0] == opt) { \ 6497c478bd9Sstevel@tonic-gate len -= cilen; \ 6507c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 6517c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 6527c478bd9Sstevel@tonic-gate no.neg = 1; \ 6537c478bd9Sstevel@tonic-gate code \ 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * Accept the peer's idea of {our,his} interface identifier, if different 6587c478bd9Sstevel@tonic-gate * from our idea, only if the accept_{local,remote} flag is set. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate NAKCIIFACEID(CI_IFACEID, neg_ifaceid, 6617c478bd9Sstevel@tonic-gate if (go->accept_local) { 6627c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 6637c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->hisid)) /* bad luck */ 6647c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 6657c478bd9Sstevel@tonic-gate try.ourid = ifaceid; 6667c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate ); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 6717c478bd9Sstevel@tonic-gate NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate if (cishort == IPV6CP_COMP) { 6747c478bd9Sstevel@tonic-gate try.vj_protocol = cishort; 6757c478bd9Sstevel@tonic-gate } else { 6767c478bd9Sstevel@tonic-gate try.neg_vj = 0; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate ); 6807c478bd9Sstevel@tonic-gate #else 6817c478bd9Sstevel@tonic-gate NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 6827c478bd9Sstevel@tonic-gate { 6837c478bd9Sstevel@tonic-gate try.neg_vj = 0; 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate ); 6867c478bd9Sstevel@tonic-gate #endif 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * There may be remaining CIs, if the peer is requesting negotiation 6907c478bd9Sstevel@tonic-gate * on an option that we didn't include in our request packet. 6917c478bd9Sstevel@tonic-gate * If they want to negotiate about interface identifier, we comply. 6927c478bd9Sstevel@tonic-gate * If they want us to ask for compression, we refuse. 6937c478bd9Sstevel@tonic-gate */ 6947c478bd9Sstevel@tonic-gate while (len > CILEN_VOID) { 6957c478bd9Sstevel@tonic-gate GETCHAR(citype, p); 6967c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); 6977c478bd9Sstevel@tonic-gate if( (len -= cilen) < 0 ) 6987c478bd9Sstevel@tonic-gate goto bad; 6997c478bd9Sstevel@tonic-gate next = p + cilen - 2; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate switch (citype) { 7027c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 7037c478bd9Sstevel@tonic-gate if (go->neg_vj || no.neg_vj || 7047c478bd9Sstevel@tonic-gate (cilen != CILEN_COMPRESS)) 7057c478bd9Sstevel@tonic-gate goto bad; 7067c478bd9Sstevel@tonic-gate no.neg_vj = 1; 7077c478bd9Sstevel@tonic-gate break; 7087c478bd9Sstevel@tonic-gate case CI_IFACEID: 7097c478bd9Sstevel@tonic-gate if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) 7107c478bd9Sstevel@tonic-gate goto bad; 7117c478bd9Sstevel@tonic-gate try.neg_ifaceid = 1; 7127c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 7137c478bd9Sstevel@tonic-gate if (go->accept_local) { 7147c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 7157c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->hisid)) /* bad luck */ 7167c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 7177c478bd9Sstevel@tonic-gate try.ourid = ifaceid; 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate no.neg_ifaceid = 1; 7207c478bd9Sstevel@tonic-gate break; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate p = next; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* If there is still anything left, this packet is bad. */ 7267c478bd9Sstevel@tonic-gate if (len != 0) 7277c478bd9Sstevel@tonic-gate goto bad; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * OK, the Nak is good. Now we can update state. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate if (f->state != OPENED) 7337c478bd9Sstevel@tonic-gate *go = try; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate return 1; 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate bad: 7387c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); 7397c478bd9Sstevel@tonic-gate return 0; 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * ipv6cp_rejci - Reject some of our CIs. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate static int 7477c478bd9Sstevel@tonic-gate ipv6cp_rejci(f, p, len) 7487c478bd9Sstevel@tonic-gate fsm *f; 7497c478bd9Sstevel@tonic-gate u_char *p; 7507c478bd9Sstevel@tonic-gate int len; 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 7537c478bd9Sstevel@tonic-gate u_char cilen; 7547c478bd9Sstevel@tonic-gate u_short cishort; 7557c478bd9Sstevel@tonic-gate eui64_t ifaceid; 7567c478bd9Sstevel@tonic-gate ipv6cp_options try; /* options to request next time */ 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate try = *go; 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate * Any Rejected CIs must be in exactly the same order that we sent. 7617c478bd9Sstevel@tonic-gate * Check packet length and CI length at each step. 7627c478bd9Sstevel@tonic-gate * If we find any deviations, then this packet is bad. 7637c478bd9Sstevel@tonic-gate */ 7647c478bd9Sstevel@tonic-gate #define REJCIIFACEID(opt, neg, val1) \ 7657c478bd9Sstevel@tonic-gate if (go->neg && \ 7667c478bd9Sstevel@tonic-gate len >= (cilen = CILEN_IFACEID) && \ 7677c478bd9Sstevel@tonic-gate p[1] == cilen && \ 7687c478bd9Sstevel@tonic-gate p[0] == opt) { \ 7697c478bd9Sstevel@tonic-gate len -= cilen; \ 7707c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 7717c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); \ 7727c478bd9Sstevel@tonic-gate /* Check rejected value. */ \ 7737c478bd9Sstevel@tonic-gate if (! eui64_equals(ifaceid, val1)) \ 7747c478bd9Sstevel@tonic-gate goto bad; \ 7757c478bd9Sstevel@tonic-gate try.neg = 0; \ 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate #define REJCIVJ(opt, neg, val) \ 7797c478bd9Sstevel@tonic-gate if (go->neg && \ 7807c478bd9Sstevel@tonic-gate p[1] == CILEN_COMPRESS && \ 7817c478bd9Sstevel@tonic-gate len >= p[1] && \ 7827c478bd9Sstevel@tonic-gate p[0] == opt) { \ 7837c478bd9Sstevel@tonic-gate len -= p[1]; \ 7847c478bd9Sstevel@tonic-gate INCPTR(2, p); \ 7857c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); \ 7867c478bd9Sstevel@tonic-gate /* Check rejected value. */ \ 7877c478bd9Sstevel@tonic-gate if (cishort != val) \ 7887c478bd9Sstevel@tonic-gate goto bad; \ 7897c478bd9Sstevel@tonic-gate try.neg = 0; \ 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * If there are any remaining CIs, then this packet is bad. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate if (len != 0) 8007c478bd9Sstevel@tonic-gate goto bad; 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Now we can update state. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate if (f->state != OPENED) 8057c478bd9Sstevel@tonic-gate *go = try; 8067c478bd9Sstevel@tonic-gate return 1; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate bad: 8097c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); 8107c478bd9Sstevel@tonic-gate return 0; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. 8167c478bd9Sstevel@tonic-gate * 8177c478bd9Sstevel@tonic-gate * Returns: CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and input packet modified 8187c478bd9Sstevel@tonic-gate * appropriately. If reject_if_disagree is non-zero, doesn't return 8197c478bd9Sstevel@tonic-gate * CODE_CONFNAK; returns CODE_CONFREJ if it can't return CODE_CONFACK. 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate static int 8227c478bd9Sstevel@tonic-gate ipv6cp_reqci(f, p, lenp, dont_nak) 8237c478bd9Sstevel@tonic-gate fsm *f; 8247c478bd9Sstevel@tonic-gate u_char *p; /* Requested CIs */ 8257c478bd9Sstevel@tonic-gate int *lenp; /* Length of requested CIs */ 8267c478bd9Sstevel@tonic-gate int dont_nak; 8277c478bd9Sstevel@tonic-gate { 8287c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 8297c478bd9Sstevel@tonic-gate ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 8307c478bd9Sstevel@tonic-gate ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit]; 8317c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 8327c478bd9Sstevel@tonic-gate u_char *p0, *nakp, *rejp, *prev; 8337c478bd9Sstevel@tonic-gate int ret, newret; 8347c478bd9Sstevel@tonic-gate int len, cilen, type; 8357c478bd9Sstevel@tonic-gate eui64_t ifaceid; 8367c478bd9Sstevel@tonic-gate u_short cishort; 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate ret = CODE_CONFACK; 8397c478bd9Sstevel@tonic-gate rejp = p0 = p; 8407c478bd9Sstevel@tonic-gate nakp = nak_buffer; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * Reset all his options. 8447c478bd9Sstevel@tonic-gate */ 8457c478bd9Sstevel@tonic-gate BZERO(ho, sizeof(*ho)); 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * Process all his options. 8497c478bd9Sstevel@tonic-gate */ 8507c478bd9Sstevel@tonic-gate for (len = *lenp; len > 0; len -= cilen, p = prev + cilen) { 8517c478bd9Sstevel@tonic-gate newret = CODE_CONFACK; 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if ((len < 2) || p[1] > len) { 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * RFC 1661 page 40 -- if the option extends beyond the 8567c478bd9Sstevel@tonic-gate * packet, then discard the entire packet. 8577c478bd9Sstevel@tonic-gate */ 8587c478bd9Sstevel@tonic-gate return (0); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate prev = p; 8627c478bd9Sstevel@tonic-gate GETCHAR(type, p); 8637c478bd9Sstevel@tonic-gate GETCHAR(cilen, p); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate switch (type) { /* Check CI type */ 8667c478bd9Sstevel@tonic-gate case CI_IFACEID: 8677c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: received interface identifier ")); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (!ao->neg_ifaceid) { 8707c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 8717c478bd9Sstevel@tonic-gate break; 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate if (cilen != CILEN_IFACEID) { 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * rfc1661, page 40 -- a recongnized option with an 8777c478bd9Sstevel@tonic-gate * invalid length should be Nak'ed. 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 8807c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 8817c478bd9Sstevel@tonic-gate } else { 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * If he has no interface identifier, or if we both 8857c478bd9Sstevel@tonic-gate * have same identifier then NAK it with new idea. In 8867c478bd9Sstevel@tonic-gate * particular, if we don't know his identifier, but he 8877c478bd9Sstevel@tonic-gate * does, then accept it. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 8907c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); 8917c478bd9Sstevel@tonic-gate if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { 8927c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; /* Reject CI */ 8937c478bd9Sstevel@tonic-gate break; 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate /* If we don't like his ID, then nak it. */ 8967c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->hisid) && 8977c478bd9Sstevel@tonic-gate !eui64_equals(ifaceid, wo->hisid) && 8987c478bd9Sstevel@tonic-gate eui64_iszero(go->hisid)) { 8997c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 9007c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 9017c478bd9Sstevel@tonic-gate } else if (eui64_iszero(ifaceid) || 9027c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->ourid)) { 9037c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 9047c478bd9Sstevel@tonic-gate /* first time, try option */ 9057c478bd9Sstevel@tonic-gate if (eui64_iszero(go->hisid)) 9067c478bd9Sstevel@tonic-gate eui64_copy(wo->hisid, ifaceid); 9077c478bd9Sstevel@tonic-gate while (eui64_iszero(ifaceid) || 9087c478bd9Sstevel@tonic-gate eui64_equals(ifaceid, go->ourid)) /* bad luck */ 9097c478bd9Sstevel@tonic-gate eui64_magic(ifaceid); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate if (newret == CODE_CONFNAK) { 9137c478bd9Sstevel@tonic-gate PUTCHAR(type, nakp); 9147c478bd9Sstevel@tonic-gate PUTCHAR(CILEN_IFACEID, nakp); 9157c478bd9Sstevel@tonic-gate eui64_put(ifaceid, nakp); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate ho->neg_ifaceid = 1; 9197c478bd9Sstevel@tonic-gate eui64_copy(ifaceid, ho->hisid); 9207c478bd9Sstevel@tonic-gate break; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 9237c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate if (!ao->neg_vj) { 9267c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 9277c478bd9Sstevel@tonic-gate break; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate if (cilen != CILEN_COMPRESS) { 9317c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 9327c478bd9Sstevel@tonic-gate cishort = ao->vj_protocol; 9337c478bd9Sstevel@tonic-gate } else { 9347c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); 9357c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("(%d)", cishort)); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 9387c478bd9Sstevel@tonic-gate if (cishort != IPV6CP_COMP) { 9397c478bd9Sstevel@tonic-gate newret = CODE_CONFNAK; 9407c478bd9Sstevel@tonic-gate cishort = IPV6CP_COMP; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate #else 9437c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate #endif 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate ho->neg_vj = 1; 9497c478bd9Sstevel@tonic-gate ho->vj_protocol = cishort; 9507c478bd9Sstevel@tonic-gate break; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate default: 9537c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 9547c478bd9Sstevel@tonic-gate break; 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate IPV6CPDEBUG((" (%s)\n", CODENAME(newret))); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* Cope with confused peers. */ 9607c478bd9Sstevel@tonic-gate if (cilen < 2) 9617c478bd9Sstevel@tonic-gate cilen = 2; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * If this is an Ack'able CI, but we're sending back a Nak, 9657c478bd9Sstevel@tonic-gate * don't include this CI. 9667c478bd9Sstevel@tonic-gate */ 9677c478bd9Sstevel@tonic-gate if (newret == CODE_CONFACK && ret != CODE_CONFACK) 9687c478bd9Sstevel@tonic-gate continue; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate if (newret == CODE_CONFNAK) { 9717c478bd9Sstevel@tonic-gate if (dont_nak) { 9727c478bd9Sstevel@tonic-gate newret = CODE_CONFREJ; 9737c478bd9Sstevel@tonic-gate } else { 9747c478bd9Sstevel@tonic-gate /* Ignore subsequent Nak'able things if rejecting. */ 9757c478bd9Sstevel@tonic-gate if (ret == CODE_CONFREJ) 9767c478bd9Sstevel@tonic-gate continue; 9777c478bd9Sstevel@tonic-gate ret = CODE_CONFNAK; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate if (newret == CODE_CONFREJ) { 9827c478bd9Sstevel@tonic-gate ret = CODE_CONFREJ; 9837c478bd9Sstevel@tonic-gate if (prev != rejp) 9847c478bd9Sstevel@tonic-gate (void) BCOPY(prev, rejp, cilen); 9857c478bd9Sstevel@tonic-gate rejp += cilen; 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * If we aren't rejecting this packet, and we want to negotiate 9917c478bd9Sstevel@tonic-gate * their identifier and they didn't send their identifier, then we 9927c478bd9Sstevel@tonic-gate * send a NAK with a CI_IFACEID option appended. We assume the 9937c478bd9Sstevel@tonic-gate * input buffer is long enough that we can append the extra 9947c478bd9Sstevel@tonic-gate * option safely. 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate if (ret != CODE_CONFREJ && !ho->neg_ifaceid && 9977c478bd9Sstevel@tonic-gate wo->req_ifaceid && !dont_nak) { 9987c478bd9Sstevel@tonic-gate if (ret == CODE_CONFACK) 9997c478bd9Sstevel@tonic-gate wo->req_ifaceid = 0; 10007c478bd9Sstevel@tonic-gate ret = CODE_CONFNAK; 10017c478bd9Sstevel@tonic-gate PUTCHAR(CI_IFACEID, nakp); 10027c478bd9Sstevel@tonic-gate PUTCHAR(CILEN_IFACEID, nakp); 10037c478bd9Sstevel@tonic-gate eui64_put(wo->hisid, nakp); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate switch (ret) { 10077c478bd9Sstevel@tonic-gate case CODE_CONFACK: 10087c478bd9Sstevel@tonic-gate *lenp = p - p0; 10097c478bd9Sstevel@tonic-gate sys_block_proto(PPP_IPV6); 10107c478bd9Sstevel@tonic-gate break; 10117c478bd9Sstevel@tonic-gate case CODE_CONFNAK: 10127c478bd9Sstevel@tonic-gate *lenp = nakp - nak_buffer; 10137c478bd9Sstevel@tonic-gate (void) BCOPY(nak_buffer, p0, *lenp); 10147c478bd9Sstevel@tonic-gate break; 10157c478bd9Sstevel@tonic-gate case CODE_CONFREJ: 10167c478bd9Sstevel@tonic-gate *lenp = rejp - p0; 10177c478bd9Sstevel@tonic-gate break; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(ret))); 10217c478bd9Sstevel@tonic-gate return (ret); /* Return final code */ 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * ipv6_check_options - check that any IP-related options are OK, 10277c478bd9Sstevel@tonic-gate * and assign appropriate defaults. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate static void 10307c478bd9Sstevel@tonic-gate ipv6_check_options() 10317c478bd9Sstevel@tonic-gate { 10327c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate #if defined(SOL2) 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Persistent link-local id is only used when user has not explicitly 10377c478bd9Sstevel@tonic-gate * configure/hard-code the id 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * On systems where there are no Ethernet interfaces used, there 10437c478bd9Sstevel@tonic-gate * may be other ways to obtain a persistent id. Right now, it 10447c478bd9Sstevel@tonic-gate * will fall back to using magic [see eui64_magic] below when 10457c478bd9Sstevel@tonic-gate * an EUI-48 from MAC address can't be obtained. Other possibilities 10467c478bd9Sstevel@tonic-gate * include obtaining EEPROM serial numbers, or some other unique 10477c478bd9Sstevel@tonic-gate * yet persistent number. On Sparc platforms, this is possible, 10487c478bd9Sstevel@tonic-gate * but too bad there's no standards yet for x86 machines. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate if (ether_to_eui64(&wo->ourid)) { 10517c478bd9Sstevel@tonic-gate wo->opt_local = 1; 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate #endif 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * If ipv6cp-use-ipaddr is used, then both local and remote IPv4 10587c478bd9Sstevel@tonic-gate * addresses should be specified as options. Otherwise, since 10597c478bd9Sstevel@tonic-gate * ipcp has yet to negotiate the IPv4 addresses, the interface 10607c478bd9Sstevel@tonic-gate * identifiers will be based on meaningless values. 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate if (wo->use_ip) { 10637c478bd9Sstevel@tonic-gate if ((ipcp_wantoptions[0].accept_local || 10647c478bd9Sstevel@tonic-gate ipcp_wantoptions[0].ouraddr == 0) && eui64_iszero(wo->ourid)) { 10657c478bd9Sstevel@tonic-gate warn("either IPv4 or IPv6 local address should be non-zero for ipv6cp-use-ipaddr"); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate if ((ipcp_wantoptions[0].accept_remote || 10687c478bd9Sstevel@tonic-gate ipcp_wantoptions[0].hisaddr == 0) && eui64_iszero(wo->hisid)) { 10697c478bd9Sstevel@tonic-gate warn("either IPv4 or IPv6 remote address should be non-zero for ipv6cp-use-ipaddr"); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if (!wo->opt_local) { /* init interface identifier */ 10747c478bd9Sstevel@tonic-gate if (wo->use_ip && eui64_iszero(wo->ourid)) { 10757c478bd9Sstevel@tonic-gate eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); 10767c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->ourid)) 10777c478bd9Sstevel@tonic-gate wo->opt_local = 1; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate while (eui64_iszero(wo->ourid)) 10817c478bd9Sstevel@tonic-gate eui64_magic(wo->ourid); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (!wo->opt_remote) { 10857c478bd9Sstevel@tonic-gate if (wo->use_ip && eui64_iszero(wo->hisid)) { 10867c478bd9Sstevel@tonic-gate eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); 10877c478bd9Sstevel@tonic-gate if (!eui64_iszero(wo->hisid)) 10887c478bd9Sstevel@tonic-gate wo->opt_remote = 1; 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { 10937c478bd9Sstevel@tonic-gate fatal("local/remote LL address required for demand-dialling\n"); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * ipv6_demand_conf - configure the interface as though 11007c478bd9Sstevel@tonic-gate * IPV6CP were up, for use with dial-on-demand. 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate static int 11037c478bd9Sstevel@tonic-gate ipv6_demand_conf(u) 11047c478bd9Sstevel@tonic-gate int u; 11057c478bd9Sstevel@tonic-gate { 11067c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[u]; 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate #if SIF6UPFIRST 11097c478bd9Sstevel@tonic-gate if (!sif6up(u)) 11107c478bd9Sstevel@tonic-gate return 0; 11117c478bd9Sstevel@tonic-gate #endif 11127c478bd9Sstevel@tonic-gate if (!sif6addr(u, wo->ourid, wo->hisid)) 11137c478bd9Sstevel@tonic-gate return 0; 11147c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST 11157c478bd9Sstevel@tonic-gate if (!sif6up(u)) 11167c478bd9Sstevel@tonic-gate return 0; 11177c478bd9Sstevel@tonic-gate #endif 11187c478bd9Sstevel@tonic-gate if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) 11197c478bd9Sstevel@tonic-gate return 0; 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate notice("local LL address %s", llv6_ntoa(wo->ourid)); 11227c478bd9Sstevel@tonic-gate notice("remote LL address %s", llv6_ntoa(wo->hisid)); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate return 1; 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * ipv6cp_up - IPV6CP has come UP. 11307c478bd9Sstevel@tonic-gate * 11317c478bd9Sstevel@tonic-gate * Configure the IPv6 network interface appropriately and bring it up. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate static void 11347c478bd9Sstevel@tonic-gate ipv6cp_up(f) 11357c478bd9Sstevel@tonic-gate fsm *f; 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 11387c478bd9Sstevel@tonic-gate ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 11397c478bd9Sstevel@tonic-gate ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: up")); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * We must have a non-zero LL address for both ends of the link. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate if (!ho->neg_ifaceid) 11477c478bd9Sstevel@tonic-gate ho->hisid = wo->hisid; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate if(!no_ifaceid_neg) { 11507c478bd9Sstevel@tonic-gate if (eui64_iszero(ho->hisid)) { 11517c478bd9Sstevel@tonic-gate error("Could not determine remote LL address"); 11527c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not determine remote LL address"); 11537c478bd9Sstevel@tonic-gate return; 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate if (eui64_iszero(go->ourid)) { 11567c478bd9Sstevel@tonic-gate error("Could not determine local LL address"); 11577c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not determine local LL address"); 11587c478bd9Sstevel@tonic-gate return; 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate if (eui64_equals(go->ourid, ho->hisid)) { 11617c478bd9Sstevel@tonic-gate error("local and remote LL addresses are equal"); 11627c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "local and remote LL addresses are equal"); 11637c478bd9Sstevel@tonic-gate return; 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 11687c478bd9Sstevel@tonic-gate /* set tcp compression */ 11697c478bd9Sstevel@tonic-gate if (sif6comp(f->unit, ho->neg_vj) != 1) { 11707c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Could not enable TCP compression"); 11717c478bd9Sstevel@tonic-gate return; 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate #endif 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * If we are doing dial-on-demand, the interface is already 11777c478bd9Sstevel@tonic-gate * configured, so we put out any saved-up packets, then set the 11787c478bd9Sstevel@tonic-gate * interface to pass IPv6 packets. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate if (demand) { 11817c478bd9Sstevel@tonic-gate if (! eui64_equals(go->ourid, wo->ourid) || 11827c478bd9Sstevel@tonic-gate ! eui64_equals(ho->hisid, wo->hisid)) { 11837c478bd9Sstevel@tonic-gate if (! eui64_equals(go->ourid, wo->ourid)) 11847c478bd9Sstevel@tonic-gate warn("Local LL address changed to %s", 11857c478bd9Sstevel@tonic-gate llv6_ntoa(go->ourid)); 11867c478bd9Sstevel@tonic-gate if (! eui64_equals(ho->hisid, wo->hisid)) 11877c478bd9Sstevel@tonic-gate warn("Remote LL address changed to %s", 11887c478bd9Sstevel@tonic-gate llv6_ntoa(ho->hisid)); 11897c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid); 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate /* Set the interface to the new addresses */ 11927c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 11937c478bd9Sstevel@tonic-gate if (debug) 11947c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 11957c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 11967c478bd9Sstevel@tonic-gate return; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate demand_rexmit(PPP_IPV6); 12017c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) { 12027c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12037c478bd9Sstevel@tonic-gate return; 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate } else { 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * Set LL addresses 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST 12117c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 12127c478bd9Sstevel@tonic-gate if (debug) 12137c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 12147c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12157c478bd9Sstevel@tonic-gate return; 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate #endif 12187c478bd9Sstevel@tonic-gate #if defined(SOL2) 12197c478bd9Sstevel@tonic-gate /* bring the interface up for IPv6 */ 12207c478bd9Sstevel@tonic-gate if (!sif6up(f->unit)) { 12217c478bd9Sstevel@tonic-gate if (debug) 12227c478bd9Sstevel@tonic-gate warn("sifup failed (IPV6)"); 12237c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12247c478bd9Sstevel@tonic-gate return; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate #else 12277c478bd9Sstevel@tonic-gate if (!sifup(f->unit)) { 12287c478bd9Sstevel@tonic-gate if (debug) 12297c478bd9Sstevel@tonic-gate warn("sifup failed (IPV6)"); 12307c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12317c478bd9Sstevel@tonic-gate return; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate #endif 12347c478bd9Sstevel@tonic-gate #if SIF6UPFIRST 12357c478bd9Sstevel@tonic-gate if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 12367c478bd9Sstevel@tonic-gate if (debug) 12377c478bd9Sstevel@tonic-gate warn("sif6addr failed"); 12387c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12397c478bd9Sstevel@tonic-gate return; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate #endif 12427c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) { 12437c478bd9Sstevel@tonic-gate ipv6cp_close(f->unit, "Interface configuration failed"); 12447c478bd9Sstevel@tonic-gate return; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate notice("local LL address %s", llv6_ntoa(go->ourid)); 12487c478bd9Sstevel@tonic-gate notice("remote LL address %s", llv6_ntoa(ho->hisid)); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate np_up(f->unit, PPP_IPV6); 12527c478bd9Sstevel@tonic-gate ipv6cp_is_up = 1; 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate /* 12557c478bd9Sstevel@tonic-gate * Execute the ipv6-up script, like this: 12567c478bd9Sstevel@tonic-gate * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL 12577c478bd9Sstevel@tonic-gate */ 12587c478bd9Sstevel@tonic-gate script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); 12597c478bd9Sstevel@tonic-gate script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); 12607c478bd9Sstevel@tonic-gate if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { 12617c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_up; 12627c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6UP); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate sys_unblock_proto(PPP_IPV6); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /* 12697c478bd9Sstevel@tonic-gate * ipv6cp_down - IPV6CP has gone DOWN. 12707c478bd9Sstevel@tonic-gate * 12717c478bd9Sstevel@tonic-gate * Take the IPv6 network interface down, clear its addresses 12727c478bd9Sstevel@tonic-gate * and delete routes through it. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate static void 12757c478bd9Sstevel@tonic-gate ipv6cp_down(f) 12767c478bd9Sstevel@tonic-gate fsm *f; 12777c478bd9Sstevel@tonic-gate { 12787c478bd9Sstevel@tonic-gate IPV6CPDEBUG(("ipv6cp: down")); 12797c478bd9Sstevel@tonic-gate update_link_stats(f->unit); 12807c478bd9Sstevel@tonic-gate if (ipv6cp_is_up) { 12817c478bd9Sstevel@tonic-gate ipv6cp_is_up = 0; 12827c478bd9Sstevel@tonic-gate np_down(f->unit, PPP_IPV6); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP 12857c478bd9Sstevel@tonic-gate if (sif6comp(f->unit, 0) != 1) { 12867c478bd9Sstevel@tonic-gate if (debug) 12877c478bd9Sstevel@tonic-gate warn("Failed to disable TCP compression."); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate #endif 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * If we are doing dial-on-demand, set the interface 12937c478bd9Sstevel@tonic-gate * to queue up outgoing packets (for now). 12947c478bd9Sstevel@tonic-gate */ 12957c478bd9Sstevel@tonic-gate if (demand) { 12967c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE) != 1) { 12977c478bd9Sstevel@tonic-gate if (debug) 12987c478bd9Sstevel@tonic-gate warn("Failed to enable queueing on outgoing packets."); 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate } else { 13017c478bd9Sstevel@tonic-gate if (sifnpmode(f->unit, PPP_IPV6, NPMODE_ERROR) != 1) { 13027c478bd9Sstevel@tonic-gate if (debug) 13037c478bd9Sstevel@tonic-gate warn("Could not set interface to drop packets."); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC))) 13067c478bd9Sstevel@tonic-gate #if defined(SOL2) 13077c478bd9Sstevel@tonic-gate if (sif6down(f->unit) != 1) 13087c478bd9Sstevel@tonic-gate warn("Couldn not bring interface down."); 13097c478bd9Sstevel@tonic-gate #else 13107c478bd9Sstevel@tonic-gate if (sifdown(f->unit) != 1) 13117c478bd9Sstevel@tonic-gate warn("Could not bring interface down."); 13127c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */ 13137c478bd9Sstevel@tonic-gate #endif 13147c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(f->unit, 13157c478bd9Sstevel@tonic-gate ipv6cp_gotoptions[f->unit].ourid, 13167c478bd9Sstevel@tonic-gate ipv6cp_hisoptions[f->unit].hisid); 13177c478bd9Sstevel@tonic-gate #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC))) 13187c478bd9Sstevel@tonic-gate if (sifdown(f->unit) != 1) 13197c478bd9Sstevel@tonic-gate warn("Could not bring interface down."); 13207c478bd9Sstevel@tonic-gate #endif 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* Execute the ipv6-down script */ 13247c478bd9Sstevel@tonic-gate if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { 13257c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_down; 13267c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6DOWN); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* 13327c478bd9Sstevel@tonic-gate * ipv6cp_clear_addrs() - clear the interface addresses, routes, 13337c478bd9Sstevel@tonic-gate * proxy neighbour discovery entries, etc. 13347c478bd9Sstevel@tonic-gate */ 13357c478bd9Sstevel@tonic-gate static void 13367c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(unit, ourid, hisid) 13377c478bd9Sstevel@tonic-gate int unit; 13387c478bd9Sstevel@tonic-gate eui64_t ourid; 13397c478bd9Sstevel@tonic-gate eui64_t hisid; 13407c478bd9Sstevel@tonic-gate { 13417c478bd9Sstevel@tonic-gate if (cif6addr(unit, ourid, hisid) != 1) 13427c478bd9Sstevel@tonic-gate warn("Could not clear addresses"); 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate /* 13477c478bd9Sstevel@tonic-gate * ipv6cp_finished - possibly shut down the lower layers. 13487c478bd9Sstevel@tonic-gate */ 13497c478bd9Sstevel@tonic-gate static void 13507c478bd9Sstevel@tonic-gate ipv6cp_finished(f) 13517c478bd9Sstevel@tonic-gate fsm *f; 13527c478bd9Sstevel@tonic-gate { 13537c478bd9Sstevel@tonic-gate np_finished(f->unit, PPP_IPV6); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * ipv6cp_script_done - called when the ipv6-up or ipv6-down script 13597c478bd9Sstevel@tonic-gate * has finished. 13607c478bd9Sstevel@tonic-gate */ 13617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13627c478bd9Sstevel@tonic-gate static void 13637c478bd9Sstevel@tonic-gate ipv6cp_script_done(arg, status) 13647c478bd9Sstevel@tonic-gate void *arg; 13657c478bd9Sstevel@tonic-gate int status; 13667c478bd9Sstevel@tonic-gate { 13677c478bd9Sstevel@tonic-gate ipv6cp_script_pid = 0; 13687c478bd9Sstevel@tonic-gate switch (ipv6cp_script_state) { 13697c478bd9Sstevel@tonic-gate case s_up: 13707c478bd9Sstevel@tonic-gate if (ipv6cp_fsm[0].state != OPENED) { 13717c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_down; 13727c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6DOWN); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate break; 13757c478bd9Sstevel@tonic-gate case s_down: 13767c478bd9Sstevel@tonic-gate if (ipv6cp_fsm[0].state == OPENED) { 13777c478bd9Sstevel@tonic-gate ipv6cp_script_state = s_up; 13787c478bd9Sstevel@tonic-gate ipv6cp_script(_PATH_IPV6UP); 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate break; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * ipv6cp_script - Execute a script with arguments 13877c478bd9Sstevel@tonic-gate * interface-name tty-name speed local-LL remote-LL. 13887c478bd9Sstevel@tonic-gate */ 13897c478bd9Sstevel@tonic-gate static void 13907c478bd9Sstevel@tonic-gate ipv6cp_script(script) 13917c478bd9Sstevel@tonic-gate char *script; 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate char strspeed[32], strlocal[26], strremote[26]; 13947c478bd9Sstevel@tonic-gate char *argv[8]; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate (void) slprintf(strspeed, sizeof (strspeed), "%d", baud_rate); 13977c478bd9Sstevel@tonic-gate (void) strlcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid), 13987c478bd9Sstevel@tonic-gate sizeof (strlocal)); 13997c478bd9Sstevel@tonic-gate (void) strlcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid), 14007c478bd9Sstevel@tonic-gate sizeof (strremote)); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate argv[0] = script; 14037c478bd9Sstevel@tonic-gate argv[1] = ifname; 14047c478bd9Sstevel@tonic-gate argv[2] = devnam; 14057c478bd9Sstevel@tonic-gate argv[3] = strspeed; 14067c478bd9Sstevel@tonic-gate argv[4] = strlocal; 14077c478bd9Sstevel@tonic-gate argv[5] = strremote; 14087c478bd9Sstevel@tonic-gate argv[6] = ipparam; 14097c478bd9Sstevel@tonic-gate argv[7] = NULL; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate static int 14157c478bd9Sstevel@tonic-gate ipv6cp_printpkt(p, plen, printer, arg) 14167c478bd9Sstevel@tonic-gate u_char *p; 14177c478bd9Sstevel@tonic-gate int plen; 14187c478bd9Sstevel@tonic-gate void (*printer) __P((void *, const char *, ...)); 14197c478bd9Sstevel@tonic-gate void *arg; 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate int code, id, len, olen; 14227c478bd9Sstevel@tonic-gate u_char *pstart, *optend; 14237c478bd9Sstevel@tonic-gate u_short cishort; 14247c478bd9Sstevel@tonic-gate eui64_t ifaceid; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate if (plen < HEADERLEN) 14277c478bd9Sstevel@tonic-gate return 0; 14287c478bd9Sstevel@tonic-gate pstart = p; 14297c478bd9Sstevel@tonic-gate GETCHAR(code, p); 14307c478bd9Sstevel@tonic-gate GETCHAR(id, p); 14317c478bd9Sstevel@tonic-gate GETSHORT(len, p); 14327c478bd9Sstevel@tonic-gate if (len < HEADERLEN || len > plen) 14337c478bd9Sstevel@tonic-gate return 0; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate printer(arg, " %s id=0x%x", code_name(code, 1), id); 14377c478bd9Sstevel@tonic-gate len -= HEADERLEN; 14387c478bd9Sstevel@tonic-gate switch (code) { 14397c478bd9Sstevel@tonic-gate case CODE_CONFREQ: 14407c478bd9Sstevel@tonic-gate case CODE_CONFACK: 14417c478bd9Sstevel@tonic-gate case CODE_CONFNAK: 14427c478bd9Sstevel@tonic-gate case CODE_CONFREJ: 14437c478bd9Sstevel@tonic-gate /* print option list */ 14447c478bd9Sstevel@tonic-gate while (len >= 2) { 14457c478bd9Sstevel@tonic-gate GETCHAR(code, p); 14467c478bd9Sstevel@tonic-gate GETCHAR(olen, p); 14477c478bd9Sstevel@tonic-gate p -= 2; 14487c478bd9Sstevel@tonic-gate if (olen < 2 || olen > len) { 14497c478bd9Sstevel@tonic-gate break; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate printer(arg, " <"); 14527c478bd9Sstevel@tonic-gate len -= olen; 14537c478bd9Sstevel@tonic-gate optend = p + olen; 14547c478bd9Sstevel@tonic-gate switch (code) { 14557c478bd9Sstevel@tonic-gate case CI_COMPRESSTYPE: 14567c478bd9Sstevel@tonic-gate if (olen >= CILEN_COMPRESS) { 14577c478bd9Sstevel@tonic-gate p += 2; 14587c478bd9Sstevel@tonic-gate GETSHORT(cishort, p); 14597c478bd9Sstevel@tonic-gate printer(arg, "compress 0x%x", cishort); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate break; 14627c478bd9Sstevel@tonic-gate case CI_IFACEID: 14637c478bd9Sstevel@tonic-gate if (olen == CILEN_IFACEID) { 14647c478bd9Sstevel@tonic-gate p += 2; 14657c478bd9Sstevel@tonic-gate eui64_get(ifaceid, p); 14667c478bd9Sstevel@tonic-gate printer(arg, "addr %s", llv6_ntoa(ifaceid)); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate break; 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate printer(arg, "%8.*B>", optend-p, p); 14717c478bd9Sstevel@tonic-gate p = optend; 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate break; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate case CODE_TERMACK: 14767c478bd9Sstevel@tonic-gate case CODE_TERMREQ: 14777c478bd9Sstevel@tonic-gate if (len > 0 && *p >= ' ' && *p < 0x7f) { 14787c478bd9Sstevel@tonic-gate printer(arg, " "); 14797c478bd9Sstevel@tonic-gate print_string((char *)p, len, printer, arg); 14807c478bd9Sstevel@tonic-gate p += len; 14817c478bd9Sstevel@tonic-gate len = 0; 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate break; 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* print the rest of the bytes in the packet */ 14877c478bd9Sstevel@tonic-gate printer(arg, " %32.*B", len, p); 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate return p - pstart; 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. 14947c478bd9Sstevel@tonic-gate * We don't bring the link up for IP fragments or for TCP FIN packets 14957c478bd9Sstevel@tonic-gate * with no data. 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate #define TCP_HDRLEN 20 14987c478bd9Sstevel@tonic-gate #define TH_FIN 0x01 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate static int 15017c478bd9Sstevel@tonic-gate ipv6_active_pkt(pkt, len) 15027c478bd9Sstevel@tonic-gate u_char *pkt; 15037c478bd9Sstevel@tonic-gate int len; 15047c478bd9Sstevel@tonic-gate { 15057c478bd9Sstevel@tonic-gate u_char *tcp; 1506*f53eecf5SJames Carlson struct in6_addr addr; 1507*f53eecf5SJames Carlson char fromstr[26]; 1508*f53eecf5SJames Carlson char tostr[26]; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate len -= PPP_HDRLEN; 15117c478bd9Sstevel@tonic-gate pkt += PPP_HDRLEN; 1512*f53eecf5SJames Carlson if (len < IP6_HDRLEN) { 1513*f53eecf5SJames Carlson dbglog("IPv6 packet of length %d is not activity", len); 15147c478bd9Sstevel@tonic-gate return 0; 1515*f53eecf5SJames Carlson } 1516*f53eecf5SJames Carlson (void) BCOPY(get_ip6src(pkt), &addr, sizeof (addr)); 1517*f53eecf5SJames Carlson (void) inet_ntop(AF_INET6, &addr, fromstr, 26); 1518*f53eecf5SJames Carlson (void) BCOPY(get_ip6dst(pkt), &addr, sizeof (addr)); 1519*f53eecf5SJames Carlson (void) inet_ntop(AF_INET6, &addr, tostr, 26); 1520*f53eecf5SJames Carlson if (get_ip6nh(pkt) == IPPROTO_FRAGMENT) { 1521*f53eecf5SJames Carlson dbglog("IPv6 fragment from %s->%s is not activity", fromstr, tostr); 15227c478bd9Sstevel@tonic-gate return 0; 1523*f53eecf5SJames Carlson } 1524*f53eecf5SJames Carlson if (get_ip6nh(pkt) != IPPROTO_TCP) { 1525*f53eecf5SJames Carlson info("IPv6 proto %d from %s->%s is activity", get_ip6nh(pkt), fromstr, 1526*f53eecf5SJames Carlson tostr); 15277c478bd9Sstevel@tonic-gate return 1; 1528*f53eecf5SJames Carlson } 1529*f53eecf5SJames Carlson if (len < IP6_HDRLEN + TCP_HDRLEN) { 1530*f53eecf5SJames Carlson dbglog("Bad TCP length %d<%d+%d %s->%s is not activity", len, 1531*f53eecf5SJames Carlson IP6_HDRLEN, TCP_HDRLEN, fromstr, tostr); 15327c478bd9Sstevel@tonic-gate return 0; 1533*f53eecf5SJames Carlson } 15347c478bd9Sstevel@tonic-gate tcp = pkt + IP6_HDRLEN; 15357c478bd9Sstevel@tonic-gate if ((get_tcpflags(tcp) & TH_FIN) != 0 && 1536*f53eecf5SJames Carlson len == IP6_HDRLEN + get_tcpoff(tcp) * 4) { 1537*f53eecf5SJames Carlson dbglog("Empty TCP FIN %s->%s is not activity", fromstr, tostr); 15387c478bd9Sstevel@tonic-gate return 0; 1539*f53eecf5SJames Carlson } 1540*f53eecf5SJames Carlson info("TCP %d data %s%s->%s is activity", len - IP6_HDRLEN - TCP_HDRLEN, 1541*f53eecf5SJames Carlson tcp_flag_decode(get_tcpflags(tcp)), fromstr, tostr); 15427c478bd9Sstevel@tonic-gate return 1; 15437c478bd9Sstevel@tonic-gate } 1544