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/* ----------------------------------------------------------------------------- 25includes 26----------------------------------------------------------------------------- */ 27#include <string.h> 28#include <stdio.h> 29#include <sys/errno.h> 30#include <sys/signal.h> 31#include <sys/types.h> 32#include <sys/socket.h> 33#include <sys/stat.h> 34#include <sys/un.h> 35#include <unistd.h> 36#include <sys/param.h> 37#include <sys/fcntl.h> 38#include <sys/ucred.h> 39#include <CoreFoundation/CoreFoundation.h> 40#include <SystemConfiguration/SystemConfiguration.h> 41 42#include <SystemConfiguration/SCPrivate.h> // for SCLog() 43 44#include "ppp_msg.h" 45#include "scnc_main.h" 46#include "ppp_privmsg.h" 47#include "scnc_client.h" 48#include "ppp_manager.h" 49#include "ppp_option.h" 50#include "ppp_socket_server.h" 51#include "scnc_utils.h" 52 53/* ----------------------------------------------------------------------------- 54definitions 55----------------------------------------------------------------------------- */ 56 57enum { 58 do_nothing = 0, 59 do_process, 60 do_close, 61 do_error 62}; 63 64 65/* ----------------------------------------------------------------------------- 66forward declarations 67----------------------------------------------------------------------------- */ 68 69static void socket_status (struct client *client, struct msg *msg, void **reply); 70static void socket_extendedstatus (struct client *client, struct msg *msg, void **reply); 71static void socket_connect (struct client *client, struct msg *msg, void **reply); 72static void socket_disconnect (struct client *client, struct msg *msg, void **reply); 73static void socket_suspend (struct client *client, struct msg *msg, void **reply); 74static void socket_resume (struct client *client, struct msg *msg, void **reply); 75static void socket_getconnectdata (struct client *client, struct msg *msg, void **reply); 76static void socket_enable_event (struct client *client, struct msg *msg, void **reply); 77static void socket_disable_event (struct client *client, struct msg *msg, void **reply); 78static void socket_version (struct client *client, struct msg *msg, void **reply); 79static void socket_getnblinks (struct client *client, struct msg *msg, void **reply); 80static void socket_getlinkbyindex (struct client *client, struct msg *msg, void **reply); 81static void socket_getlinkbyserviceid (struct client *client, struct msg *msg, void **reply); 82static void socket_getlinkbyifname (struct client *client, struct msg *msg, void **reply); 83static void socket_setoption (struct client *client, struct msg *msg, void **reply); 84static void socket_getoption (struct client *client, struct msg *msg, void **reply); 85 86static void socket_pppd_event(struct client *client, struct msg *msg); 87static void socket_pppd_status(struct client *client, struct msg *msg); 88static void socket_pppd_phase(struct client *client, struct msg *msg); 89 90 91 92static void processRequest (struct client *client, struct msg *msg); 93 94static void listenCallBack(CFSocketRef s, CFSocketCallBackType type, 95 CFDataRef address, const void *data, void *info); 96static void clientCallBack(CFSocketRef s, CFSocketCallBackType type, 97 CFDataRef address, const void *data, void *info); 98 99 100 101/* ----------------------------------------------------------------------------- 102globals 103----------------------------------------------------------------------------- */ 104 105extern TAILQ_HEAD(, service) service_head; 106 107/* ----------------------------------------------------------------------------- 108----------------------------------------------------------------------------- */ 109int ppp_socket_start_server () 110{ 111 struct sockaddr_un addr; 112 int error, s; 113 mode_t mask; 114 CFSocketRef ref = 0; 115 CFRunLoopSourceRef rls; 116 CFSocketContext context = { 0, NULL, NULL, NULL, NULL }; 117 118 if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) 119 goto fail; 120 121 unlink(PPP_PATH); 122 bzero(&addr, sizeof(addr)); 123 addr.sun_family = AF_LOCAL; 124 strlcpy(addr.sun_path, PPP_PATH, sizeof(addr.sun_path)); 125 mask = umask(0); 126 error = bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)); 127 umask(mask); 128 if (error) 129 goto fail; 130 131 if ((ref = CFSocketCreateWithNative(NULL, s, kCFSocketReadCallBack, 132 listenCallBack, &context)) == 0) 133 goto fail; 134 135 if ((rls = CFSocketCreateRunLoopSource(NULL, ref, 0)) == 0) 136 goto fail; 137 138 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 139 CFRelease(rls); 140 141 listen(s, SOMAXCONN); 142 CFRelease(ref); 143 return 0; 144 145fail: 146 SCLog(TRUE, LOG_INFO, CFSTR("PPPController: initialization failed...")); 147 if (s != -1) 148 close(s); 149 if (ref) { 150 CFSocketInvalidate(ref); 151 CFRelease(ref); 152 } 153 return 1; 154} 155 156/* ----------------------------------------------------------------------------- 157----------------------------------------------------------------------------- */ 158int ppp_socket_create_client(int s, int priviledged, uid_t uid, gid_t gid) 159{ 160 int flags; 161 CFSocketRef ref; 162 CFRunLoopSourceRef rls; 163 CFSocketContext context = { 0, NULL, NULL, NULL, NULL }; 164 165 if ((flags = fcntl(s, F_GETFL)) == -1 166 || fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { 167 SCLog(TRUE, LOG_INFO, CFSTR("Couldn't set client socket in non-blocking mode, errno = %d."), errno); 168 } 169 170 if ((ref = CFSocketCreateWithNative(NULL, s, 171 kCFSocketReadCallBack, clientCallBack, &context)) == 0) { 172 close(s); 173 return -1; 174 } 175 if ((rls = CFSocketCreateRunLoopSource(NULL, ref, 0)) == 0) 176 goto fail; 177 178 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 179 CFRelease(rls); 180 181 if (client_new_socket(ref, priviledged, uid, gid) == 0) 182 goto fail; 183 184 CFRelease(ref); 185 return 0; 186 187fail: 188 CFSocketInvalidate(ref); 189 CFRelease(ref); 190 return -1; 191} 192 193/* ----------------------------------------------------------------------------- 194----------------------------------------------------------------------------- */ 195static 196void listenCallBack(CFSocketRef inref, CFSocketCallBackType type, 197 CFDataRef address, const void *data, void *info) 198{ 199 struct sockaddr_un addr; 200 int s; 201 uint32_t len; 202 struct xucred xucred; 203 204 len = sizeof(addr); 205 if ((s = accept(CFSocketGetNative(inref), (struct sockaddr *) &addr, &len)) == -1) 206 return; 207 208 PRINTF(("Accepted connection...\n")); 209 210 len = sizeof(xucred); 211 if (getsockopt(s, 0, LOCAL_PEERCRED, &xucred, &len) == -1) { 212 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: can't get LOCAL_PEERCRED, errno = %d."), errno); 213 return ; 214 } 215 216 ppp_socket_create_client(s, 0, 0 /*xucred.cr_uid*/, 0 /*xucred.cr_gid*/); 217} 218 219/* ----------------------------------------------------------------------------- 220----------------------------------------------------------------------------- */ 221int readn(int ref, void *data, int len) 222{ 223#define MAXSLEEPTIME 40000 /* 1/25 of a second */ 224#define MAXRETRY 10 225 226 int n, left = len; 227 void *p = data; 228 int retry = MAXRETRY; 229 230 while (left > 0) { 231 if ((n = read(ref, p, left)) < 0) { 232 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: readn, retry %d, errno %d."), retry, errno); 233 if (errno == EAGAIN){ 234 if (retry--){ 235 if (!usleep(MAXSLEEPTIME)) 236 continue; 237 }else 238 return (len-left); 239 } 240 if (errno != EINTR) 241 return -1; 242 n = 0; 243 } 244 else if (n == 0) 245 return -1; /* EOF */ 246 247 left -= n; 248 p += n; 249 } 250 return (len - left); 251} 252 253/* ----------------------------------------------------------------------------- 254----------------------------------------------------------------------------- */ 255//static 256int writen(int ref, void *data, int len) 257{ 258#define MAXSLEEPTIME 40000 /* 1/25 of a second */ 259#define MAXRETRY 10 260 int n, left = len; 261 void *p = data; 262 int retry = MAXRETRY; 263 264 while (left > 0) { 265 if ((n = write(ref, p, left)) <= 0) { 266 SCLog(TRUE, LOG_ERR, CFSTR("PPPController writen: retry %d, errno %d."), retry, errno); 267 if (errno == EAGAIN){ 268 if (retry--){ 269 if (!usleep(MAXSLEEPTIME)) 270 continue; 271 }else 272 return(len-left); 273 } 274 if (errno != EINTR) 275 return -1; 276 n = 0; 277 } 278 left -= n; 279 p += n; 280 } 281 return len; 282} 283 284typedef void (*msg_function)(struct client *client, struct msg *msg, void **reply); 285 286msg_function requests[] = { 287 NULL, /* */ 288 socket_version, /* PPP_VERSION */ 289 socket_status, /* PPP_STATUS */ 290 socket_connect, /* PPP_CONNECT */ 291 NULL, /* */ 292 socket_disconnect, /* PPP_DISCONNECT */ 293 socket_getoption, /* PPP_GETOPTION */ 294 socket_setoption, /* PPP_SETOPTION */ 295 socket_enable_event, /* PPP_ENABLE_EVENT */ 296 socket_disable_event, /* PPP_DISABLE_EVENT */ 297 NULL, /* PPP_EVENT */ 298 socket_getnblinks, /* PPP_GETNBLINKS */ 299 socket_getlinkbyindex, /* PPP_GETLINKBYINDEX */ 300 socket_getlinkbyserviceid, /* PPP_GETLINKBYSERVICEID */ 301 socket_getlinkbyifname, /* PPP_GETLINKBYIFNAME */ 302 socket_suspend, /* PPP_SUSPEND */ 303 socket_resume, /* PPP_RESUME */ 304 socket_extendedstatus, /* PPP_EXTENDEDSTATUS */ 305 socket_getconnectdata /* PPP_GETCONNECTDATA */ 306}; 307#define LAST_REQUEST PPP_GETCONNECTDATA 308 309/* ----------------------------------------------------------------------------- 310----------------------------------------------------------------------------- */ 311static 312void clientCallBack(CFSocketRef inref, CFSocketCallBackType type, 313 CFDataRef address, const void *data, void *info) 314{ 315 int s = CFSocketGetNative(inref); 316 int action = do_nothing; 317 ssize_t n; 318 struct client *client; 319 320 client = client_findbysocketref(inref); 321 if (client == 0) 322 return; 323 324 /* first read the header part of the message */ 325 if (client->msglen < sizeof(struct ppp_msg_hdr)) { 326 n = readn(s, &((u_int8_t *)&client->msghdr)[client->msglen], sizeof(struct ppp_msg_hdr) - client->msglen); 327 switch (n) { 328 case -1: 329 action = do_close; 330 goto clientCallBackPerformAction; 331 default: 332 client->msglen += n; 333 if (client->msglen == sizeof(struct ppp_msg_hdr)) { 334 335 /* check if message bytes are in network order */ 336 if (!(client->flags & CLIENT_FLAG_PRIVILEDGED) && (client->msghdr.m_type > LAST_REQUEST)) { 337 client->flags |= CLIENT_FLAG_SWAP_BYTES; 338 client->msghdr.m_flags = ntohs(client->msghdr.m_flags); 339 client->msghdr.m_type = ntohs(client->msghdr.m_type); 340 client->msghdr.m_result = ntohl(client->msghdr.m_result); 341 client->msghdr.m_cookie = ntohl(client->msghdr.m_cookie); 342 client->msghdr.m_link = ntohl(client->msghdr.m_link); 343 client->msghdr.m_len = ntohl(client->msghdr.m_len); 344 } 345 else 346 client->flags &= ~CLIENT_FLAG_SWAP_BYTES; 347 348 /* verify msghdr fields that are used to calculate msgtotallen */ 349 if (client->msghdr.m_len > PPP_MSG_MAX_DATA_LEN) { 350 SCLog(TRUE, LOG_ERR, CFSTR("Invalid client message header: length %d..."), client->msghdr.m_len); 351 action = do_error; 352 goto clientCallBackPerformAction; 353 } 354 if (client->msghdr.m_flags & USE_SERVICEID && 355 client->msghdr.m_link > PPP_MSG_MAX_SERVICEID_LEN) { 356 SCLog(TRUE, LOG_ERR, CFSTR("Invalid client message header: service-id %d..."), client->msghdr.m_link); 357 action = do_error; 358 goto clientCallBackPerformAction; 359 } 360 361 client->msgtotallen = client->msglen 362 + client->msghdr.m_len 363 + (client->msghdr.m_flags & USE_SERVICEID ? client->msghdr.m_link : 0); 364 client->msg = my_Allocate(client->msgtotallen + 1); 365 if (client->msg == 0) { 366 SCLog(TRUE, LOG_ERR, CFSTR("Failed to allocate client message...")); 367 action = do_error; 368 goto clientCallBackPerformAction; 369 } else { 370 bcopy(&client->msghdr, client->msg, sizeof(struct ppp_msg_hdr)); 371 // let's end the message with a null byte 372 client->msg[client->msgtotallen] = 0; 373 } 374 } 375 } 376 } 377 378 /* first read the data part of the message, including serviceid */ 379 if (client->msglen >= sizeof(struct ppp_msg_hdr)) { 380 n = readn(s, &client->msg[client->msglen], client->msgtotallen - client->msglen); 381 switch (n) { 382 case -1: 383 SCLog(TRUE, LOG_ERR, CFSTR("Failed to read client message...")); 384 action = do_close; 385 break; 386 default: 387 client->msglen += n; 388 if (client->msglen == client->msgtotallen) { 389 action = do_process; 390 } 391 } 392 } 393 394clientCallBackPerformAction: 395 /* perform action */ 396 switch (action) { 397 case do_nothing: 398 break; 399 case do_error: 400 case do_close: 401 PRINTF(("Connection closed...\n")); 402 /* connection closed by client */ 403 client_dispose(client); 404 break; 405 406 case do_process: 407 // process client request 408 processRequest(client, ALIGNED_CAST(struct msg *)client->msg); 409 my_Deallocate(client->msg, client->msgtotallen + 1); 410 client->msg = 0; 411 client->msglen = 0; 412 client->msgtotallen = 0; 413 break; 414 } 415} 416 417/* ----------------------------------------------------------------------------- 418----------------------------------------------------------------------------- */ 419static 420void processRequest (struct client *client, struct msg *msg) 421{ 422 void *reply = 0; 423 msg_function func; 424 struct ppp_msg_hdr hdr; 425 426 PRINTF(("process_request : type = %x, len = %d\n", msg->hdr.m_type, msg->hdr.m_len)); 427 //printf("process_request : type = %x, len = %d\n", msg->hdr.m_type, msg->hdr.m_len); 428 429 if (msg->hdr.m_type <= LAST_REQUEST) { 430 431 func = requests[msg->hdr.m_type]; 432 if (func) 433 (*func)(client, msg, &reply); 434 } 435 else { 436 // check if it belongs to a controlling service 437 if (client->flags & CLIENT_FLAG_PRIVILEDGED) { 438 switch (msg->hdr.m_type) { 439 // private pppd event 440 case PPPD_EVENT: 441 socket_pppd_event(client, msg); 442 break; 443 case PPPD_STATUS: 444 socket_pppd_status(client, msg); 445 break; 446 case PPPD_PHASE: 447 socket_pppd_phase(client, msg); 448 break; 449 } 450 } 451 } 452 453 /* save header before swapping bytes */ 454 bcopy(msg, &hdr, sizeof(hdr)); 455 456 /* swap back bytes in the message header */ 457 if (client->flags & CLIENT_FLAG_SWAP_BYTES) { 458 msg->hdr.m_flags = htons(msg->hdr.m_flags); 459 msg->hdr.m_type = htons(msg->hdr.m_type); 460 msg->hdr.m_result = htonl(msg->hdr.m_result); 461 msg->hdr.m_cookie = htonl(msg->hdr.m_cookie); 462 msg->hdr.m_link = htonl(msg->hdr.m_link); 463 msg->hdr.m_len = htonl(msg->hdr.m_len); 464 } 465 466 if (hdr.m_len != 0xFFFFFFFF) { 467 468 writen(CFSocketGetNative(client->socketRef), msg, sizeof(struct ppp_msg_hdr) + 469 (hdr.m_flags & USE_SERVICEID ? hdr.m_link : 0)); 470 471 if (hdr.m_len) { 472 writen(CFSocketGetNative(client->socketRef), reply, hdr.m_len); 473 my_Deallocate(reply, hdr.m_len); 474 } 475 PRINTF(("process_request : m_type = 0x%x, result = 0x%x, cookie = 0x%x, link = 0x%x, len = 0x%x\n", 476 hdr.m_type, hdr.m_result, hdr.m_cookie, hdr.m_link, hdr.m_len)); 477#if 0 478 if (hdr.m_type == PPP_STATUS) { 479 struct ppp_status *stat = (struct ppp_status *)&msg->data[0]; 480 PRINTF((" ----- status = 0x%x", stat->status)); 481 if (stat->status != PPP_RUNNING) { 482 PRINTF((", cause = 0x%x", stat->s.disc.lastDiscCause)); 483 } 484 PRINTF(("\n")); 485 } 486#endif 487 } 488} 489 490/* ----------------------------------------------------------------------------- 491find the ppp structure corresponding to the message 492----------------------------------------------------------------------------- */ 493struct service *ppp_find(struct msg *msg) 494{ 495 496 if (msg->hdr.m_flags & USE_SERVICEID) 497 return findbysid(msg->data, msg->hdr.m_link); 498 else 499 return findbyref(TYPE_PPP, msg->hdr.m_link); 500 501 return 0; 502} 503 504/* ----------------------------------------------------------------------------- 505----------------------------------------------------------------------------- */ 506static 507void socket_status(struct client *client, struct msg *msg, void **reply) 508{ 509 struct service *serv = ppp_find(msg); 510 int err; 511 u_int16_t replylen; 512 513 if (!serv) { 514 msg->hdr.m_result = ENODEV; 515 msg->hdr.m_len = 0; 516 return; 517 } 518 519 err = ppp_getstatus1(serv, reply, &replylen); 520 if (err) { 521 msg->hdr.m_result = err; 522 msg->hdr.m_len = 0; 523 return; 524 } 525 526 if (client->flags & CLIENT_FLAG_SWAP_BYTES) { 527 struct ppp_status *stat = (struct ppp_status *)*reply; 528 stat->status = htonl(stat->status); 529 stat->s.run.timeElapsed = htonl(stat->s.run.timeElapsed); 530 stat->s.run.timeRemaining = htonl(stat->s.run.timeRemaining); 531 stat->s.run.inBytes = htonl(stat->s.run.inBytes); 532 stat->s.run.inPackets = htonl(stat->s.run.inPackets); 533 stat->s.run.inErrors = htonl(stat->s.run.inErrors); 534 stat->s.run.outBytes = htonl(stat->s.run.outBytes); 535 stat->s.run.outPackets = htonl(stat->s.run.outPackets); 536 stat->s.run.outErrors = htonl(stat->s.run.outErrors); 537 } 538 539 msg->hdr.m_result = 0; 540 msg->hdr.m_len = replylen; 541} 542 543/* ----------------------------------------------------------------------------- 544----------------------------------------------------------------------------- */ 545static 546void socket_extendedstatus(struct client *client, struct msg *msg, void **reply) 547{ 548 struct service *serv = ppp_find(msg); 549 int err = 0; 550 uint32_t replylen = 0; 551 CFDictionaryRef status = NULL; 552 CFDataRef data = NULL; 553 554 if (!serv) { 555 err = ENODEV; 556 goto done; 557 } 558 559 err = ppp_copyextendedstatus(serv, &status); 560 if (err) { 561 goto done; 562 } 563 564 if (status != NULL) { 565 void *dataptr = NULL; 566 567 data = Serialize(status, &dataptr, &replylen); 568 if (data == NULL) { 569 err = ENOMEM; 570 goto done; 571 } 572 573 *reply = my_Allocate(replylen); 574 if (*reply == NULL) { 575 err = ENOMEM; 576 goto done; 577 } 578 579 bcopy(dataptr, *reply, replylen); 580 } 581 582done: 583 msg->hdr.m_result = err; 584 msg->hdr.m_len = (err == 0 ? (uint16_t)replylen : 0); 585 586 if (status != NULL) { 587 CFRelease(status); 588 } 589 if (data != NULL) { 590 CFRelease(data); 591 } 592} 593 594/* ----------------------------------------------------------------------------- 595----------------------------------------------------------------------------- */ 596static 597void socket_connect(struct client *client, struct msg *msg, void **reply) 598{ 599 void *data = &msg->data[MSG_DATAOFF(msg)]; 600 struct service *serv = ppp_find(msg); 601 CFDictionaryRef opts = 0; 602 603 if (!serv) { 604 msg->hdr.m_result = ENODEV; 605 msg->hdr.m_len = 0; 606 return; 607 } 608 609 if (msg->hdr.m_len == 0) { 610 // first find current the appropriate set of options 611 opts = client_findoptset(client, serv->serviceID); 612 } 613 else { 614 opts = (CFDictionaryRef)Unserialize(data, msg->hdr.m_len); 615 if (opts == 0 || CFGetTypeID(opts) != CFDictionaryGetTypeID()) { 616 msg->hdr.m_result = ENOMEM; 617 msg->hdr.m_len = 0; 618 if (opts) 619 CFRelease(opts); 620 return; 621 } 622 } 623 624 msg->hdr.m_result = scnc_start(serv, opts, 625 (msg->hdr.m_flags & CONNECT_ARBITRATED_FLAG) ? client : 0, 626 (msg->hdr.m_flags & CONNECT_AUTOCLOSE_FLAG) ? 1 : 0, client->uid, client->gid, 627 client->pid, 0, 0); 628 if (opts && msg->hdr.m_len) 629 CFRelease(opts); 630 msg->hdr.m_len = 0; 631} 632 633/* ----------------------------------------------------------------------------- 634----------------------------------------------------------------------------- */ 635static 636void socket_disconnect(struct client *client, struct msg *msg, void **reply) 637{ 638 struct service *serv = ppp_find(msg); 639 struct client *arb_client; 640 int scnc_reason; 641 642 if (!serv) { 643 msg->hdr.m_result = ENODEV; 644 msg->hdr.m_len = 0; 645 return; 646 } 647 arb_client = (msg->hdr.m_flags & DISCONNECT_ARBITRATED_FLAG) ? client : 0; 648 scnc_reason = arb_client? SCNC_STOP_SOCK_DISCONNECT : SCNC_STOP_SOCK_DISCONNECT_NO_CLIENT; 649 scnc_stop(serv, client, SIGHUP, scnc_reason); 650 651 msg->hdr.m_result = 0; 652 msg->hdr.m_len = 0; 653} 654 655/* ----------------------------------------------------------------------------- 656----------------------------------------------------------------------------- */ 657static 658void socket_suspend(struct client *client, struct msg *msg, void **reply) 659{ 660 struct service *serv = ppp_find(msg); 661 662 if (!serv) { 663 msg->hdr.m_result = ENODEV; 664 msg->hdr.m_len = 0; 665 return; 666 } 667 668 ppp_suspend(serv); 669 670 msg->hdr.m_result = 0; 671 msg->hdr.m_len = 0; 672} 673 674/* ----------------------------------------------------------------------------- 675----------------------------------------------------------------------------- */ 676static 677void socket_resume(struct client *client, struct msg *msg, void **reply) 678{ 679 struct service *serv = ppp_find(msg); 680 681 if (!serv) { 682 msg->hdr.m_result = ENODEV; 683 msg->hdr.m_len = 0; 684 return; 685 } 686 687 ppp_resume(serv); 688 689 msg->hdr.m_result = 0; 690 msg->hdr.m_len = 0; 691} 692 693/* ----------------------------------------------------------------------------- 694----------------------------------------------------------------------------- */ 695static 696void socket_getconnectdata(struct client *client, struct msg *msg, void **reply) 697{ 698 struct service *serv = ppp_find(msg); 699 int err = 0; 700 uint32_t replylen = 0; 701 CFDictionaryRef userOptions = NULL; 702 CFDataRef data = NULL; 703 704 if (!serv) { 705 err = ENODEV; 706 goto done; 707 } 708 709 err = ppp_getconnectdata(serv, &userOptions, 0); 710 if (err) { 711 goto done; 712 } 713 714 if (userOptions != NULL) { 715 void *dataptr = NULL; 716 717 data = Serialize(userOptions, &dataptr, &replylen); 718 if (data == NULL) { 719 err = ENOMEM; 720 goto done; 721 } 722 723 *reply = my_Allocate(replylen); 724 if (*reply == NULL) { 725 err = ENOMEM; 726 goto done; 727 } 728 729 bcopy(dataptr, *reply, replylen); 730 } 731 732done: 733 msg->hdr.m_result = err; 734 msg->hdr.m_len = (err == 0 ? (uint16_t)replylen : 0); 735 736 if (userOptions != NULL) { 737 CFRelease(userOptions); 738 } 739 if (data != NULL) { 740 CFRelease(data); 741 } 742} 743 744/* ----------------------------------------------------------------------------- 745----------------------------------------------------------------------------- */ 746static 747void socket_enable_event(struct client *client, struct msg *msg, void **reply) 748{ 749 u_int32_t notification = 1; // type of notification, event or status 750 751 if (msg->hdr.m_len == 4) { 752 notification = *ALIGNED_CAST(u_int32_t *)&msg->data[MSG_DATAOFF(msg)]; 753 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 754 notification = htonl(notification); 755 if (notification < 1 || notification > 3) { 756 msg->hdr.m_result = EINVAL; 757 msg->hdr.m_len = 0; 758 return; 759 } 760 } 761 762 msg->hdr.m_result = 0; 763 client->flags &= ~(CLIENT_FLAG_NOTIFY_EVENT + CLIENT_FLAG_NOTIFY_STATUS); 764 if (notification & 1) 765 client->flags |= CLIENT_FLAG_NOTIFY_EVENT; 766 if (notification & 2) 767 client->flags |= CLIENT_FLAG_NOTIFY_STATUS; 768 client->notify_link = 0; 769 if (client->notify_serviceid) { 770 free(client->notify_serviceid); 771 client->notify_serviceid = 0; 772 } 773 if (msg->hdr.m_flags & USE_SERVICEID) { 774 if ((client->notify_serviceid = malloc(msg->hdr.m_link + 1))) { 775 strncpy((char*)client->notify_serviceid, (char*)msg->data, msg->hdr.m_link); 776 client->notify_serviceid[msg->hdr.m_link] = 0; 777 } 778 else 779 msg->hdr.m_result = ENOMEM; 780 } 781 else 782 client->notify_link = msg->hdr.m_link; 783 784 msg->hdr.m_len = 0; 785} 786 787/* ----------------------------------------------------------------------------- 788----------------------------------------------------------------------------- */ 789static 790void socket_disable_event(struct client *client, struct msg *msg, void **reply) 791{ 792 u_int32_t notification = 1; // type of notification, event or status 793 794 if (msg->hdr.m_len == 4) { 795 notification = *ALIGNED_CAST(u_int32_t *)&msg->data[MSG_DATAOFF(msg)]; 796 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 797 notification = htonl(notification); 798 if (notification < 1 || notification > 3) { 799 msg->hdr.m_result = EINVAL; 800 msg->hdr.m_len = 0; 801 return; 802 } 803 } 804 805 if (notification & 1) 806 client->flags &= ~CLIENT_FLAG_NOTIFY_EVENT; 807 if (notification & 2) 808 client->flags &= ~CLIENT_FLAG_NOTIFY_STATUS; 809 810 if ((client->flags & (CLIENT_FLAG_NOTIFY_EVENT + CLIENT_FLAG_NOTIFY_EVENT)) == 0) { 811 client->notify_link = 0; 812 if (client->notify_serviceid) { 813 free(client->notify_serviceid); 814 client->notify_serviceid = 0; 815 } 816 } 817 msg->hdr.m_result = 0; 818 msg->hdr.m_len = 0; 819} 820 821/* ----------------------------------------------------------------------------- 822----------------------------------------------------------------------------- */ 823static 824void socket_version(struct client *client, struct msg *msg, void **reply) 825{ 826 827 *reply = my_Allocate(sizeof(u_int32_t)); 828 if (*reply == 0) { 829 msg->hdr.m_result = ENOMEM; 830 msg->hdr.m_len = 0; 831 } 832 else { 833 msg->hdr.m_result = 0; 834 msg->hdr.m_len = sizeof(u_int32_t); 835 *(u_int32_t*)*reply = CURRENT_VERSION; 836 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 837 *(u_int32_t*)*reply = htonl(*(u_int32_t*)*reply); 838 } 839} 840 841/* ----------------------------------------------------------------------------- 842----------------------------------------------------------------------------- */ 843static 844void socket_getnblinks(struct client *client, struct msg *msg, void **reply) 845{ 846 u_int32_t nb = 0; 847 struct service *serv; 848 u_short subtype = msg->hdr.m_link >> 16; 849 850 TAILQ_FOREACH(serv, &service_head, next) { 851 if ((subtype == 0xFFFF) 852 || ( subtype == serv->subtype)) { 853 nb++; 854 } 855 } 856 857 *reply = my_Allocate(sizeof(u_int32_t)); 858 if (*reply == 0) { 859 msg->hdr.m_result = ENOMEM; 860 msg->hdr.m_len = 0; 861 } 862 else { 863 msg->hdr.m_result = 0; 864 msg->hdr.m_len = sizeof(u_int32_t); 865 *(u_int32_t*)*reply = nb; 866 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 867 *(u_int32_t*)*reply = htonl(*(u_int32_t*)*reply); 868 } 869} 870 871/* ----------------------------------------------------------------------------- 872index is a global index across all the link types (or within the family) 873index if between 0 and nblinks 874----------------------------------------------------------------------------- */ 875static 876void socket_getlinkbyindex(struct client *client, struct msg *msg, void **reply) 877{ 878 u_int32_t nb = 0, len = 0, err = ENODEV, index; 879 struct service *serv; 880 u_short subtype = msg->hdr.m_link >> 16; 881 882 index = *ALIGNED_CAST(u_int32_t *)&msg->data[0]; 883 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 884 index = htonl(index); 885 886 TAILQ_FOREACH(serv, &service_head, next) { 887 if ((subtype == 0xFFFF) 888 || (subtype == serv->subtype)) { 889 if (nb == index) { 890 *reply = my_Allocate(sizeof(u_int32_t)); 891 if (*reply == 0) 892 err = ENOMEM; 893 else { 894 err = 0; 895 len = sizeof(u_int32_t); 896 *(u_int32_t*)*reply = makeref(serv); 897 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 898 *(u_int32_t*)*reply = htonl(*(u_int32_t*)*reply); 899 } 900 break; 901 } 902 nb++; 903 } 904 } 905 906 msg->hdr.m_result = err; 907 msg->hdr.m_len = len; 908} 909 910/* ----------------------------------------------------------------------------- 911----------------------------------------------------------------------------- */ 912static 913void socket_getlinkbyserviceid(struct client *client, struct msg *msg, void **reply) 914{ 915 u_int32_t len = 0, err = ENODEV; 916 struct service *serv; 917 CFStringRef ref; 918 919 msg->data[msg->hdr.m_len] = 0; 920 ref = CFStringCreateWithCString(NULL, (char*)msg->data, kCFStringEncodingUTF8); 921 if (ref) { 922 serv = findbyserviceID(ref); 923 if (serv) { 924 *reply = my_Allocate(sizeof(u_int32_t)); 925 if (*reply == 0) 926 err = ENOMEM; 927 else { 928 err = 0; 929 len = sizeof(u_int32_t); 930 *(u_int32_t*)*reply = makeref(serv); 931 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 932 *(u_int32_t*)*reply = htonl(*(u_int32_t*)*reply); 933 } 934 } 935 CFRelease(ref); 936 } 937 else 938 err = ENOMEM; 939 940 msg->hdr.m_result = err; 941 msg->hdr.m_len = len; 942} 943 944/* ----------------------------------------------------------------------------- 945----------------------------------------------------------------------------- */ 946static 947void socket_getlinkbyifname(struct client *client, struct msg *msg, void **reply) 948{ 949 u_int32_t len = 0, err = ENODEV; 950 struct service *serv; 951 952 TAILQ_FOREACH(serv, &service_head, next) { 953 if (!strncmp((char*)serv->if_name, (char*)&msg->data[0], sizeof(serv->if_name))) { 954 955 if (msg->hdr.m_flags & USE_SERVICEID) { 956 *reply = my_Allocate(strlen((char*)serv->sid)); 957 if (*reply == 0) 958 err = ENOMEM; 959 else { 960 err = 0; 961 len = strlen((char*)serv->sid); 962 bcopy(serv->sid, *reply, len); 963 } 964 } 965 else { 966 *reply = my_Allocate(sizeof(u_int32_t)); 967 if (*reply == 0) 968 err = ENOMEM; 969 else { 970 err = 0; 971 len = sizeof(u_int32_t); 972 *(u_int32_t*)*reply = makeref(serv); 973 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 974 *(u_int32_t*)*reply = htonl(*(u_int32_t*)*reply); 975 } 976 } 977 break; 978 } 979 } 980 981 msg->hdr.m_result = err; 982 msg->hdr.m_len = len; 983} 984 985/* ----------------------------------------------------------------------------- 986----------------------------------------------------------------------------- */ 987static 988void socket_pppd_event(struct client *client, struct msg *msg) 989{ 990 struct service *serv = ppp_find(msg); 991 void *data = &msg->data[MSG_DATAOFF(msg)]; 992 u_int32_t event = *(u_int32_t *)data; 993 u_int32_t error = *(u_int32_t *)(data + 4); 994 995 msg->hdr.m_len = 0xFFFFFFFF; // no reply 996 //printf("ppp_event, event = 0x%x, cause = 0x%x, serviceid = '%s'\n", event, error, serviceid); 997 if (!serv) 998 return; 999 1000 if (event == PPP_EVT_DISCONNECTED) { 1001 //if (error == EXIT_USER_REQUEST) 1002 // return; // PPP API generates PPP_EVT_DISCONNECTED only for unrequested disconnections 1003 error = ppp_translate_error(serv->subtype, error, 0); 1004 if (serv->ne_sm_bridge != NULL) { 1005 ne_sm_bridge_request_uninstall(serv->ne_sm_bridge); 1006 } 1007 } else if (event == PPP_EVT_REQUEST_INSTALL) { 1008 if (serv->ne_sm_bridge != NULL) { 1009 // error is used as a flag for exclusivity 1010 ne_sm_bridge_request_install(serv->ne_sm_bridge, error); 1011 } 1012 } else if (event == PPP_EVT_REQUEST_UNINSTALL) { 1013 if (serv->ne_sm_bridge != NULL) { 1014 ne_sm_bridge_request_uninstall(serv->ne_sm_bridge); 1015 } 1016 } else { 1017 error = 0; 1018 } 1019 1020 client_notify(serv->serviceID, serv->sid, makeref(serv), event, error, CLIENT_FLAG_NOTIFY_EVENT, ppp_getstatus(serv)); 1021} 1022 1023/* ----------------------------------------------------------------------------- 1024----------------------------------------------------------------------------- */ 1025static 1026void socket_pppd_status(struct client *client, struct msg *msg) 1027{ 1028 struct service *serv = ppp_find(msg); 1029 void *data = &msg->data[MSG_DATAOFF(msg)]; 1030 u_int32_t status = *(u_int32_t *)data; 1031 u_int32_t devstatus = *(u_int32_t *)(data + 4); 1032 1033 msg->hdr.m_len = 0xFFFFFFFF; // no reply 1034 1035 if (!serv) 1036 return; 1037 1038 ppp_updatestatus(serv, status, devstatus); 1039 1040} 1041 1042/* ----------------------------------------------------------------------------- 1043----------------------------------------------------------------------------- */ 1044static 1045void socket_pppd_phase(struct client *client, struct msg *msg) 1046{ 1047 struct service *serv = ppp_find(msg); 1048 void *data = &msg->data[MSG_DATAOFF(msg)]; 1049 u_int32_t phase = *(u_int32_t *)data; 1050 u_int32_t ifunit = *(u_int32_t *)(data + 4); 1051 1052 msg->hdr.m_len = 0xFFFFFFFF; // no reply 1053 1054 if (!serv) 1055 return; 1056 1057 ppp_updatephase(serv, phase, ifunit); 1058 1059} 1060 1061/* ----------------------------------------------------------------------------- 1062----------------------------------------------------------------------------- */ 1063static 1064CFMutableDictionaryRef prepare_entity(CFMutableDictionaryRef opts, CFStringRef entity, CFStringRef property) 1065{ 1066 CFMutableDictionaryRef dict; 1067 1068 dict = (CFMutableDictionaryRef)CFDictionaryGetValue(opts, entity); 1069 // make sure we get a valid dictionary here 1070 if (dict && (CFGetTypeID(dict) != CFDictionaryGetTypeID())) 1071 return 0; 1072 1073 if (dict == 0) { 1074 dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1075 if (dict == 0) 1076 return 0; 1077 CFDictionaryAddValue((CFMutableDictionaryRef)opts, entity, dict); 1078 CFRelease(dict); 1079 } 1080 CFDictionaryRemoveValue(dict, property); 1081 1082 return dict; 1083} 1084 1085 1086/* ----------------------------------------------------------------------------- 1087----------------------------------------------------------------------------- */ 1088static 1089int set_long_opt(CFMutableDictionaryRef opts, CFStringRef entity, CFStringRef property, u_long opt, u_long mini, u_long maxi, u_long limit) 1090{ 1091 CFMutableDictionaryRef dict; 1092 CFNumberRef num; 1093 1094 if (opt < mini) { 1095 if (limit) opt = mini; 1096 else return EINVAL; 1097 } 1098 else if (opt > maxi) { 1099 if (limit) opt = maxi; 1100 else return EINVAL; 1101 } 1102 1103 dict = prepare_entity(opts, entity, property); 1104 if (dict == 0) 1105 return ENOMEM; 1106 1107 num = CFNumberCreate(NULL, kCFNumberLongType, &opt); 1108 if (num) { 1109 CFDictionaryAddValue(dict, property, num); 1110 CFRelease(num); 1111 } 1112 1113 return 0; 1114} 1115 1116/* ----------------------------------------------------------------------------- 1117----------------------------------------------------------------------------- */ 1118static 1119int set_str_opt(CFMutableDictionaryRef opts, CFStringRef entity, CFStringRef property, char *opt, int len, CFStringRef optref) 1120{ 1121 CFMutableDictionaryRef dict; 1122 CFStringRef str; 1123 1124 dict = prepare_entity(opts, entity, property); 1125 if (dict == 0) 1126 return ENOMEM; 1127 1128 if (optref) 1129 CFDictionaryAddValue(dict, property, optref); 1130 else { 1131 opt[len] = 0; 1132 str = CFStringCreateWithCString(NULL, opt, kCFStringEncodingUTF8); 1133 if (str) { 1134 CFDictionaryAddValue(dict, property, str); 1135 CFRelease(str); 1136 } 1137 } 1138 return 0; 1139} 1140 1141/* ----------------------------------------------------------------------------- 1142----------------------------------------------------------------------------- */ 1143static 1144int set_array_opt(CFMutableDictionaryRef opts, CFStringRef entity, CFStringRef property, CFStringRef optref1, CFStringRef optref2) 1145{ 1146 CFMutableDictionaryRef dict; 1147 CFMutableArrayRef array; 1148 1149 dict = prepare_entity(opts, entity, property); 1150 if (dict == 0) 1151 return ENOMEM; 1152 1153 array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); 1154 if (array == 0) 1155 return ENOMEM; 1156 1157 if (optref1) 1158 CFArrayAppendValue(array, optref1); 1159 if (optref2) 1160 CFArrayAppendValue(array, optref2); 1161 1162 CFDictionaryAddValue(dict, property, array); 1163 CFRelease(array); 1164 1165 return 0; 1166} 1167 1168/* ----------------------------------------------------------------------------- 1169----------------------------------------------------------------------------- */ 1170static 1171void remove_opt(CFMutableDictionaryRef opts, CFStringRef entity, CFStringRef property) 1172{ 1173 CFMutableDictionaryRef dict; 1174 1175 dict = (CFMutableDictionaryRef)CFDictionaryGetValue(opts, entity); 1176 // make sure we get a valid dictionary here 1177 if (dict&& (CFGetTypeID(dict) == CFDictionaryGetTypeID())) 1178 CFDictionaryRemoveValue(dict, property); 1179} 1180 1181 1182/* ----------------------------------------------------------------------------- 1183id must be a valid client 1184----------------------------------------------------------------------------- */ 1185static 1186void socket_setoption(struct client *client, struct msg *msg, void **reply) 1187{ 1188 struct ppp_opt *opt = ALIGNED_CAST(struct ppp_opt *)&msg->data[MSG_DATAOFF(msg)]; 1189 u_int32_t optint = *ALIGNED_CAST(u_int32_t *)(&opt->o_data[0]); 1190 u_char *optstr = &opt->o_data[0]; 1191 CFMutableDictionaryRef opts; 1192 u_int32_t err = 0, len = msg->hdr.m_len - sizeof(struct ppp_opt_hdr), speed; 1193 struct service *serv = ppp_find(msg); 1194 CFStringRef string1, string2; 1195 1196 if (!serv) { 1197 msg->hdr.m_result = ENODEV; 1198 msg->hdr.m_len = 0; 1199 return; 1200 } 1201 1202 if (client->flags & CLIENT_FLAG_SWAP_BYTES) { 1203 opt->o_type = htonl(opt->o_type); 1204 optint = htonl(optint); 1205 } 1206 1207 // not connected, set the client options that will be used. 1208 opts = client_findoptset(client, serv->serviceID); 1209 if (!opts) { 1210 // first option used by client, create private set 1211 opts = client_newoptset(client, serv->serviceID); 1212 if (!opts) { 1213 msg->hdr.m_result = ENOMEM; 1214 msg->hdr.m_len = 0; 1215 return; 1216 } 1217 } 1218 1219 switch (opt->o_type) { 1220 1221 // COMM options 1222 case PPP_OPT_DEV_NAME: 1223 err = set_str_opt(opts, kSCEntNetInterface, kSCPropNetInterfaceDeviceName, (char*)optstr, len, 0); 1224 break; 1225 case PPP_OPT_DEV_SPEED: 1226 // add flexibility and adapt the speed to the immediatly higher speed 1227 speed = optint; 1228 if (speed <= 1200) speed = 1200; 1229 else if ((speed > 1200) && (speed <= 2400)) speed = 2400; 1230 else if ((speed > 2400) && (speed <= 9600)) speed = 9600; 1231 else if ((speed > 9600) && (speed <= 19200)) speed = 19200; 1232 else if ((speed > 19200) && (speed <= 38400)) speed = 38400; 1233 else if ((speed > 38400) && (speed <= 57600)) speed = 57600; 1234 else if ((speed > 38400) && (speed <= 57600)) speed = 57600; 1235 else if ((speed > 57600) && (speed <= 0xFFFFFFFF)) speed = 115200; 1236 err = set_long_opt(opts, kSCEntNetModem, kSCPropNetModemSpeed, speed, 0, 0xFFFFFFFF, 0); 1237 break; 1238 case PPP_OPT_DEV_CONNECTSCRIPT: 1239 err = set_str_opt(opts, kSCEntNetModem, kSCPropNetModemConnectionScript, (char*)optstr, len, 0); 1240 break; 1241 case PPP_OPT_DEV_DIALMODE: 1242 string1 = kSCValNetModemDialModeWaitForDialTone; 1243 switch (optint) { 1244 case PPP_DEV_IGNOREDIALTONE: 1245 string1 = kSCValNetModemDialModeIgnoreDialTone; 1246 break; 1247 case PPP_DEV_MANUALDIAL: 1248 string1 = kSCValNetModemDialModeManual; 1249 break; 1250 } 1251 if (string1) 1252 set_str_opt(opts, kSCEntNetModem, kSCPropNetModemDialMode, 0, 0, string1); 1253 break; 1254 case PPP_OPT_COMM_TERMINALMODE: 1255 switch (optint) { 1256 case PPP_COMM_TERM_NONE: 1257 remove_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommDisplayTerminalWindow); 1258 remove_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommUseTerminalScript); 1259 break; 1260 case PPP_COMM_TERM_SCRIPT: 1261 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommUseTerminalScript, 1, 0, 1, 1) 1262 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommDisplayTerminalWindow, 0, 0, 1, 1); 1263 break; 1264 case PPP_COMM_TERM_WINDOW: 1265 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommUseTerminalScript, 0, 0, 1, 1) 1266 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommDisplayTerminalWindow, 1, 0, 1, 1); 1267 break; 1268 } 1269 break; 1270 case PPP_OPT_COMM_TERMINALSCRIPT: 1271 err = set_str_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommTerminalScript, (char*)optstr, len, 0); 1272 break; 1273 case PPP_OPT_COMM_REMOTEADDR: 1274 err = set_str_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress, (char*)optstr, len, 0); 1275 break; 1276 case PPP_OPT_COMM_IDLETIMER: 1277 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPDisconnectOnIdleTimer, optint, 0, 0xFFFFFFFF, 1) 1278 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPDisconnectOnIdle, optint, 0, 1, 1); 1279 break; 1280 case PPP_OPT_COMM_SESSIONTIMER: 1281 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPSessionTimer, optint, 0, 0xFFFFFFFF, 1) 1282 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPUseSessionTimer, optint, 0, 1, 1); 1283 break; 1284 case PPP_OPT_COMM_CONNECTDELAY: 1285 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPCommConnectDelay, optint, 0, 0xFFFFFFFF, 1); 1286 break; 1287 1288 // LCP options 1289 case PPP_OPT_LCP_HDRCOMP: 1290 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, optint & PPP_LCP_HDRCOMP_PROTO, 0, 1, 1) 1291 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, optint & PPP_LCP_HDRCOMP_ADDR, 0, 1, 1); 1292 break; 1293 case PPP_OPT_LCP_MRU: 1294 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPMRU, optint, 0, 0xFFFFFFFF, 1); 1295 break; 1296 case PPP_OPT_LCP_MTU: 1297 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPMTU, optint, 0, 0xFFFFFFFF, 1); 1298 break; 1299 case PPP_OPT_LCP_RCACCM: 1300 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPReceiveACCM, optint, 0, 0xFFFFFFFF, 1); 1301 break; 1302 case PPP_OPT_LCP_TXACCM: 1303 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPTransmitACCM, optint, 0, 0xFFFFFFFF, 1); 1304 break; 1305 case PPP_OPT_LCP_ECHO: 1306 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPEchoInterval, (ALIGNED_CAST(struct ppp_opt_echo *)opt->o_data)->interval, 0, 0xFFFFFFFF, 1) 1307 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPLCPEchoFailure, (ALIGNED_CAST(struct ppp_opt_echo *)opt->o_data)->failure, 0, 0xFFFFFFFF, 1); 1308 break; 1309 1310 // SEC options 1311 case PPP_OPT_AUTH_PROTO: 1312 string1 = string2 = 0; 1313 switch (optint) { 1314 case PPP_AUTH_NONE: 1315 string1 = CFSTR("None");//kSCValNetPPPAuthProtocolNone; 1316 break; 1317 case PPP_AUTH_PAP: 1318 string1 = kSCValNetPPPAuthProtocolPAP; 1319 break; 1320 case PPP_AUTH_CHAP: 1321 string2 = kSCValNetPPPAuthProtocolCHAP; 1322 break; 1323 case PPP_AUTH_PAPCHAP: 1324 string1 = kSCValNetPPPAuthProtocolPAP; 1325 string2 = kSCValNetPPPAuthProtocolCHAP; 1326 break; 1327 default: 1328 err = EINVAL; 1329 } 1330 if (string1 || string2) 1331 err = set_array_opt(opts, kSCEntNetPPP, kSCPropNetPPPAuthProtocol, string1, string2); 1332 break; 1333 case PPP_OPT_AUTH_NAME: 1334 err = set_str_opt(opts, kSCEntNetPPP, kSCPropNetPPPAuthName, (char*)optstr, len, 0); 1335 break; 1336 case PPP_OPT_AUTH_PASSWD: 1337 err = set_str_opt(opts, kSCEntNetPPP, kSCPropNetPPPAuthPassword, (char*)optstr, len, 0); 1338 break; 1339 1340 // IPCP options 1341 case PPP_OPT_IPCP_HDRCOMP: 1342 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPIPCPCompressionVJ, optint, 0, 1, 1); 1343 break; 1344 case PPP_OPT_IPCP_REMOTEADDR: 1345 string1 = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d.%d.%d.%d"), 1346 optint >> 24, (optint >> 16) & 0xFF, (optint >> 8) & 0xFF, optint & 0xFF); 1347 if (string1) { 1348 err = set_array_opt(opts, kSCEntNetIPv4, kSCPropNetIPv4DestAddresses, string1, 0); 1349 CFRelease(string1); 1350 } 1351 break; 1352 case PPP_OPT_IPCP_LOCALADDR: 1353 string1 = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d.%d.%d.%d"), 1354 optint >> 24, (optint >> 16) & 0xFF, (optint >> 8) & 0xFF, optint & 0xFF); 1355 if (string1) { 1356 err = set_array_opt(opts, kSCEntNetIPv4, kSCPropNetIPv4Addresses, string1, 0); 1357 CFRelease(string1); 1358 } 1359 break; 1360 // MISC options 1361 case PPP_OPT_LOGFILE: 1362 err = EOPNOTSUPP; 1363 //err = set_str_opt(&opts->misc.logfile, optstr, len); 1364 break; 1365 case PPP_OPT_COMM_REMINDERTIMER: 1366 err = set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPIdleReminderTimer, optint, 0, 0xFFFFFFFF, 1) 1367 || set_long_opt(opts, kSCEntNetPPP, kSCPropNetPPPIdleReminder, optint, 0, 1, 1); 1368 break; 1369 case PPP_OPT_ALERTENABLE: 1370 err = set_long_opt(opts, kSCEntNetPPP, CFSTR("AlertEnable"), optint, 0, 0xFFFFFFFF, 1); 1371 break; 1372 default: 1373 err = EOPNOTSUPP; 1374 }; 1375 1376 msg->hdr.m_result = err; 1377 msg->hdr.m_len = 0; 1378} 1379 1380/* ----------------------------------------------------------------------------- 1381----------------------------------------------------------------------------- */ 1382static 1383void socket_getoption (struct client *client, struct msg *msg, void **reply) 1384{ 1385 struct ppp_opt *opt = ALIGNED_CAST(struct ppp_opt *)&msg->data[MSG_DATAOFF(msg)]; 1386 CFDictionaryRef opts; 1387 struct service *serv = ppp_find(msg); 1388 u_int8_t optdata[OPT_STR_LEN + 1] __attribute__ ((aligned(4))); // Wcast-align fix - force alignment 1389 u_int32_t optlen; 1390 1391 if (!serv) { 1392 msg->hdr.m_len = 0; 1393 msg->hdr.m_result = ENODEV; 1394 return; 1395 } 1396 1397 if (client->flags & CLIENT_FLAG_SWAP_BYTES) 1398 opt->o_type = htonl(opt->o_type); 1399 1400 if (serv->u.ppp.phase != PPP_IDLE) 1401 // take the active user options 1402 opts = serv->connectopts; 1403 else 1404 // not connected, get the client options that will be used. 1405 opts = client_findoptset(client, serv->serviceID); 1406 1407 if (!ppp_getoptval(serv, opts, 0, opt->o_type, optdata, sizeof(optdata), &optlen)) { 1408 msg->hdr.m_len = 0; 1409 msg->hdr.m_result = EOPNOTSUPP; 1410 return; 1411 } 1412 1413 *reply = my_Allocate(sizeof(struct ppp_opt_hdr) + optlen); 1414 if (*reply == 0) { 1415 msg->hdr.m_result = ENOMEM; 1416 msg->hdr.m_len = 0; 1417 return; 1418 } 1419 1420 if (client->flags & CLIENT_FLAG_SWAP_BYTES) { 1421 switch(opt->o_type) { 1422 // all 4 bytes options 1423 case PPP_OPT_DEV_SPEED: 1424 case PPP_OPT_COMM_IDLETIMER: 1425 case PPP_OPT_AUTH_PROTO: 1426 case PPP_OPT_LCP_HDRCOMP: 1427 case PPP_OPT_LCP_MRU: 1428 case PPP_OPT_LCP_MTU: 1429 case PPP_OPT_LCP_RCACCM: 1430 case PPP_OPT_LCP_TXACCM: 1431 case PPP_OPT_IPCP_HDRCOMP: 1432 case PPP_OPT_IPCP_LOCALADDR: 1433 case PPP_OPT_IPCP_REMOTEADDR: 1434 case PPP_OPT_RESERVED: 1435 case PPP_OPT_COMM_REMINDERTIMER: 1436 case PPP_OPT_ALERTENABLE: 1437 case PPP_OPT_COMM_CONNECTDELAY: 1438 case PPP_OPT_COMM_SESSIONTIMER: 1439 case PPP_OPT_COMM_TERMINALMODE: 1440 case PPP_OPT_DEV_CONNECTSPEED: 1441 case PPP_OPT_DEV_DIALMODE: 1442 case PPP_OPT_DIALONDEMAND: 1443 case PPP_OPT_LCP_ECHO: 1444 *ALIGNED_CAST(u_int32_t*)optdata = htonl(*ALIGNED_CAST(u_int32_t*)optdata); 1445 break; 1446 } 1447 } 1448 1449 bcopy(opt, *reply, sizeof(struct ppp_opt_hdr)); 1450 bcopy(optdata, (*reply) + sizeof(struct ppp_opt_hdr), optlen); 1451 1452 msg->hdr.m_result = 0; 1453 msg->hdr.m_len = sizeof(struct ppp_opt_hdr) + optlen; 1454} 1455 1456/* ----------------------------------------------------------------------------- 1457----------------------------------------------------------------------------- */ 1458void socket_client_notify (CFSocketRef ref, u_char *sid, u_int32_t link, u_long event, u_long error, u_int32_t flags) 1459{ 1460 struct ppp_msg_hdr msg; 1461 int link_len = 0; 1462 1463 bzero(&msg, sizeof(msg)); 1464 msg.m_type = PPP_EVENT; 1465 msg.m_link = link; 1466 msg.m_result = event; 1467 msg.m_cookie = error; 1468 if (sid) { 1469 msg.m_flags |= USE_SERVICEID; 1470 msg.m_link = strlen((char*)sid); 1471 link_len = msg.m_link; /* save len */ 1472 } 1473 1474 /* swap back bytes that have been assigned by internal processing functions */ 1475 if (flags & CLIENT_FLAG_SWAP_BYTES) { 1476 msg.m_flags = htons(msg.m_flags); 1477 msg.m_type = htons(msg.m_type); 1478 msg.m_result = htonl(msg.m_result); 1479 msg.m_cookie = htonl(msg.m_cookie); 1480 msg.m_link = htonl(msg.m_link); 1481 msg.m_len = htonl(msg.m_len); 1482 } 1483 1484 if (writen(CFSocketGetNative(ref), &msg, sizeof(msg)) != sizeof(msg)) 1485 return; 1486 1487 if (sid) { 1488 if (writen(CFSocketGetNative(ref), sid, link_len) != link_len) 1489 return; 1490 } 1491} 1492 1493