1/*
2 * Copyright (c) 2002, 2003, 2005, 2013, 2014 Apple 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 * May 29, 2002		Roger Smith <rsmith@apple.com>
28 * - initial revision
29 */
30
31#include <stdio.h>
32#include <unistd.h>
33#include <sys/types.h>
34#include <sys/errno.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37
38#include <SystemConfiguration/SystemConfiguration.h>
39#include <SystemConfiguration/SCPrivate.h>
40
41#include "moh.h"
42#include "moh_msg.h"
43
44// Note: right now we are not currently using the deviceName.  This could be the raw
45//       tty name such as "modem" since this is guaranteed to be unique in the /dev.
46//       We would use this deviceName to differientate between multiple MOH devices
47//       present in the system when we create the socket.
48
49
50static ssize_t
51readn(int ref, void *data, size_t len)
52{
53	size_t	left	= len;
54	ssize_t	n;
55	void	*p	= data;
56
57	while (left > 0) {
58		if ((n = read(ref, p, left)) == -1) {
59			if (errno != EINTR) {
60				return -1;
61			}
62			n = 0;
63		} else if (n == 0) {
64			break; /* EOF */
65		}
66
67		left -= n;
68		p += n;
69	}
70	return (len - left);
71}
72
73
74static ssize_t
75writen(int ref, const void *data, size_t len)
76{
77	size_t		left	= len;
78	ssize_t		n;
79	const void	*p	= data;
80
81	while (left > 0) {
82		if ((n = write(ref, p, left)) == -1) {
83			if (errno != EINTR) {
84				return -1;
85			}
86			n = 0;
87		}
88		left -= n;
89		p += n;
90	}
91	return len;
92}
93
94
95__private_extern__
96int
97MOHInit(int *ref, CFStringRef deviceName)
98{
99	int			sock;
100	int			status;
101	struct sockaddr_un	sun;
102
103	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
104
105	bzero(&sun, sizeof(sun));
106	sun.sun_family = AF_LOCAL;
107	strncpy(sun.sun_path, MOH_PATH, sizeof(sun.sun_path));
108
109	status = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
110	if (status == -1) {
111		return errno;
112	}
113
114	*ref = sock;
115	return 0;
116}
117
118
119__private_extern__
120int
121MOHDispose(int ref)
122{
123	if (close(ref) == -1) {
124		return errno;
125	}
126	return 0;
127}
128
129
130__private_extern__
131int
132MOHExec(int		ref,
133	uint32_t	link,
134	uint32_t	cmd,
135	void		*request,
136	size_t		requestLen,
137	void		**reply,
138	size_t		*replyLen)
139{
140	struct moh_msg_hdr	msg;
141	char			*buf		= NULL;
142	ssize_t			n;
143
144	bzero(&msg, sizeof(msg));
145	msg.m_type = cmd;
146	msg.m_link = link;
147	msg.m_len  = ((request != NULL) && (requestLen > 0)) ? (uint32_t)requestLen : 0;
148
149	//  send the command
150	n = writen(ref, &msg, sizeof(msg));
151	if (n == -1) {
152		SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec writen() failed: %s"), strerror(errno));
153		return errno;
154	} else if (n != sizeof(msg)) {
155		SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec writen() failed: wrote=%ld"), n);
156		return -1;
157	}
158
159	if ((request != NULL) && (requestLen > 0)) {
160		n = writen(ref, request, requestLen);
161		if (n == -1) {
162			SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec writen() failed: %s"), strerror(errno));
163			return errno;
164		} else if (n != (ssize_t)requestLen) {
165			SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec writen() failed: wrote=%ld"), n);
166			return -1;
167		}
168	}
169
170	// always expect a reply
171	n = readn(ref, &msg, sizeof(msg));
172	if (n == -1) {
173		SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec readn() failed: error=%s"), strerror(errno));
174		return errno;
175	} else if (n != sizeof(msg)) {
176		SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec readn() failed: insufficent data, read=%ld"), n);
177		return -1;
178	}
179
180	if (msg.m_len) {
181		buf = CFAllocatorAllocate(NULL, msg.m_len, 0);
182		if (buf) {
183			// read reply
184			n = readn(ref, buf, msg.m_len);
185			if (n == -1) {
186				SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec readn() failed: error=%s"), strerror(errno));
187				CFAllocatorDeallocate(NULL, buf);
188				return errno;
189			} else if (n != (ssize_t)msg.m_len) {
190				SCLog(_sc_verbose, LOG_ERR, CFSTR("MOHExec readn() failed: insufficent data, read=%ld"), n);
191				CFAllocatorDeallocate(NULL, buf);
192				return -1;
193			}
194		}
195	}
196
197	if (reply && replyLen) {
198		*reply    = buf;
199		*replyLen = msg.m_len;
200	} else if (buf) {
201		// if additional returned data is unwanted
202		CFAllocatorDeallocate(NULL, buf);
203	}
204
205	return msg.m_result;
206}
207
208