1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/* -----------------------------------------------------------------------------
25 *
26 *  Theory of operation :
27 *
28 *  This file implements the ip protocol module for the ppp interface
29 *
30----------------------------------------------------------------------------- */
31
32/* -----------------------------------------------------------------------------
33Includes
34----------------------------------------------------------------------------- */
35
36#include <sys/param.h>
37#include <sys/mbuf.h>
38#include <sys/socket.h>
39#include <sys/syslog.h>
40#include <sys/systm.h>
41#include <sys/malloc.h>
42#include <sys/sockio.h>
43#include <kern/locks.h>
44
45#include <net/if.h>
46#include <net/kpi_protocol.h>
47
48#include <netinet/in.h>
49#include <netinet/in_systm.h>
50#include <netinet/in_var.h>
51#include <netinet/ip.h>
52
53#include "ppp_defs.h"		// public ppp values
54#include "ppp_ipv6.h"
55#include "ppp_domain.h"
56#include "ppp_if.h"
57#include "if_ppplink.h"
58
59
60/* -----------------------------------------------------------------------------
61Definitions
62----------------------------------------------------------------------------- */
63
64/* -----------------------------------------------------------------------------
65Forward declarations
66----------------------------------------------------------------------------- */
67
68static errno_t ppp_ipv6_input(ifnet_t ifp, protocol_family_t protocol,
69									 mbuf_t packet, char* header);
70static errno_t ppp_ipv6_preoutput(ifnet_t ifp, protocol_family_t protocol,
71									mbuf_t *packet, const struct sockaddr *dest,
72									void *route, char *frame_type, char *link_layer_dest);
73static errno_t ppp_ipv6_ioctl(ifnet_t ifp, protocol_family_t protocol,
74									 u_long command, void* argument);
75
76
77/* -----------------------------------------------------------------------------
78Globals
79----------------------------------------------------------------------------- */
80extern lck_mtx_t	*ppp_domain_mutex;
81
82/* -----------------------------------------------------------------------------
83init function
84----------------------------------------------------------------------------- */
85int ppp_ipv6_init(int init_arg)
86{
87	return proto_register_plumber(PF_INET6, APPLE_IF_FAM_PPP, ppp_ipv6_attach, ppp_ipv6_detach);
88}
89
90/* -----------------------------------------------------------------------------
91terminate function
92----------------------------------------------------------------------------- */
93int ppp_ipv6_dispose(int term_arg)
94{
95	proto_unregister_plumber(PF_INET6, APPLE_IF_FAM_PPP);
96	return 0;
97}
98
99/* -----------------------------------------------------------------------------
100attach the PPPx interface ifp to the network protocol IPv6,
101called when the ppp interface is ready for ppp traffic
102----------------------------------------------------------------------------- */
103errno_t ppp_ipv6_attach(ifnet_t ifp, protocol_family_t protocol)
104{
105    int					ret;
106    struct ifnet_attach_proto_param   reg;
107    struct ppp_if		*wan = (struct ppp_if *)ifnet_softc(ifp);
108
109    LOGDBG(ifp, ("ppp_ipv6_attach: name = %s, unit = %d\n", ifnet_name(ifp), ifnet_unit(ifp)));
110
111    if (wan->ipv6_attached)
112        return 0;	// already attached
113
114    bzero(&reg, sizeof(struct ifnet_attach_proto_param));
115
116	reg.input = ppp_ipv6_input;
117	reg.pre_output = ppp_ipv6_preoutput;
118	reg.ioctl = ppp_ipv6_ioctl;
119	ret = ifnet_attach_protocol(ifp, PF_INET6, &reg);
120    LOGRETURN(ret, ret, "ppp_ipv6_attach: ifnet_attach_protocol error = 0x%x\n");
121
122    LOGDBG(ifp, ("ppp_ipv6_attach: ifnet_attach_protocol family = 0x%x\n", protocol));
123    wan->ipv6_attached = 1;
124
125    return 0;
126}
127
128/* -----------------------------------------------------------------------------
129detach the PPPx interface ifp from the network protocol IPv6,
130called when the ppp interface stops ip traffic
131----------------------------------------------------------------------------- */
132void ppp_ipv6_detach(ifnet_t ifp, protocol_family_t protocol)
133{
134    int 		ret;
135    struct ppp_if		*wan = (struct ppp_if *)ifnet_softc(ifp);
136
137    LOGDBG(ifp, ("ppp_ipv6_detach\n"));
138
139    if (!wan->ipv6_attached)
140        return;	// already detached
141
142    ret = ifnet_detach_protocol(ifp, PF_INET6);
143	if (ret)
144        IOLog("ppp_ipv6_detach: ifnet_detach_protocol error = 0x%x\n", ret);
145
146    wan->ipv6_attached = 0;
147}
148
149/* -----------------------------------------------------------------------------
150called from dlil when an ioctl is sent to the interface
151----------------------------------------------------------------------------- */
152errno_t ppp_ipv6_ioctl(ifnet_t ifp, protocol_family_t protocol,
153									 u_long command, void* argument)
154{
155    struct sockaddr_in6  addr6;
156    int 		error = 0;
157
158    switch (command) {
159
160        case SIOCSIFADDR:
161        case SIOCAIFADDR:
162            LOGDBG(ifp, ("ppp_ipv6_ioctl: cmd = SIOCSIFADDR/SIOCAIFADDR\n"));
163
164	    error = ifaddr_address(argument, (struct sockaddr *)&addr6, sizeof (addr6));
165	    if (error != 0) {
166                error = EAFNOSUPPORT;
167                break;
168	    }
169
170            // only an IPv6 address should arrive here
171            if (addr6.sin6_family != AF_INET6) {
172                error = EAFNOSUPPORT;
173                break;
174            }
175            break;
176
177        default :
178            error = EOPNOTSUPP;
179    }
180
181    return error;
182}
183
184/* -----------------------------------------------------------------------------
185called from dlil when a packet from the interface is to be dispatched to
186the specific network protocol attached by dl_tag.
187the network protocol has been determined earlier by the demux function.
188the packet is in the mbuf chain m without
189the frame header, which is provided separately. (not used)
190----------------------------------------------------------------------------- */
191errno_t ppp_ipv6_input(ifnet_t ifp, protocol_family_t protocol,
192									 mbuf_t packet, char* header)
193{
194    LOGMBUF("ppp_ipv6_input", packet);
195
196	if (proto_input(PF_INET6, packet))
197		mbuf_freem(packet);
198
199	return 0;
200}
201
202/* -----------------------------------------------------------------------------
203pre_output function
204----------------------------------------------------------------------------- */
205errno_t ppp_ipv6_preoutput(ifnet_t ifp, protocol_family_t protocol,
206									mbuf_t *packet, const struct sockaddr *dest,
207									void *route, char *frame_type, char *link_layer_dest)
208{
209    u_int16_t ftype = PPP_IPV6;
210
211    LOGMBUF("ppp_ipv6_preoutput", *packet);
212
213    memcpy(frame_type, &ftype, sizeof(u_int16_t));
214    return 0;
215}
216
217