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 pptp 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 38* ifnet.if_obytes = nb of correct PPP bytes sent 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 "PPTP.h" 71#include "pptp_rfc.h" 72#include "pptp_wan.h" 73 74 75/* ----------------------------------------------------------------------------- 76Definitions 77----------------------------------------------------------------------------- */ 78 79struct pptp_wan { 80 /* first, the ifnet structure... */ 81 struct ppp_link link; /* ppp link structure */ 82 83 /* administrative info */ 84 TAILQ_ENTRY(pptp_wan) next; 85 void *rfc; /* pptp 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 pptp_wan_output(struct ppp_link *link, mbuf_t m); 101static int pptp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data); 102static int pptp_wan_findfreeunit(u_short *freeunit); 103 104/* ----------------------------------------------------------------------------- 105Globals 106----------------------------------------------------------------------------- */ 107 108static TAILQ_HEAD(, pptp_wan) pptp_wan_head; 109 110extern lck_mtx_t *ppp_domain_mutex; 111 112/* ----------------------------------------------------------------------------- 113----------------------------------------------------------------------------- */ 114int pptp_wan_init() 115{ 116 117 TAILQ_INIT(&pptp_wan_head); 118 return 0; 119} 120 121/* ----------------------------------------------------------------------------- 122----------------------------------------------------------------------------- */ 123int pptp_wan_dispose() 124{ 125 126 // don't detach if links are in use 127 if (TAILQ_FIRST(&pptp_wan_head)) 128 return EBUSY; 129 130 return 0; 131} 132 133/* ----------------------------------------------------------------------------- 134detach pptp interface dlil layer 135----------------------------------------------------------------------------- */ 136int pptp_wan_attach(void *rfc, struct ppp_link **link) 137{ 138 int ret; 139 struct pptp_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 pptp_wan *, sizeof(struct pptp_wan), M_TEMP, M_WAITOK); 149 if (!wan) 150 return ENOMEM; 151 152 if (pptp_wan_findfreeunit(&unit)) { 153 FREE(wan, M_TEMP); 154 return ENOMEM; 155 } 156 157 bzero(wan, sizeof(struct pptp_wan)); 158 159 TAILQ_INSERT_TAIL(&pptp_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*)PPTP_NAME; 164 lk->lk_mtu = PPTP_MTU; 165 lk->lk_mru = PPTP_MTU;; 166 lk->lk_type = PPP_TYPE_PPTP; 167 lk->lk_hdrlen = 80; // ??? 168 pptp_rfc_command(rfc, PPTP_CMD_GETBAUDRATE, &lk->lk_baudrate); 169 lk->lk_ioctl = pptp_wan_ioctl; 170 lk->lk_output = pptp_wan_output; 171 lk->lk_unit = unit; 172 lk->lk_support = 0; 173 wan->rfc = rfc; 174 175 ret = ppp_link_attach((struct ppp_link *)wan); 176 if (ret) { 177 IOLog("pptp_wan_attach, error = %d, (ld = %p)\n", ret, wan); 178 TAILQ_REMOVE(&pptp_wan_head, wan, next); 179 FREE(wan, M_TEMP); 180 return ret; 181 } 182 183 //IOLog("pptp_wan_attach, link index = %d, (ld = %p)\n", lk->lk_index, lk); 184 185 *link = lk; 186 187 return 0; 188} 189 190/* ----------------------------------------------------------------------------- 191detach pptp interface dlil layer 192----------------------------------------------------------------------------- */ 193void pptp_wan_detach(struct ppp_link *link) 194{ 195 struct pptp_wan *wan = (struct pptp_wan *)link; 196 197 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 198 199 ppp_link_detach(link); 200 TAILQ_REMOVE(&pptp_wan_head, wan, next); 201 FREE(wan, M_TEMP); 202} 203 204/* ----------------------------------------------------------------------------- 205find a free unit in the interface list 206----------------------------------------------------------------------------- */ 207int pptp_wan_findfreeunit(u_short *freeunit) 208{ 209 struct pptp_wan *wan = TAILQ_FIRST(&pptp_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(&pptp_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 pptp_rfc when data are present 228----------------------------------------------------------------------------- */ 229int pptp_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 nanouptime(&tv); 238 link->lk_last_recv = tv.tv_sec; 239 ppp_link_input(link, m); 240 return 0; 241} 242 243/* ----------------------------------------------------------------------------- 244called from pptp_rfc when xmit is full 245----------------------------------------------------------------------------- */ 246void pptp_wan_xmit_full(struct ppp_link *link) 247{ 248 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 249 250 link->lk_flags |= SC_XMIT_FULL; 251} 252 253/* ----------------------------------------------------------------------------- 254called from pptp_rfc when there is an input error 255----------------------------------------------------------------------------- */ 256void pptp_wan_input_error(struct ppp_link *link) 257{ 258 259 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 260 261 ppp_link_event(link, PPP_LINK_EVT_INPUTERROR, 0); 262} 263 264/* ----------------------------------------------------------------------------- 265called from pptp_rfc when xmit is ok again 266----------------------------------------------------------------------------- */ 267void pptp_wan_xmit_ok(struct ppp_link *link) 268{ 269 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 270 link->lk_flags &= ~SC_XMIT_FULL; 271 ppp_link_event(link, PPP_LINK_EVT_XMIT_OK, 0); 272} 273 274/* ----------------------------------------------------------------------------- 275Process an ioctl request to the ppp interface 276----------------------------------------------------------------------------- */ 277int pptp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data) 278{ 279 //struct pptp_wan *wan = (struct pptp_wan *)link;; 280 int error = 0; 281 282 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 283 284 //LOGDBG(ifp, ("pptp_wan_ioctl, cmd = 0x%x\n", cmd)); 285 286 switch (cmd) { 287 default: 288 error = ENOTSUP; 289 } 290 return error; 291} 292 293/* ----------------------------------------------------------------------------- 294This gets called at splnet from if_ppp.c at various times 295when there is data ready to be sent 296----------------------------------------------------------------------------- */ 297int pptp_wan_output(struct ppp_link *link, mbuf_t m) 298{ 299 struct pptp_wan *wan = (struct pptp_wan *)link; 300 u_int32_t len = mbuf_pkthdr_len(m); // take it now, as output will change the mbuf 301 int err; 302 struct timespec tv; 303 304 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 305 306 if ((err = pptp_rfc_output(wan->rfc, m))) { 307 link->lk_oerrors++; 308 return err; 309 } 310 311 link->lk_opackets++; 312 link->lk_obytes += len; 313 nanouptime(&tv); 314 link->lk_last_xmit = tv.tv_sec; 315 return 0; 316} 317