]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/ppp.c
12e5685c9178763463cdb1384262b1a4f3658a5b
[apple/configd.git] / SystemConfiguration.fproj / ppp.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * Nov 7, 2002 Allan Nathanson <ajn@apple.com>
30 * - use ServiceID *or* LinkID
31 *
32 * Oct 25, 2002 Christophe Allie <callie@apple.com>
33 * - use ServiceID instead of LinkID
34 *
35 * Feb 28, 2002 Christophe Allie <callie@apple.com>
36 * - socket API fixes
37 *
38 * Feb 10, 2001 Allan Nathanson <ajn@apple.com>
39 * - cleanup API
40 *
41 * Feb 2000 Christophe Allie <callie@apple.com>
42 * - initial revision
43 */
44
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/errno.h>
49 #include <sys/socket.h>
50 #include <sys/un.h>
51 #include <CoreFoundation/CoreFoundation.h>
52
53 #include <SystemConfiguration/SystemConfiguration.h>
54 #include <SystemConfiguration/SCPrivate.h>
55
56 #include <ppp/ppp_msg.h>
57 #include "ppp.h"
58
59
60 static int
61 readn(int ref, void *data, int len)
62 {
63 int left = len;
64 int n;
65 void *p = data;
66
67 while (left > 0) {
68 if ((n = read(ref, p, left)) < 0) {
69 if (errno != EINTR) {
70 return -1;
71 }
72 n = 0;
73 } else if (n == 0) {
74 break; /* EOF */
75 }
76
77 left -= n;
78 p += n;
79 }
80 return (len - left);
81 }
82
83
84 static int
85 writen(int ref, void *data, int len)
86 {
87 int left = len;
88 int n;
89 void *p = data;
90
91 while (left > 0) {
92 if ((n = write(ref, p, left)) <= 0) {
93 if (errno != EINTR) {
94 return -1;
95 }
96 n = 0;
97 }
98 left -= n;
99 p += n;
100 }
101 return len;
102 }
103
104
105 __private_extern__
106 int
107 PPPInit(int *ref)
108 {
109 int sock;
110 int status;
111 struct sockaddr_un sun;
112
113 sock = socket(AF_LOCAL, SOCK_STREAM, 0);
114
115 bzero(&sun, sizeof(sun));
116 sun.sun_family = AF_LOCAL;
117 strncpy(sun.sun_path, PPP_PATH, sizeof(sun.sun_path));
118
119 status = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
120 if (status < 0) {
121 return errno;
122 }
123
124 *ref = sock;
125 return 0;
126 }
127
128
129 __private_extern__
130 int
131 PPPDispose(int ref)
132 {
133 if (close(ref) < 0) {
134 return errno;
135 }
136 return 0;
137 }
138
139
140 static int
141 PPPExec(int ref,
142 CFStringRef serviceID,
143 uint32_t link,
144 uint32_t cmd,
145 u_int16_t flags,
146 void *request,
147 uint32_t requestLen,
148 void **reply,
149 uint32_t *replyLen)
150 {
151 struct ppp_msg_hdr msg;
152 char *buf = NULL;
153 ssize_t n;
154 CFDataRef sID = NULL;
155
156 bzero(&msg, sizeof(msg));
157
158 // first send request, if necessary
159 if (cmd) {
160 msg.m_type = cmd;
161 msg.m_flags = flags;
162 if (serviceID) {
163 sID = CFStringCreateExternalRepresentation(NULL,
164 serviceID,
165 kCFStringEncodingUTF8,
166 0);
167 // serviceID is present, use it
168 msg.m_flags |= USE_SERVICEID;
169 msg.m_link = CFDataGetLength(sID);
170 } else {
171 // no service ID, use the requested link
172 msg.m_link = link;
173 }
174 msg.m_len = ((request != NULL) && (requestLen > 0)) ? requestLen : 0;
175
176 // send the command
177 if (writen(ref, &msg, sizeof(msg)) < 0) {
178 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec write() failed: %s"), strerror(errno));
179 if (sID) CFRelease(sID);
180 return errno;
181 }
182
183 if (sID) {
184 if (writen(ref, (void *)CFDataGetBytePtr(sID), msg.m_link) < 0) {
185 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec write() failed: %s"), strerror(errno));
186 CFRelease(sID);
187 return errno;
188 }
189 CFRelease(sID);
190 }
191
192 if ((request != NULL) && (requestLen > 0)) {
193 if (writen(ref, request, requestLen) < 0) {
194 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec write() failed: %s"), strerror(errno));
195 return errno;
196 }
197 }
198 }
199
200 // then read replies or incoming message
201 n = readn(ref, &msg, sizeof(msg));
202 if (n == -1) {
203 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno));
204 return errno;
205 } else if (n != sizeof(msg)) {
206 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: insufficent data, read=%d"), n);
207 return -1;
208 }
209
210 if ((msg.m_flags & USE_SERVICEID) && msg.m_link) {
211 buf = CFAllocatorAllocate(NULL, msg.m_link, 0);
212 if (buf) {
213 // read reply
214 n = readn(ref, buf, msg.m_link);
215 if (n == -1) {
216 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno));
217 CFAllocatorDeallocate(NULL, buf);
218 return errno;
219 } else if (n != (ssize_t)msg.m_link) {
220 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno));
221 CFAllocatorDeallocate(NULL, buf);
222 return -1;
223 }
224 // buf contains the service id we passed in the request
225 CFAllocatorDeallocate(NULL, buf);
226 buf = NULL;
227 }
228 }
229
230 if (msg.m_len) {
231 buf = CFAllocatorAllocate(NULL, msg.m_len, 0);
232 if (buf) {
233 // read reply
234 n = readn(ref, buf, msg.m_len);
235 if (n == -1) {
236 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno));
237 CFAllocatorDeallocate(NULL, buf);
238 return errno;
239 } else if (n != (ssize_t)msg.m_len) {
240 SCLog(_sc_verbose, LOG_ERR, CFSTR("PPPExec readn() failed: insufficent data, read=%d"), n);
241 CFAllocatorDeallocate(NULL, buf);
242 return -1;
243 }
244 }
245 }
246
247 if (reply && replyLen) {
248 *reply = buf;
249 *replyLen = msg.m_len;
250 } else if (buf) {
251 // if additional returned data is unwanted
252 CFAllocatorDeallocate(NULL, buf);
253 }
254
255 return msg.m_result;
256 }
257
258
259 __private_extern__
260 int
261 PPPGetLinkByInterface(int ref, char *if_name, uint32_t *link)
262 {
263 void *replyBuf = NULL;
264 uint32_t replyBufLen = 0;
265 int status;
266
267 status = PPPExec(ref,
268 NULL,
269 -1,
270 PPP_GETLINKBYIFNAME,
271 0,
272 (void *)if_name,
273 strlen(if_name),
274 &replyBuf,
275 &replyBufLen);
276 if (status != 0) {
277 return status;
278 }
279
280 if (replyBuf && (replyBufLen == sizeof(uint32_t))) {
281 *link = *(uint32_t *)replyBuf;
282 } else {
283 status = -2; /* if not found */
284 }
285 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
286
287 return status;
288 }
289
290
291 __private_extern__
292 int
293 PPPConnect(int ref, CFStringRef serviceID, uint32_t link, void *data, uint32_t dataLen, int linger)
294 {
295 int status;
296
297 status = PPPExec(ref,
298 serviceID,
299 link,
300 PPP_CONNECT,
301 CONNECT_ARBITRATED_FLAG + (linger ? 0 : CONNECT_AUTOCLOSE_FLAG),
302 data,
303 dataLen,
304 NULL,
305 NULL);
306 return status;
307 }
308
309
310 __private_extern__
311 int
312 PPPDisconnect(int ref, CFStringRef serviceID, uint32_t link, int force)
313 {
314 int status;
315
316 status = PPPExec(ref,
317 serviceID,
318 link,
319 PPP_DISCONNECT,
320 force ? 0 : DISCONNECT_ARBITRATED_FLAG,
321 NULL,
322 0,
323 NULL,
324 NULL);
325 return status;
326 }
327
328
329 __private_extern__
330 int
331 PPPSuspend(int ref, CFStringRef serviceID, uint32_t link)
332 {
333 int status;
334
335 status = PPPExec(ref,
336 serviceID,
337 link,
338 PPP_SUSPEND,
339 0,
340 NULL,
341 0,
342 NULL,
343 NULL);
344 return status;
345 }
346
347
348 __private_extern__
349 int
350 PPPResume(int ref, CFStringRef serviceID, uint32_t link)
351 {
352 int status;
353
354 status = PPPExec(ref,
355 serviceID,
356 link,
357 PPP_RESUME,
358 0,
359 NULL,
360 0,
361 NULL,
362 NULL);
363 return status;
364 }
365
366
367 __private_extern__
368 int
369 PPPGetOption(int ref, CFStringRef serviceID, uint32_t link, uint32_t option, void **data, uint32_t *dataLen)
370 {
371 struct ppp_opt_hdr opt;
372 void *replyBuf = NULL;
373 uint32_t replyBufLen = 0;
374 int status;
375
376 *dataLen = 0;
377 *data = NULL;
378
379 bzero(&opt, sizeof(opt));
380 opt.o_type = option;
381
382 status = PPPExec(ref,
383 serviceID,
384 link,
385 PPP_GETOPTION,
386 0,
387 (void *)&opt,
388 sizeof(opt),
389 &replyBuf,
390 &replyBufLen);
391 if (status != 0) {
392 return status;
393 }
394
395 if (replyBuf && (replyBufLen > sizeof(struct ppp_opt_hdr))) {
396 *dataLen = replyBufLen - sizeof(struct ppp_opt_hdr);
397 *data = CFAllocatorAllocate(NULL, *dataLen, 0);
398 bcopy(((struct ppp_opt *)replyBuf)->o_data, *data, *dataLen);
399 }
400 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
401
402 return status;
403 }
404
405
406 __private_extern__
407 int
408 PPPSetOption(int ref, CFStringRef serviceID, uint32_t link, uint32_t option, void *data, uint32_t dataLen)
409 {
410 void *buf;
411 uint32_t bufLen;
412 int status;
413
414 bufLen = sizeof(struct ppp_opt_hdr) + dataLen;
415 buf = CFAllocatorAllocate(NULL, bufLen, 0);
416
417 bzero((struct ppp_opt_hdr *)buf, sizeof(struct ppp_opt_hdr));
418 ((struct ppp_opt_hdr *)buf)->o_type = option;
419 bcopy(data, ((struct ppp_opt *)buf)->o_data, dataLen);
420
421 status = PPPExec(ref,
422 serviceID,
423 link,
424 PPP_SETOPTION,
425 0,
426 buf,
427 bufLen,
428 NULL,
429 NULL);
430
431 CFAllocatorDeallocate(NULL, buf);
432 return status;
433 }
434
435
436 __private_extern__
437 int
438 PPPGetConnectData(int ref, CFStringRef serviceID, uint32_t link, void **data, uint32_t *dataLen)
439 {
440 int status;
441
442 *dataLen = 0;
443 *data = NULL;
444
445 status = PPPExec(ref,
446 serviceID,
447 link,
448 PPP_GETCONNECTDATA,
449 0,
450 NULL,
451 0,
452 data,
453 dataLen);
454 return status;
455 }
456
457
458 __private_extern__
459 int
460 PPPStatus(int ref, CFStringRef serviceID, uint32_t link, struct ppp_status **stat)
461 {
462 void *replyBuf = NULL;
463 uint32_t replyBufLen = 0;
464 int status;
465
466 *stat = NULL;
467
468 status = PPPExec(ref,
469 serviceID,
470 link,
471 PPP_STATUS,
472 0,
473 NULL,
474 0,
475 &replyBuf,
476 &replyBufLen);
477 if (status != 0) {
478 return status;
479 }
480
481 if (replyBuf && (replyBufLen == sizeof(struct ppp_status))) {
482 *stat = (struct ppp_status *)replyBuf;
483 } else {
484 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
485 status = -1;
486 }
487
488 return status;
489 }
490
491
492 __private_extern__
493 int
494 PPPExtendedStatus(int ref, CFStringRef serviceID, uint32_t link, void **data, uint32_t *dataLen)
495 {
496 int status;
497
498 *dataLen = 0;
499 *data = NULL;
500
501 status = PPPExec(ref,
502 serviceID,
503 link,
504 PPP_EXTENDEDSTATUS,
505 0,
506 NULL,
507 0,
508 data,
509 dataLen);
510 return status;
511 }
512
513
514 __private_extern__
515 int
516 PPPEnableEvents(int ref, CFStringRef serviceID, uint32_t link, u_char enable)
517 {
518 int status;
519 uint32_t lval = 2; // status notifications
520
521 status = PPPExec(ref,
522 serviceID,
523 link,
524 enable ? PPP_ENABLE_EVENT : PPP_DISABLE_EVENT,
525 0,
526 &lval,
527 sizeof(lval),
528 NULL,
529 NULL);
530 return status;
531 }
532
533
534 __private_extern__
535 int
536 PPPReadEvent(int ref, uint32_t *event)
537 {
538
539 *event = PPPExec(ref, NULL, 0, 0, 0, NULL, 0, NULL, NULL);
540 return 0;
541 }
542
543
544 __private_extern__
545 CFDataRef
546 PPPSerialize(CFPropertyListRef obj, void **data, uint32_t *dataLen)
547 {
548 CFDataRef xml;
549
550 xml = CFPropertyListCreateXMLData(NULL, obj);
551 if (xml) {
552 *data = (void*)CFDataGetBytePtr(xml);
553 *dataLen = CFDataGetLength(xml);
554 }
555 return xml;
556 }
557
558
559 __private_extern__
560 CFPropertyListRef
561 PPPUnserialize(void *data, uint32_t dataLen)
562 {
563 CFDataRef xml;
564 CFStringRef xmlError;
565 CFPropertyListRef ref = NULL;
566
567 xml = CFDataCreateWithBytesNoCopy(NULL, data, dataLen, kCFAllocatorNull);
568 if (xml) {
569 ref = CFPropertyListCreateFromXMLData(NULL,
570 xml,
571 kCFPropertyListImmutable,
572 &xmlError);
573 if (!ref) {
574 if (xmlError) {
575 SCLog(TRUE,
576 LOG_ERR,
577 CFSTR("CFPropertyListCreateFromXMLData() failed: %@"),
578 xmlError);
579 CFRelease(xmlError);
580 }
581 }
582
583 CFRelease(xml);
584 }
585
586 return ref;
587 }