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