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* Feb 2001 - Christophe Allie - created. 29* 30* Theory of operation : 31* 32* this file implements the link operations for ppp 33* 34----------------------------------------------------------------------------- */ 35 36 37 38/* ----------------------------------------------------------------------------- 39Includes 40----------------------------------------------------------------------------- */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/mbuf.h> 45#include <sys/socket.h> 46#include <sys/malloc.h> 47#include <sys/syslog.h> 48#include <sys/sockio.h> 49#include <kern/locks.h> 50#include <net/if_types.h> 51#include <net/if.h> 52#include <netinet/in.h> 53 54#include "ppp_defs.h" // public ppp values 55#include "if_ppp.h" // public ppp API 56#include "if_ppplink.h" // public link API 57#include "ppp_domain.h" 58#include "ppp_if.h" 59 60/* ----------------------------------------------------------------------------- 61Definitions 62----------------------------------------------------------------------------- */ 63 64/* Macro facilities */ 65 66#define LKIFNET(lk) (((struct ppp_link *)lk)->lk_ifnet) 67#define LKNAME(lk) (((struct ppp_link*)lk)->lk_name) 68#define LKUNIT(lk) (((struct ppp_link*)lk)->lk_unit) 69 70#define LKIFFDEBUG(lk) (LKIFNET(lk) ? ifnet_flags(LKIFNET(lk)) & IFF_DEBUG : 0 ) 71#define LKIFNAME(lk) (LKIFNET(lk) ? ifnet_name(LKIFNET(lk)) : "???") 72#define LKIFUNIT(lk) (LKIFNET(lk) ? ifnet_unit(LKIFNET(lk)) : 0) 73 74#define LOGLKDBG(lk, text) \ 75 if (LKIFNET(lk) && (ifnet_flags(LKIFNET(lk)) & IFF_DEBUG)) { \ 76 IOLog text; \ 77 } 78 79/* 80 As the private structure contains only one field, 81 there is no need for an extra malloc . 82 Can be changed later, if we need to keep 83 more information in the private structure. 84*/ 85#ifdef USE_PRIVATE_STRUCT 86/* Link private data structure */ 87struct ppp_priv { 88 void *host; /* our client structure */ 89}; 90#endif 91 92/* ----------------------------------------------------------------------------- 93Forward declarations 94----------------------------------------------------------------------------- */ 95 96 97 98/* ----------------------------------------------------------------------------- 99Globals 100----------------------------------------------------------------------------- */ 101 102static TAILQ_HEAD(, ppp_link) ppp_link_head; 103extern lck_mtx_t *ppp_domain_mutex; 104 105/* ----------------------------------------------------------------------------- 106----------------------------------------------------------------------------- */ 107int ppp_link_init() 108{ 109 TAILQ_INIT(&ppp_link_head); 110 111 return 0; 112} 113 114/* ----------------------------------------------------------------------------- 115----------------------------------------------------------------------------- */ 116int ppp_link_dispose() 117{ 118 // can't dispose if serial lines are in use 119 if (TAILQ_FIRST(&ppp_link_head)) 120 return EBUSY; 121 122 return 0; 123} 124 125/* ----------------------------------------------------------------------------- 126find a free unit in the interface list 127----------------------------------------------------------------------------- */ 128u_short ppp_link_findfreeindex() 129{ 130 struct ppp_link *link = TAILQ_FIRST(&ppp_link_head); 131 u_short index = 0; 132 133 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 134 135 while (link) { 136 if (link->lk_index == index) { 137 index++; 138 link = TAILQ_FIRST(&ppp_link_head); // restart 139 } 140 else 141 link = TAILQ_NEXT(link, lk_next); // continue 142 } 143 return index; 144} 145 146/* ----------------------------------------------------------------------------- 147Attach a link 148----------------------------------------------------------------------------- */ 149int ppp_link_attach(struct ppp_link *link) 150{ 151#ifdef USE_PRIVATE_STRUCT 152 struct ppp_priv *priv; 153#endif 154 155 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 156 157 if (!link->lk_ioctl || !link->lk_output) { 158 return EINVAL; 159 } 160 161#ifdef USE_PRIVATE_STRUCT 162 MALLOC(priv, struct ppp_priv *, sizeof(struct ppp_priv), M_TEMP, M_WAITOK); 163 if (!priv) 164 return ENOMEM; 165 166 bzero(priv, sizeof(struct ppp_priv)); 167 link->lk_ppp_private = priv; 168#else 169 link->lk_ppp_private = 0; 170#endif 171 link->lk_ifnet = 0; 172 link->lk_index = ppp_link_findfreeindex(); 173 TAILQ_INSERT_TAIL(&ppp_link_head, link, lk_next); 174 175 return 0; 176} 177 178/* ----------------------------------------------------------------------------- 179Detach a link 180----------------------------------------------------------------------------- */ 181int ppp_link_detach(struct ppp_link *link) 182{ 183#ifdef USE_PRIVATE_STRUCT 184 struct ppp_priv *priv = (struct ppp_priv *)link->lk_ppp_private; 185#endif 186 187 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 188 189 LOGLKDBG(link, ("ppp_link_detach : (link = %s%d)\n", LKNAME(link), LKUNIT(link))); 190 ppp_if_detachlink(link); 191#ifdef USE_PRIVATE_STRUCT 192 ppp_proto_free(priv->host); 193 FREE(priv, M_TEMP); 194#else 195 ppp_proto_free(link->lk_ppp_private); 196#endif 197 TAILQ_REMOVE(&ppp_link_head, link, lk_next); 198 link->lk_ppp_private = 0; 199 return 0; 200} 201 202/* ----------------------------------------------------------------------------- 203----------------------------------------------------------------------------- */ 204int ppp_link_event(struct ppp_link *link, u_int32_t event, void *data) 205{ 206 207 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 208 209 switch (event) { 210 case PPP_LINK_EVT_XMIT_OK: 211 if (link->lk_ifnet) 212 ppp_if_xmit(link->lk_ifnet, 0); 213 break; 214 case PPP_LINK_EVT_INPUTERROR: 215 if (link->lk_ifnet) 216 ppp_if_error(link->lk_ifnet); 217 break; 218 } 219 return 0; 220} 221 222/* ----------------------------------------------------------------------------- 223----------------------------------------------------------------------------- */ 224int ppp_link_input(struct ppp_link *link, mbuf_t m) 225{ 226#ifdef USE_PRIVATE_STRUCT 227 struct ppp_priv *priv = (struct ppp_priv *)link->lk_ppp_private; 228#endif 229 u_char *p; 230 u_int16_t proto, len; 231 232 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 233 234 if (link->lk_ifnet && (ifnet_flags(link->lk_ifnet) & PPP_LOG_INPKT)) 235 ppp_link_logmbuf(link, "ppp_link_input", m); 236 237 if (mbuf_len(m) < PPP_HDRLEN && 238 mbuf_pullup(&m, PPP_HDRLEN)) { 239 if (m) { 240 mbuf_freem(m); 241 m = NULL; 242 } 243 IOLog("ppp_link_input: cannot pullup header\n"); 244 return 0; 245 } 246 247 p = mbuf_data(m); // no alignment issue as p is *uchar. 248 if ((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI)) { 249 mbuf_adj(m, 2); 250 p = mbuf_data(m); 251 } 252 proto = p[0]; 253 len = 1; 254 if (!(proto & 0x1)) { // lowest bit set for lowest byte of protocol 255 proto = (proto << 8) + p[1]; 256 len = 2; 257 } 258 259 if (link->lk_ifnet && (proto < 0xC000)) { 260 ppp_if_input(link->lk_ifnet, m, proto, len); // Network protocol 261 } 262 else { 263#ifdef USE_PRIVATE_STRUCT 264 ppp_proto_input(priv->host, m); // LCP/Auth/unexpected network protocol 265#else 266 ppp_proto_input(link->lk_ppp_private, m);// LCP/Auth/unexpected network protocol 267#endif 268 } 269 return 0; 270} 271 272/* ----------------------------------------------------------------------------- 273----------------------------------------------------------------------------- */ 274int ppp_link_control(struct ppp_link *link, u_long cmd, void *data) 275{ 276 int error = 0; 277 u_int32_t flags, mru; 278 279 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 280 281 switch (cmd) { 282 case PPPIOCCONNECT: 283 LOGLKDBG(link, ("ppp_link_control : PPPIOCCONNECT, (link = %s%d), attach to interface = %d \n", 284 LKNAME(link), LKUNIT(link), *(u_int32_t *)data)); 285 error = ppp_if_attachlink(link, *(u_int32_t *)data); 286 break; 287 case PPPIOCDISCONN: 288 LOGLKDBG(link, ("ppp_link_control : PPPIOCDISCONN, (link = %s%d), detach from interface = %s%d \n", 289 LKNAME(link), LKUNIT(link), LKIFNAME(link), LKIFUNIT(link))); 290 error = ppp_if_detachlink(link); 291 break; 292 default: 293 error = ENOTSUP; 294 } 295 if (error != ENOTSUP) 296 return error; 297 298 error = (*link->lk_ioctl)(link, cmd, data); 299 if (error != ENOTSUP) 300 return error; 301 302 error = 0; 303 switch (cmd) { 304 305 case PPPIOCGFLAGS: 306 LOGLKDBG(link, ("ppp_link_control: (link = %s%d), PPPIOCGFLAGS = 0x%x\n", 307 LKNAME(link), LKUNIT(link), link->lk_flags)); 308 *(u_int32_t *)data = link->lk_flags; 309 break; 310 311 case PPPIOCSFLAGS: 312 LOGLKDBG(link, ("ppp_link_control: (link = %s%d), PPPIOCSFLAGS = 0x%x\n", 313 LKNAME(link), LKUNIT(link), *(u_int32_t *)data & SC_MASK)); 314 flags = *(u_int32_t *)data & SC_MASK; 315 link->lk_flags = (link->lk_flags & ~SC_MASK) | flags; 316 break; 317 318 case PPPIOCGMRU: 319 LOGLKDBG(link, ("ppp_link_control: (link = %s%d), PPPIOCGMRU = 0x%x\n", 320 LKNAME(link), LKUNIT(link), link->lk_mru)); 321 *(u_int32_t *)data = link->lk_mru; 322 break; 323 324 case PPPIOCSMRU: 325 LOGLKDBG(link, ("ppp_link_control: (link = %s%d), PPPIOCSMRU = 0x%x\n", 326 LKNAME(link), LKUNIT(link), *(u_int32_t *)data)); 327 mru = *(u_int32_t *)data; 328 link->lk_mru = mru; 329 break; 330 331 332 case PPPIOCSASYNCMAP: 333 case PPPIOCSRASYNCMAP: 334 case PPPIOCSXASYNCMAP: 335 case PPPIOCGASYNCMAP: 336 case PPPIOCGRASYNCMAP: 337 case PPPIOCGXASYNCMAP: 338 if ((link->lk_support & PPP_LINK_ASYNC) == 0) 339 error = EINVAL; // async link must support these ioctls 340 break; 341 342 343 default: 344 error = EINVAL; 345 } 346 return error; 347} 348 349/* ----------------------------------------------------------------------------- 350----------------------------------------------------------------------------- */ 351int ppp_link_attachclient(u_short index, void *host, struct ppp_link **data) 352{ 353 struct ppp_link *link; 354#ifdef USE_PRIVATE_STRUCT 355 struct ppp_priv *priv; 356#endif 357 358 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 359 360 TAILQ_FOREACH(link, &ppp_link_head, lk_next) { 361 if (link->lk_index == index) { 362 *data = (void *)link; 363#ifdef USE_PRIVATE_STRUCT 364 priv = (struct ppp_priv *)link->lk_ppp_private; 365 if (priv->host) 366 return EBUSY; /* a client is already attached */ 367 priv->host = host; 368#else 369 if (link->lk_ppp_private) 370 return EBUSY; /* a client is already attached */ 371 link->lk_ppp_private = host; 372#endif 373 return 0; 374 } 375 } 376 return ENODEV; 377} 378 379/* ----------------------------------------------------------------------------- 380----------------------------------------------------------------------------- */ 381void ppp_link_detachclient(struct ppp_link *link, void *host) 382{ 383#ifdef USE_PRIVATE_STRUCT 384 struct ppp_priv *priv = (struct ppp_priv *)link->lk_ppp_private; 385 386 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 387 388 if (priv && (priv->host == host)) 389 priv->host = 0; 390#else 391 if (link->lk_ppp_private == host) 392 link->lk_ppp_private = 0; 393#endif 394} 395 396/* ----------------------------------------------------------------------------- 397we wend packet without link framing (FF03) 398it's the reponsability of the driver to add the header, it the links need it. 399it should be done accordingly to the ppp negociation as well. 400----------------------------------------------------------------------------- */ 401int ppp_link_send(struct ppp_link *link, mbuf_t m) 402{ 403 u_char *p = mbuf_data(m); // no alignment issue as p is *uchar. 404 u_int16_t proto = ((u_int16_t)p[0] << 8) + p[1]; 405 406 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 407 408 // if pcomp has been negociated, remove leading 0 byte 409 if ((link->lk_flags & SC_COMP_PROT) && !p[0]) { 410 mbuf_adj(m, 1); 411 } 412 413 // if accomp has not been negociated, or if the needs FF03, add the header 414 if (!(link->lk_support & PPP_LINK_DEL_AC)) { 415 if ((proto == PPP_LCP) 416 || !(link->lk_flags & SC_COMP_AC)) { 417 418 if (mbuf_prepend(&m, 2, MBUF_DONTWAIT) != 0) 419 return ENOBUFS; 420 421 p = mbuf_data(m); 422 p[0] = PPP_ALLSTATIONS; 423 p[1] = PPP_UI; 424 } 425 } 426 427 if (link->lk_ifnet && (ifnet_flags(link->lk_ifnet) & PPP_LOG_OUTPKT)) 428 ppp_link_logmbuf(link, "ppp_link_send", m); 429 430 /* link level packet are send oot of band */ 431 if ((proto >= 0xC000) && 432 (link->lk_support & PPP_LINK_OOB_QUEUE)) 433 mbuf_settype(m, MBUF_TYPE_OOBDATA); 434 435 return (*link->lk_output)(link, m); 436} 437 438/* ----------------------------------------------------------------------------- 439----------------------------------------------------------------------------- */ 440void ppp_link_logmbuf(struct ppp_link *link, char *msg, mbuf_t m) 441{ 442 int i, lcount, copycount, count; 443 char lbuf[16], *data; 444 445 if (m == NULL) 446 return; 447 448 IOLog("%s: [ifnet = %s%d] [link = %s%d]\n", msg, 449 LKIFNAME(link), LKIFUNIT(link), LKNAME(link), LKUNIT(link)); 450 451 for (count = mbuf_len(m), data = mbuf_data(m); m != NULL; ) { // no alignment issue as data is *uchar. 452 /* build a line of output */ 453 for(lcount = 0; lcount < sizeof(lbuf); lcount += copycount) { 454 if (!count) { 455 m = mbuf_next(m); 456 if (m == NULL) 457 break; 458 count = mbuf_len(m); 459 data = mbuf_data(m); 460 } 461 copycount = (count > sizeof(lbuf) - lcount) ? sizeof(lbuf) - lcount : count; 462 bcopy(data, &lbuf[lcount], copycount); 463 data += copycount; 464 count -= copycount; 465 } 466 467 /* output line (hex 1st, then ascii) */ 468 IOLog("%s: 0x ", msg); 469 for(i = 0; i < lcount; i++) { 470 if (i == 8) IOLog(" "); 471 IOLog("%02x ", (u_char)lbuf[i]); 472 } 473 for( ; i < sizeof(lbuf); i++) { 474 if (i == 8) IOLog(" "); 475 IOLog(" "); 476 } 477 IOLog(" '"); 478 for(i = 0; i < lcount; i++) 479 IOLog("%c",(lbuf[i]>=040 && lbuf[i]<=0176)?lbuf[i]:'.'); 480 IOLog("'\n"); 481 } 482} 483 484