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 ppp domain, which is used to communicate 29* between pppd and the interface/link layer 30* 31----------------------------------------------------------------------------- */ 32 33/* ----------------------------------------------------------------------------- 34Includes 35----------------------------------------------------------------------------- */ 36 37#include <sys/systm.h> 38#include <sys/mbuf.h> 39#include <sys/socket.h> 40#include <sys/syslog.h> 41#include <sys/protosw.h> 42#include <sys/domain.h> 43#include <sys/sysctl.h> 44#include <kern/locks.h> 45#include <net/if.h> 46#include <netinet/in.h> 47 48#include "if_ppplink.h" // public link API 49#include "ppp_domain.h" 50#include "ppp_defs.h" // public ppp values 51#include "if_ppp.h" // public ppp API 52#include "ppp_if.h" 53#include "ppp_link.h" 54 55/* ----------------------------------------------------------------------------- 56Definitions 57----------------------------------------------------------------------------- */ 58 59#define TYPE_IF 1 60#define TYPE_LINK 2 61 62/* ----------------------------------------------------------------------------- 63Forward declarations 64----------------------------------------------------------------------------- */ 65 66int ppp_proto_attach(struct socket *, int, struct proc *); 67int ppp_proto_detach(struct socket *so); 68int ppp_proto_connect(struct socket *, struct sockaddr *, struct proc *); 69int ppp_proto_ioctl(struct socket *, u_long cmd, caddr_t , struct ifnet *, struct proc *); 70int ppp_proto_send(struct socket *, int , struct mbuf * , struct sockaddr *, struct mbuf *, struct proc *); 71 72/* ----------------------------------------------------------------------------- 73Globals 74----------------------------------------------------------------------------- */ 75 76struct domain ppp_domain = 77{ PF_PPP, PPP_NAME, NULL, 78 NULL, NULL, NULL, NULL, NULL, 79 0, 0, 0, 0 80}; 81 82struct pr_usrreqs ppp_usr = 83{ pru_abort_notsupp, pru_accept_notsupp, ppp_proto_attach, pru_bind_notsupp, 84 ppp_proto_connect, pru_connect2_notsupp, ppp_proto_ioctl, ppp_proto_detach, 85 pru_disconnect_notsupp, pru_listen_notsupp, pru_peeraddr_notsupp, 86 pru_rcvd_notsupp, pru_rcvoob_notsupp, ppp_proto_send, 87 pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp, 88 sosend, soreceive, pru_sopoll_notsupp 89}; 90 91struct protosw ppp_proto = 92{ SOCK_RAW, &ppp_domain, PPPPROTO_CTL, PR_ATOMIC|PR_CONNREQUIRED|PR_PROTOLOCK, 93 NULL, NULL, NULL, NULL, 94 NULL, NULL, 95 NULL, NULL, NULL, NULL, &ppp_usr 96}; 97 98u_char pppproto_inited = 0; 99 100lck_mtx_t *ppp_domain_mutex; 101 102SYSCTL_NODE(_net, PF_PPP, ppp, CTLFLAG_RW, 0, ""); 103 104/* ----------------------------------------------------------------------------- 105Initialization function 106----------------------------------------------------------------------------- */ 107int ppp_domain_init() 108{ 109 110 // add domain cannot fail, just add the domain struct to the linked list 111 net_add_domain(&ppp_domain); 112 ppp_domain_mutex = ppp_domain.dom_mtx; 113 ppp_domain.dom_flags = DOM_REENTRANT; // tell dlil not to take our lock 114 115 sysctl_register_oid(&sysctl__net_ppp); 116 117 return 0; 118} 119 120/* ----------------------------------------------------------------------------- 121Initialization function 122----------------------------------------------------------------------------- */ 123int ppp_proto_add() 124{ 125 int ret; 126 127 ret = net_add_proto(&ppp_proto, &ppp_domain); 128 if (ret) { 129 net_del_domain(&ppp_domain); 130 LOGRETURN(ret, ret, "ppp_proto_add : can't add proto to PPP domain, error = 0x%x\n"); 131 } 132 133 pppproto_inited = 1; 134 135 return 0; 136} 137 138/* ----------------------------------------------------------------------------- 139Dispose function 140----------------------------------------------------------------------------- */ 141int ppp_proto_remove() 142{ 143 int ret; 144 145 if (pppproto_inited) { 146 ret = net_del_proto(ppp_proto.pr_type, ppp_proto.pr_protocol, ppp_proto.pr_domain); 147 LOGRETURN(ret, ret, "ppp_domain_terminate : can't del proto from PPP domain, error = 0x%x\n"); 148 pppproto_inited = 0; 149 } 150 151 return 0; 152} 153 154/* ----------------------------------------------------------------------------- 155Dispose function 156----------------------------------------------------------------------------- */ 157int ppp_domain_dispose() 158{ 159 int ret; 160 161 ret = net_del_domain(&ppp_domain); 162 LOGRETURN(ret, ret, "ppp_domain_terminate : can't del PPP domain, error = 0x%x\n"); 163 164 sysctl_unregister_oid(&sysctl__net_ppp); 165 166 return 0; 167} 168 169/* ----------------------------------------------------------------------------- 170Called by socket layer when a new socket is created 171----------------------------------------------------------------------------- */ 172int ppp_proto_attach (struct socket *so, int proto, struct proc *p) 173{ 174 int error = 0; 175 176 //IOLog("ppp_proto_attach, so = %p\n", so); 177 178 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) 179 error = soreserve(so, 8192, 8192); 180 181 return error; 182} 183 184/* ----------------------------------------------------------------------------- 185Called by socket layer when the socket is closed 186----------------------------------------------------------------------------- */ 187int ppp_proto_detach(struct socket *so) 188{ 189 //IOLog("ppp_proto_detach, so = %p\n", so); 190 191 ppp_proto_free(so); 192 return 0; 193} 194 195/* ----------------------------------------------------------------------------- 196Called by socket layer to connect the protocol (PR_CONNREQUIRED) 197----------------------------------------------------------------------------- */ 198int ppp_proto_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 199{ 200 soisconnected(so); 201 return 0; 202} 203 204/* ----------------------------------------------------------------------------- 205Called by socket layer to handle ioctl 206----------------------------------------------------------------------------- */ 207int ppp_proto_ioctl(struct socket *so, u_long cmd, caddr_t data, 208 struct ifnet *ifp, struct proc *p) 209{ 210 int error = 0; 211 u_int16_t unit; 212 u_int32_t data_aligned; 213 214 //IOLog("ppp_proto_control : so = %p, cmd = %d\n", so, cmd); 215 216 switch (cmd) { 217 case PPPIOCNEWUNIT: 218 // this ioctl must be done before connecting the socket 219 //IOLog("ppp_proto_control : PPPIOCNEWUNIT\n"); 220 memcpy(&data_aligned, data, sizeof(u_int32_t)); // Wcast-align fix - memcpy for unaligned move 221 unit = data_aligned; 222 error = ppp_if_attach(&unit); 223 if (error) 224 return error; 225 data_aligned = unit; 226 memcpy(data, &data_aligned, sizeof(u_int32_t)); // Wcast-align fix - memcpy for unaligned move 227 // no break; PPPIOCNEWUNIT implicitlty attach the client 228 229 case PPPIOCATTACH: 230 //IOLog("ppp_proto_control : PPPIOCATTACH\n"); 231 memcpy(&data_aligned, data, sizeof(u_int32_t)); // Wcast-align fix - memcpy for unaligned move 232 unit = data_aligned; 233 error = ppp_if_attachclient(unit, so, (ifnet_t *)&so->so_pcb); 234 if (!error) 235 so->so_tpcb = (caddr_t)TYPE_IF; 236 break; 237 238 case PPPIOCATTCHAN: 239 //IOLog("ppp_proto_control : PPPIOCATTCHAN\n"); 240 memcpy(&data_aligned, data, sizeof(u_int32_t)); // Wcast-align fix - memcpy for unaligned move 241 unit = data_aligned; 242 error = ppp_link_attachclient(unit, so, (struct ppp_link **)&so->so_pcb); 243 if (!error) 244 so->so_tpcb = (caddr_t)TYPE_LINK; 245 break; 246 247 case PPPIOCDETACH: 248 //IOLog("ppp_proto_control : PPPIOCDETACH\n"); 249 ppp_proto_free(so); 250 break; 251 252 default: 253 switch ((uintptr_t)so->so_tpcb) { 254 case TYPE_IF: 255 error = ppp_if_control((ifnet_t)so->so_pcb, cmd, data); 256 break; 257 case TYPE_LINK: 258 error = ppp_link_control((struct ppp_link *)so->so_pcb, cmd, data); 259 break; 260 default: 261 error = EINVAL; 262 } 263 } 264 265 return error; 266} 267 268/* ----------------------------------------------------------------------------- 269Called by socket layer to send data out 270----------------------------------------------------------------------------- */ 271int ppp_proto_send(struct socket *so, int flags, struct mbuf *m, 272 struct sockaddr *nam, struct mbuf *control, struct proc *p) 273{ 274 int error = 0; 275 276 switch ((uintptr_t)so->so_tpcb) { 277 case TYPE_IF: 278 error = ppp_if_send((ifnet_t)so->so_pcb, (mbuf_t)m); 279 break; 280 case TYPE_LINK: 281 error = ppp_link_send((struct ppp_link *)so->so_pcb, (mbuf_t)m); 282 break; 283 default: 284 error = EINVAL; 285 if (m) 286 mbuf_freem((mbuf_t)m); 287 } 288 if (control) 289 mbuf_freem((mbuf_t)control); 290 return error; 291} 292 293/* ----------------------------------------------------------------------------- 294called from ppp_if or ppp_link when data struct disappears 295----------------------------------------------------------------------------- */ 296void ppp_proto_free(void *data) 297{ 298 struct socket *so = (struct socket *)data; 299 300 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 301 302 if (!so) 303 return; 304 305 switch ((uintptr_t)so->so_tpcb) { 306 case TYPE_IF: 307 ppp_if_detachclient((ifnet_t)so->so_pcb, so); 308 break; 309 case TYPE_LINK: 310 ppp_link_detachclient((struct ppp_link *)so->so_pcb, so); 311 break; 312 } 313 so->so_pcb = 0; 314 so->so_tpcb = 0; 315 so->so_flags |= SOF_PCBCLEARING; 316} 317 318/* ----------------------------------------------------------------------------- 319called from ppp_link when data are present 320----------------------------------------------------------------------------- */ 321int ppp_proto_input(void *data, mbuf_t m) 322{ 323 struct socket *so = (struct socket *)data; 324 325 lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); 326 327 //IOLog("ppp_proto_input, so = %p, len = %d\n", pcb->socket, m->m_pkthdr.len); 328 329 // use this flag to be sure the app receive packets with End OF Record 330 mbuf_setflags(m, mbuf_flags(m) | MBUF_EOR); 331 332 // if there is no pppd attached yet, or if buffer is full, free the packet 333 if (!so || sbspace(&so->so_rcv) < mbuf_pkthdr_len(m)) { 334 if (so) 335 IOLog("ppp_proto_input no space, so = %p, len = %d\n", so, mbuf_pkthdr_len(m)); 336 mbuf_freem(m); 337 return 0; 338 } 339 340// IOLog("----------- ppp_proto_input, link %d, packet %x %x %x %x %x %x %x %x \n", *(u_short *)p, p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); 341 342 sbappendrecord(&so->so_rcv, (struct mbuf*)m); 343 sorwakeup(so); 344 return 0; 345} 346 347 348/* ----------------------------------------------------------------------------- 349queue utilities 350----------------------------------------------------------------------------- */ 351int ppp_qfull(struct pppqueue *pppq) 352{ 353 return pppq->len >= pppq->maxlen; 354} 355 356void ppp_drop(struct pppqueue *pppq) 357{ 358 pppq->drops++; 359} 360 361void ppp_enqueue(struct pppqueue *pppq, mbuf_t m) 362{ 363 mbuf_setnextpkt(m, 0); 364 if (pppq->tail == 0) 365 pppq->head = m; 366 else 367 mbuf_setnextpkt(pppq->tail, m); 368 pppq->tail = m; 369 pppq->len++; 370} 371 372mbuf_t ppp_dequeue(struct pppqueue *pppq) 373{ 374 mbuf_t m = pppq->head; 375 if (m) { 376 if ((pppq->head = mbuf_nextpkt(m)) == 0) 377 pppq->tail = 0; 378 mbuf_setnextpkt(m, 0); 379 pppq->len--; 380 } 381 return m; 382} 383 384void ppp_prepend(struct pppqueue *pppq, mbuf_t m) 385{ 386 mbuf_setnextpkt(m, pppq->head); 387 if (pppq->tail == 0) 388 pppq->tail = m; 389 pppq->head = m; 390 pppq->len++; 391} 392 393