2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * Nov 7, 2002 Allan Nathanson <ajn@apple.com>
28 * - use ServiceID *or* LinkID
30 * Oct 25, 2002 Christophe Allie <callie@apple.com>
31 * - use ServiceID instead of LinkID
33 * Feb 28, 2002 Christophe Allie <callie@apple.com>
36 * Feb 10, 2001 Allan Nathanson <ajn@apple.com>
39 * Feb 2000 Christophe Allie <callie@apple.com>
45 #include <sys/types.h>
46 #include <sys/errno.h>
47 #include <sys/socket.h>
49 #include <CoreFoundation/CoreFoundation.h>
51 #include <SystemConfiguration/SystemConfiguration.h>
52 #include <SystemConfiguration/SCPrivate.h>
54 #include <ppp/ppp_msg.h>
59 readn(int ref
, void *data
, int len
)
66 if ((n
= read(ref
, p
, left
)) < 0) {
83 writen(int ref
, void *data
, int len
)
90 if ((n
= write(ref
, p
, left
)) <= 0) {
109 struct sockaddr_un sun
;
111 sock
= socket(AF_LOCAL
, SOCK_STREAM
, 0);
113 bzero(&sun
, sizeof(sun
));
114 sun
.sun_family
= AF_LOCAL
;
115 strncpy(sun
.sun_path
, PPP_PATH
, sizeof(sun
.sun_path
));
117 status
= connect(sock
, (struct sockaddr
*)&sun
, sizeof(sun
));
131 if (close(ref
) < 0) {
140 CFStringRef serviceID
,
149 struct ppp_msg_hdr msg
;
152 CFDataRef sID
= NULL
;
154 bzero(&msg
, sizeof(msg
));
156 // first send request, if necessary
161 sID
= CFStringCreateExternalRepresentation(NULL
,
163 kCFStringEncodingUTF8
,
165 // serviceID is present, use it
166 msg
.m_flags
|= USE_SERVICEID
;
167 msg
.m_link
= CFDataGetLength(sID
);
169 // no service ID, use the requested link
172 msg
.m_len
= ((request
!= NULL
) && (requestLen
> 0)) ? requestLen
: 0;
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
);
182 if (writen(ref
, (void *)CFDataGetBytePtr(sID
), msg
.m_link
) < 0) {
183 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPPExec write() failed: %s"), strerror(errno
));
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
));
198 // then read replies or incoming message
199 n
= readn(ref
, &msg
, sizeof(msg
));
201 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno
));
203 } else if (n
!= sizeof(msg
)) {
204 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPPExec readn() failed: insufficent data, read=%d"), n
);
208 if ((msg
.m_flags
& USE_SERVICEID
) && msg
.m_link
) {
209 buf
= CFAllocatorAllocate(NULL
, msg
.m_link
, 0);
212 n
= readn(ref
, buf
, msg
.m_link
);
214 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno
));
215 CFAllocatorDeallocate(NULL
, buf
);
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
);
222 // buf contains the service id we passed in the request
223 CFAllocatorDeallocate(NULL
, buf
);
229 buf
= CFAllocatorAllocate(NULL
, msg
.m_len
, 0);
232 n
= readn(ref
, buf
, msg
.m_len
);
234 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPPExec readn() failed: error=%s"), strerror(errno
));
235 CFAllocatorDeallocate(NULL
, buf
);
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
);
245 if (reply
&& replyLen
) {
247 *replyLen
= msg
.m_len
;
249 // if additional returned data is unwanted
250 CFAllocatorDeallocate(NULL
, buf
);
259 PPPGetLinkByInterface(int ref
, char *if_name
, uint32_t *link
)
261 void *replyBuf
= NULL
;
262 uint32_t replyBufLen
= 0;
265 status
= PPPExec(ref
,
278 if (replyBuf
&& (replyBufLen
== sizeof(uint32_t))) {
279 *link
= *(uint32_t *)replyBuf
;
281 status
= -2; /* if not found */
283 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);
291 PPPConnect(int ref
, CFStringRef serviceID
, uint32_t link
, void *data
, uint32_t dataLen
, int linger
)
295 status
= PPPExec(ref
,
299 CONNECT_ARBITRATED_FLAG
+ (linger
? 0 : CONNECT_AUTOCLOSE_FLAG
),
310 PPPDisconnect(int ref
, CFStringRef serviceID
, uint32_t link
, int force
)
314 status
= PPPExec(ref
,
318 force
? 0 : DISCONNECT_ARBITRATED_FLAG
,
329 PPPSuspend(int ref
, CFStringRef serviceID
, uint32_t link
)
333 status
= PPPExec(ref
,
348 PPPResume(int ref
, CFStringRef serviceID
, uint32_t link
)
352 status
= PPPExec(ref
,
367 PPPGetOption(int ref
, CFStringRef serviceID
, uint32_t link
, uint32_t option
, void **data
, uint32_t *dataLen
)
369 struct ppp_opt_hdr opt
;
370 void *replyBuf
= NULL
;
371 uint32_t replyBufLen
= 0;
377 bzero(&opt
, sizeof(opt
));
380 status
= PPPExec(ref
,
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
);
398 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);
406 PPPSetOption(int ref
, CFStringRef serviceID
, uint32_t link
, uint32_t option
, void *data
, uint32_t dataLen
)
412 bufLen
= sizeof(struct ppp_opt_hdr
) + dataLen
;
413 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
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
);
419 status
= PPPExec(ref
,
429 CFAllocatorDeallocate(NULL
, buf
);
436 PPPGetConnectData(int ref
, CFStringRef serviceID
, uint32_t link
, void **data
, uint32_t *dataLen
)
443 status
= PPPExec(ref
,
458 PPPStatus(int ref
, CFStringRef serviceID
, uint32_t link
, struct ppp_status
**stat
)
460 void *replyBuf
= NULL
;
461 uint32_t replyBufLen
= 0;
466 status
= PPPExec(ref
,
479 if (replyBuf
&& (replyBufLen
== sizeof(struct ppp_status
))) {
480 *stat
= (struct ppp_status
*)replyBuf
;
482 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);
492 PPPExtendedStatus(int ref
, CFStringRef serviceID
, uint32_t link
, void **data
, uint32_t *dataLen
)
499 status
= PPPExec(ref
,
514 PPPEnableEvents(int ref
, CFStringRef serviceID
, uint32_t link
, u_char enable
)
517 uint32_t lval
= 2; // status notifications
519 status
= PPPExec(ref
,
522 enable
? PPP_ENABLE_EVENT
: PPP_DISABLE_EVENT
,
534 PPPReadEvent(int ref
, uint32_t *event
)
537 *event
= PPPExec(ref
, NULL
, 0, 0, 0, NULL
, 0, NULL
, NULL
);
544 PPPSerialize(CFPropertyListRef obj
, void **data
, uint32_t *dataLen
)
548 xml
= CFPropertyListCreateXMLData(NULL
, obj
);
550 *data
= (void*)CFDataGetBytePtr(xml
);
551 *dataLen
= CFDataGetLength(xml
);
559 PPPUnserialize(void *data
, uint32_t dataLen
)
562 CFStringRef xmlError
;
563 CFPropertyListRef ref
= NULL
;
565 xml
= CFDataCreateWithBytesNoCopy(NULL
, data
, dataLen
, kCFAllocatorNull
);
567 ref
= CFPropertyListCreateFromXMLData(NULL
,
569 kCFPropertyListImmutable
,
575 CFSTR("CFPropertyListCreateFromXMLData() failed: %@"),