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* History : 27* 28* Aug 2000 - Christophe Allie - created. 29* 30* Theory of operation : 31* 32* this file implements the pppoe driver for the ppp family 33* 34* it's the responsability of the driver to update the statistics 35* whenever that makes sense 36* ifnet.if_lastchange = a packet is present, a packet starts to be sent 37* ifnet.if_ibytes = nb of correct PPP bytes received (does not include escapes...) 38* ifnet.if_obytes = nb of correct PPP bytes sent (does not include escapes...) 39* ifnet.if_ipackets = nb of PPP packet received 40* ifnet.if_opackets = nb of PPP packet sent 41* ifnet.if_ierrors = nb on input packets in error 42* ifnet.if_oerrors = nb on ouptut packets in error 43* 44----------------------------------------------------------------------------- */ 45 46 47/* ----------------------------------------------------------------------------- 48Includes 49----------------------------------------------------------------------------- */ 50 51#include <sys/param.h> 52#include <sys/systm.h> 53#include <sys/mbuf.h> 54#include <sys/socket.h> 55#include <sys/malloc.h> 56#include <sys/syslog.h> 57#include <sys/sockio.h> 58#include <sys/kernel.h> 59#include <net/if_types.h> 60#include <net/dlil.h> 61#include <kern/clock.h> 62#include <kern/locks.h> 63 64 65 66#include "../../../Family/ppp_domain.h" 67#include "../../../Family/if_ppplink.h" 68#include "../../../Family/ppp_defs.h" 69#include "../../../Family/if_ppp.h" 70#include "PPPoE.h" 71#include "pppoe_rfc.h" 72#include "pppoe_wan.h" 73 74 75/* ----------------------------------------------------------------------------- 76Definitions 77----------------------------------------------------------------------------- */ 78 79struct pppoe_wan { 80 /* first, the ifnet structure... */ 81 struct ppp_link link; /* ppp link structure */ 82 83 /* administrative info */ 84 TAILQ_ENTRY(pppoe_wan) next; 85 void *rfc; /* pppoe protocol structure */ 86 87 /* settings */ 88 89 /* output data */ 90 91 /* input data */ 92 93 /* log purpose */ 94}; 95 96/* ----------------------------------------------------------------------------- 97Forward declarations 98----------------------------------------------------------------------------- */ 99 100static int pppoe_wan_output(struct ppp_link *link, mbuf_t m); 101static int pppoe_wan_ioctl(struct ppp_link *link, u_long cmd, void *data); 102static int pppoe_wan_findfreeunit(u_short *freeunit); 103 104/* ----------------------------------------------------------------------------- 105Globals 106----------------------------------------------------------------------------- */ 107 108static TAILQ_HEAD(, pppoe_wan) pppoe_wan_head; 109 110extern lck_mtx_t *ppp_domain_mutex; 111 112/* ----------------------------------------------------------------------------- 113----------------------------------------------------------------------------- */ 114int pppoe_wan_init() 115{ 116 117 TAILQ_INIT(&pppoe_wan_head); 118 return 0; 119} 120 121/* ----------------------------------------------------------------------------- 122----------------------------------------------------------------------------- */ 123int pppoe_wan_dispose() 124{ 125 126 // don't detach if links are in use 127 if (TAILQ_FIRST(&pppoe_wan_head)) 128 return EBUSY; 129 130 return 0; 131} 132 133/* ----------------------------------------------------------------------------- 134detach pppoe interface dlil layer 135----------------------------------------------------------------------------- */ 136int pppoe_wan_attach(void *rfc, struct ppp_link **link) 137{ 138 int ret; 139 struct pppoe_wan *wan; 140 struct ppp_link *lk; 141 u_short unit; 142 143 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 144 145 // Note : we allocate/find number/insert in queue in that specific order 146 // because of funnels and race condition issues 147 148 MALLOC(wan, struct pppoe_wan *, sizeof(struct pppoe_wan), M_TEMP, M_WAITOK); 149 if (!wan) 150 return ENOMEM; 151 152 if (pppoe_wan_findfreeunit(&unit)) { 153 FREE(wan, M_TEMP); 154 return ENOMEM; 155 } 156 157 bzero(wan, sizeof(struct pppoe_wan)); 158 159 TAILQ_INSERT_TAIL(&pppoe_wan_head, wan, next); 160 lk = (struct ppp_link *) wan; 161 162 // it's time now to register our brand new link 163 lk->lk_name = (u_char*)PPPOE_NAME; 164 lk->lk_mtu = PPPOE_MTU; 165 lk->lk_mru = PPPOE_MTU;; 166 lk->lk_type = PPP_TYPE_PPPoE; 167 lk->lk_hdrlen = 14; // ethernet header len 168 //ld->lk_if.link_lk_baudrate = tp->t_ospeed; 169 lk->lk_ioctl = pppoe_wan_ioctl; 170 lk->lk_output = pppoe_wan_output; 171 lk->lk_unit = unit; 172 lk->lk_support = PPP_LINK_DEL_AC; 173 wan->rfc = rfc; 174 175 ret = ppp_link_attach((struct ppp_link *)wan); 176 if (ret) { 177 IOLog("pppoe_wan_attach, error = %d, (ld = %p)\n", ret, wan); 178 TAILQ_REMOVE(&pppoe_wan_head, wan, next); 179 FREE(wan, M_TEMP); 180 return ret; 181 } 182 183 //IOLog("pppoe_wan_attach, link index = %d, (ld = %p)\n", lk->lk_index, lk); 184 185 *link = lk; 186 187 return 0; 188} 189 190/* ----------------------------------------------------------------------------- 191detach pppoe interface dlil layer 192----------------------------------------------------------------------------- */ 193void pppoe_wan_detach(struct ppp_link *link) 194{ 195 struct pppoe_wan *wan = (struct pppoe_wan *)link; 196 197 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 198 199 ppp_link_detach(link); 200 TAILQ_REMOVE(&pppoe_wan_head, wan, next); 201 FREE(wan, M_TEMP); 202} 203 204/* ----------------------------------------------------------------------------- 205find a free unit in the interface list 206----------------------------------------------------------------------------- */ 207int pppoe_wan_findfreeunit(u_short *freeunit) 208{ 209 struct pppoe_wan *wan = TAILQ_FIRST(&pppoe_wan_head); 210 u_short unit = 0; 211 212 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 213 214 while (wan) { 215 if (wan->link.lk_unit == unit) { 216 unit++; 217 wan = TAILQ_FIRST(&pppoe_wan_head); // restart 218 } 219 else 220 wan = TAILQ_NEXT(wan, next); // continue 221 } 222 *freeunit = unit; 223 return 0; 224} 225 226/* ----------------------------------------------------------------------------- 227called from pppoe_rfc when data are present 228----------------------------------------------------------------------------- */ 229int pppoe_wan_input(struct ppp_link *link, mbuf_t m) 230{ 231 struct timespec tv; 232 233 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 234 235 link->lk_ipackets++; 236 link->lk_ibytes += mbuf_pkthdr_len(m); 237 //getmicrotime(&link->lk_last_recv); 238 nanouptime(&tv); 239 link->lk_last_recv = tv.tv_sec; 240 241 ppp_link_input(link, m); 242 return 0; 243} 244 245/* ----------------------------------------------------------------------------- 246Process an ioctl request to the ppp interface 247----------------------------------------------------------------------------- */ 248int pppoe_wan_ioctl(struct ppp_link *link, u_long cmd, void *data) 249{ 250 //struct pppoe_wan *wan = (struct pppoe_wan *)link;; 251 int error = 0; 252 253 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 254 255 //LOGDBG(ifp, ("pppoe_wan_ioctl, cmd = 0x%x\n", cmd)); 256 257 switch (cmd) { 258 default: 259 error = ENOTSUP; 260 } 261 return error; 262} 263 264/* ----------------------------------------------------------------------------- 265This gets called at splnet from if_ppp.c at various times 266when there is data ready to be sent 267----------------------------------------------------------------------------- */ 268int pppoe_wan_output(struct ppp_link *link, mbuf_t m) 269{ 270 struct pppoe_wan *wan = (struct pppoe_wan *)link; 271 int err; 272 struct timespec tv; 273 274 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 275 276 if ((err = pppoe_rfc_output(wan->rfc, m))) { 277 link->lk_oerrors++; 278 return err; 279 } 280 281 link->lk_opackets++; 282 link->lk_obytes += mbuf_pkthdr_len(m); 283 //getmicrotime(link->lk_last_xmit); 284 nanouptime(&tv); 285 link->lk_last_xmit = tv.tv_sec; 286 return 0; 287} 288