1/* 2 * Copyright (c) 2000, 2001 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 * Modification History 26 * 27 * Oct 25, 2002 Christophe Allie <callie@apple.com> 28 * - use ServiceID instead of LinkID 29 * 30 * Feb 28, 2002 Christophe Allie <callie@apple.com> 31 * - socket API fixes 32 * 33 * Feb 10, 2001 Allan Nathanson <ajn@apple.com> 34 * - cleanup API 35 * 36 * Feb 2000 Christophe Allie <callie@apple.com> 37 * - initial revision 38 */ 39 40#include <stdio.h> 41#include <unistd.h> 42#include <sys/types.h> 43#include <sys/errno.h> 44#include <sys/socket.h> 45#include <sys/un.h> 46#include <CoreFoundation/CoreFoundation.h> 47 48#include "ppp_msg.h" 49#include "ppplib.h" 50 51__private_extern__ 52int 53PPPInit(int *ref) 54{ 55 int sock; 56 int status; 57 struct sockaddr_un sun; 58 59 sock = socket(AF_LOCAL, SOCK_STREAM, 0); 60 61 bzero(&sun, sizeof(sun)); 62 sun.sun_family = AF_LOCAL; 63 strncpy(sun.sun_path, PPP_PATH, sizeof(sun.sun_path)); 64 65 status = connect(sock, (struct sockaddr *)&sun, sizeof(sun)); 66 if (status < 0) { 67 return errno; 68 } 69 70 *ref = sock; 71 return 0; 72} 73 74 75__private_extern__ 76int 77PPPDispose(int ref) 78{ 79 if (close(ref) < 0) { 80 return errno; 81 } 82 return 0; 83} 84 85static int 86readn(int ref, void *data, int len) 87{ 88 int n, left = len; 89 void *p = data; 90 91 while (left > 0) { 92 if ((n = read(ref, p, left)) < 0) { 93 if (errno != EINTR) 94 return -1; 95 n = 0; 96 } 97 else if (n == 0) 98 break; /* EOF */ 99 100 left -= n; 101 p += n; 102 } 103 return (len - left); 104} 105 106static int 107writen(int ref, void *data, int len) 108{ 109 int n, left = len; 110 void *p = data; 111 112 while (left > 0) { 113 if ((n = write(ref, p, left)) <= 0) { 114 if (errno != EINTR) 115 return -1; 116 n = 0; 117 } 118 left -= n; 119 p += n; 120 } 121 return len; 122} 123 124static int 125PPPExec(int ref, 126 u_int8_t *serviceid, 127 u_int32_t cmd, 128 void *request, 129 u_int32_t requestLen, 130 void **reply, 131 u_int32_t *replyLen) 132{ 133 struct ppp_msg_hdr msg; 134 char *buf = NULL; 135 ssize_t n; 136 137 bzero(&msg, sizeof(msg)); 138 if (serviceid) { 139 // serviceid is present, use it 140 msg.m_flags = USE_SERVICEID; 141 msg.m_link = strlen(serviceid); 142 } 143 else { 144 // no service ID, use the default link 145 msg.m_link = -1; 146 } 147 msg.m_type = cmd; 148 msg.m_len = ((request != NULL) && (requestLen > 0)) ? requestLen : 0; 149 150 // send the command 151 if (writen(ref, &msg, sizeof(msg)) < 0) { 152 fprintf(stderr, "PPPExec write() failed: %s\n", strerror(errno)); 153 return errno; 154 } 155 156 if (serviceid) { 157 if (writen(ref, serviceid, msg.m_link) < 0) { 158 fprintf(stderr, "PPPExec write() failed: %s\n", strerror(errno)); 159 return errno; 160 } 161 } 162 163 if ((request != NULL) && (requestLen > 0)) { 164 if (writen(ref, request, requestLen) < 0) { 165 fprintf(stderr, "PPPExec write() failed: %s\n", strerror(errno)); 166 return errno; 167 } 168 } 169 170 // always expect a reply 171 n = readn(ref, &msg, sizeof(msg)); 172 if (n == -1) { 173 fprintf(stderr, "PPPExec read() failed: error=%s\n", strerror(errno)); 174 return errno; 175 } else if (n != sizeof(msg)) { 176 fprintf(stderr, "PPPExec read() failed: insufficent data, read=%d\n", n); 177 return -1; 178 } 179 180 if (serviceid && msg.m_link) { 181 buf = CFAllocatorAllocate(NULL, msg.m_link, 0); 182 if (buf) { 183 // read reply 184 n = readn(ref, buf, msg.m_link); 185 if (n == -1) { 186 fprintf(stderr, "PPPExec read() failed: error=%s\n", strerror(errno)); 187 CFAllocatorDeallocate(NULL, buf); 188 return errno; 189 } else if (n != msg.m_link) { 190 fprintf(stderr, "PPPExec read() failed: insufficent data, read=%d\n", n); 191 CFAllocatorDeallocate(NULL, buf); 192 return -1; 193 } 194 // buf contains the service id we passed in the request 195 CFAllocatorDeallocate(NULL, buf); 196 buf = NULL; 197 } 198 } 199 200 if (msg.m_len) { 201 buf = CFAllocatorAllocate(NULL, msg.m_len, 0); 202 if (buf) { 203 // read reply 204 n = readn(ref, buf, msg.m_len); 205 if (n == -1) { 206 fprintf(stderr, "PPPExec read() failed: error=%s\n", strerror(errno)); 207 CFAllocatorDeallocate(NULL, buf); 208 return errno; 209 } else if (n != msg.m_len) { 210 fprintf(stderr, "PPPExec read() failed: insufficent data, read=%d\n", n); 211 CFAllocatorDeallocate(NULL, buf); 212 return -1; 213 } 214 } 215 } 216 217 if (reply && replyLen) { 218 *reply = buf; 219 *replyLen = msg.m_len; 220 } else if (buf) { 221 // if additional returned data is unwanted 222 CFAllocatorDeallocate(NULL, buf); 223 } 224 225 return msg.m_result; 226} 227 228 229int 230PPPConnect(int ref, u_int8_t *serviceid) 231{ 232 int status; 233 234 status = PPPExec(ref, 235 serviceid, 236 PPP_CONNECT, 237 NULL, 238 0, 239 NULL, 240 NULL); 241 if (status != 0) { 242 fprintf(stderr, "PPPExec(PPP_CONNECT) failed: status = %d\n", status); 243 return status; 244 } 245 246 return status; 247} 248 249 250int 251PPPDisconnect(int ref, u_int8_t *serviceid) 252{ 253 int status; 254 255 status = PPPExec(ref, 256 serviceid, 257 PPP_DISCONNECT, 258 NULL, 259 0, 260 NULL, 261 NULL); 262 if (status != 0) { 263 fprintf(stderr, "PPPExec(PPP_DISCONNECT) failed: status = %d\n", status); 264 return status; 265 } 266 267 return status; 268} 269 270 271__private_extern__ 272int 273PPPGetOption(int ref, u_int8_t *serviceid, u_int32_t option, void **data, u_int32_t *dataLen) 274{ 275 struct ppp_opt_hdr opt; 276 void *replyBuf = NULL; 277 u_int32_t replyBufLen = 0; 278 int status; 279 280 bzero(&opt, sizeof(opt)); 281 opt.o_type = option; 282 283 status = PPPExec(ref, 284 serviceid, 285 PPP_GETOPTION, 286 (void *)&opt, 287 sizeof(opt), 288 &replyBuf, 289 &replyBufLen); 290 if (status != 0) { 291 fprintf(stderr, "PPPExec(PPP_GETOPTION) failed: status = %d\n", status); 292 *data = NULL; 293 *dataLen = 0; 294 return status; 295 } 296 297 if (replyBuf && (replyBufLen > sizeof(struct ppp_opt_hdr))) { 298 *dataLen = replyBufLen - sizeof(struct ppp_opt_hdr); 299 *data = CFAllocatorAllocate(NULL, *dataLen, 0); 300 bcopy(((struct ppp_opt *)replyBuf)->o_data, *data, *dataLen); 301 } 302 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf); 303 304 return status; 305} 306 307 308__private_extern__ 309int 310PPPSetOption(int ref, u_int8_t *serviceid, u_int32_t option, void *data, u_int32_t dataLen) 311{ 312 void *buf; 313 u_long bufLen; 314 int status; 315 316 bufLen = sizeof(struct ppp_opt_hdr) + dataLen; 317 buf = CFAllocatorAllocate(NULL, bufLen, 0); 318 319 bzero((struct ppp_opt_hdr *)buf, sizeof(struct ppp_opt_hdr)); 320 ((struct ppp_opt_hdr *)buf)->o_type = option; 321 bcopy(data, ((struct ppp_opt *)buf)->o_data, dataLen); 322 323 status = PPPExec(ref, 324 serviceid, 325 PPP_SETOPTION, 326 buf, 327 bufLen, 328 NULL, 329 NULL); 330 if (status != 0) { 331 fprintf(stderr, "PPPExec(PPP_SETOPTION) failed: status = %d\n", status); 332 } 333 334 CFAllocatorDeallocate(NULL, buf); 335 336 return status; 337} 338 339 340__private_extern__ 341int 342PPPStatus(int ref, u_int8_t *serviceid, struct ppp_status **stat) 343{ 344 void *replyBuf = NULL; 345 u_int32_t replyBufLen = 0; 346 int status; 347 348 status = PPPExec(ref, 349 serviceid, 350 PPP_STATUS, 351 NULL, 352 0, 353 &replyBuf, 354 &replyBufLen); 355 if (status != 0) { 356 fprintf(stderr, "PPPExec(PPP_STATUS) failed: status = %d\n", status); 357 return status; 358 } 359 360 if (replyBuf && (replyBufLen == sizeof(struct ppp_status))) { 361 *stat = (struct ppp_status *)replyBuf; 362 } else { 363 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf); 364 *stat = NULL; 365 status = -1; 366 } 367 368 return status; 369} 370 371 372__private_extern__ 373int 374PPPEnableEvents(int ref, u_int8_t *serviceid, u_char enable) 375{ 376 int status; 377 378 status = PPPExec(ref, 379 serviceid, 380 enable ? PPP_ENABLE_EVENT : PPP_DISABLE_EVENT, 381 NULL, 382 0, 383 NULL, 384 NULL); 385 if (status != 0) { 386 fprintf(stderr, 387 "PPPExec(%s) failed: status = %d\n", 388 enable ? "PPP_ENABLE_EVENT" : "PPP_DISABLE_EVENT", 389 status); 390 return status; 391 } 392 393 return status; 394} 395