1/*
2 *  Copyright (c) 2000-2007 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 *  winscard_msg.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 2001-2004
33 *  David Corcoran <corcoran@linuxnet.com>
34 *  Damien Sauveron <damien.sauveron@labri.fr>
35 *  Ludoic Rousseau <ludovic.rousseau@free.fr>
36 *
37 * $Id: winscard_msg.cpp 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
38 */
39
40/**
41 * @file
42 * @brief This is responsible for client/server communication.
43 *
44 * A file based socket (\c commonSocket) is used to send/receive only messages
45 * among clients and server.\n
46 * The messages' data are passed throw a memory mapped file: \c sharedSegmentMsg.
47 */
48
49#include "config.h"
50#include <fcntl.h>
51#include <unistd.h>
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <sys/socket.h>
55#include <sys/time.h>
56#include <sys/un.h>
57#include <sys/ioctl.h>
58#include <errno.h>
59#include <stdio.h>
60#include <time.h>
61#include <string.h>
62#ifdef HAVE_SYS_FILIO_H
63#include <sys/filio.h>
64#endif
65
66#include "wintypes.h"
67#include "pcsclite.h"
68#include "pcscexport.h"
69#include "winscard.h"
70#include "debug.h"
71#include "winscard_msg.h"
72#include "sys_generic.h"
73
74#include <libkern/OSByteOrder.h>
75/*
76 #define bswap_16 OSSwapInt16
77#define bswap_32 OSSwapInt32
78#define bswap_64 OSSwapInt64
79*/
80
81#include <security_utilities/debugging.h>
82
83/**
84 * @brief Wrapper for the SHMMessageReceive() function.
85 *
86 * Called by clients to read the server responses.
87 *
88 * @param[out] msgStruct Message read.
89 * @param[in] dwClientID Client socket handle.
90 * @param[in] blockamount Timeout in milliseconds.
91 *
92 * @return Same error codes as SHMMessageReceive().
93 */
94INTERNAL int32_t SHMClientRead(psharedSegmentMsg msgStruct, uint32_t dwClientID, int32_t blockamount)
95{
96	int rv = SHMMessageReceive(msgStruct, sizeof(*msgStruct), dwClientID, blockamount);
97	SHSharedSegmentMsgToHostOrder(msgStruct);
98	return rv;
99}
100
101/**
102 * @brief Wrapper for the SHMMessageReceive() function.
103 *
104 * Called by clients to read the server responses. This reads the exact number of bytes expected for the struct
105 *
106 * @param[out] msgStruct Message read.
107 * @param[in] dwClientID Client socket handle.
108 * @param[in] dataSize Size of the data at msgStruct->data
109 * @param[in] blockamount Timeout in milliseconds.
110 *
111 * @return Same error codes as SHMMessageReceive().
112 */
113INTERNAL int32_t SHMClientReadMessage(psharedSegmentMsg msgStruct, uint32_t dwClientID, size_t dataSize, int32_t blockamount)
114{
115	// Read the basic header first so we know the size of the rest
116	// The special case of "dataSize == 0" means that we should deduce the size of the
117	// data from the header
118	size_t headerSize = sizeof(sharedSegmentMsg) - sizeof(msgStruct->data);
119	Log2(PCSC_LOG_DEBUG, "SHMClientReadMessage: Issuing read for %d bytes (header)", headerSize);
120	secdebug("pcscd", "SHMClientReadMessage: Issuing read for %ld bytes (header)", headerSize);
121	int rv = SHMMessageReceive(msgStruct, headerSize, dwClientID, blockamount);
122	Log3(rv?PCSC_LOG_CRITICAL:PCSC_LOG_DEBUG, "SHMClientReadMessage: read message header error: 0x%08X [0x%08X]", rv, rv);
123	secdebug("pcscd", "SHMClientReadMessage: read message header error: 0x%08X [0x%08X]", rv, rv);
124	if (rv)
125		return rv;
126	SHSharedSegmentMsgToHostOrder(msgStruct);
127
128	// Integrity check
129	if (msgStruct->headerTag != WINSCARD_MSG_HEADER_TAG)
130	{
131		Log3(PCSC_LOG_CRITICAL, "Error: read message header tag of: 0x%08X for possible command 0x%08X",
132			msgStruct->headerTag, msgStruct->command);
133		secdebug("pcscd", "Error: read message header tag of: 0x%08X for possible command 0x%08X",
134			msgStruct->headerTag, msgStruct->command);
135		return SCARD_F_INTERNAL_ERROR;
136	}
137
138	if (dataSize == 0)
139		dataSize = msgStruct->msgSize - headerSize;		// message size includes header
140	else
141	if (msgStruct->msgSize != (headerSize + dataSize))
142	{
143		Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", strerror(errno));
144		secdebug("pcscd", "Error: create on client socket: %s", strerror(errno));
145		return SCARD_F_INTERNAL_ERROR;
146	}
147
148	Log2(PCSC_LOG_DEBUG, "SHMClientReadMessage: Issuing read for %d bytes", dataSize);
149	secdebug("pcscd", "SHMClientReadMessage: Issuing read for %ld bytes", dataSize);
150	if (blockamount == 0)
151		blockamount = PCSCLITE_SERVER_ATTEMPTS;
152	rv = SHMMessageReceive(msgStruct->data, dataSize, dwClientID, blockamount);
153	Log3(rv?PCSC_LOG_CRITICAL:PCSC_LOG_DEBUG, "SHMClientReadMessage: read message body error: 0x%08X [0x%08X]", rv, rv);
154	secdebug("pcscd", "SHMClientReadMessage: read message body error: 0x%08X [0x%08X]", rv, rv);
155
156	return rv;
157}
158
159/**
160 * @brief Prepares a communication channel for the client to talk to the server.
161 *
162 * This is called by the application to create a socket for local IPC with the
163 * server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME.
164 *
165 * @param[out] pdwClientID Client Connection ID.
166 *
167 * @retval 0 Success.
168 * @retval -1 Can not create the socket.
169 * @retval -1 The socket can not open a connection.
170 * @retval -1 Can not set the socket to non-blocking.
171 */
172INTERNAL int SHMClientSetupSession(uint32_t *pdwClientID)
173{
174	struct sockaddr_un svc_addr;
175	int one;
176	int ret;
177
178	ret = socket(AF_UNIX, SOCK_STREAM, 0);
179	if (ret < 0)
180	{
181		Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
182			strerror(errno));
183		return -1;
184	}
185	*pdwClientID = ret;
186
187	svc_addr.sun_family = AF_UNIX;
188	strncpy(svc_addr.sun_path, PCSCLITE_CSOCK_NAME,
189		sizeof(svc_addr.sun_path));
190
191	if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
192			sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
193	{
194		Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
195			PCSCLITE_CSOCK_NAME, strerror(errno));
196		SYS_CloseFile(*pdwClientID);
197		return -1;
198	}
199
200	one = 1;
201	if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
202	{
203		Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
204			PCSCLITE_CSOCK_NAME, strerror(errno));
205		SYS_CloseFile(*pdwClientID);
206		return -1;
207	}
208
209	return 0;
210}
211
212/**
213 * @brief Closes the socket used by the client to communicate with the server.
214 *
215 * @param[in] dwClientID Client socket handle to be closed.
216 *
217 * @retval 0 Success.
218 */
219INTERNAL int SHMClientCloseSession(uint32_t dwClientID)
220{
221	SYS_CloseFile(dwClientID);
222	return 0;
223}
224
225/**
226 * @brief CalculateMessageSize
227 *
228 * @param[in] dataSize Size of the additional data to send in the message.
229 *
230 * @retval total message size.
231 */
232INTERNAL size_t SHMCalculateMessageSize(size_t dataSize)
233{
234	// PCSCLITE_MAX_MESSAGE_SIZE == sizeof(sharedSegmentMsg.data)
235	return sizeof(sharedSegmentMsg) - PCSCLITE_MAX_MESSAGE_SIZE + dataSize;;
236}
237
238
239/**
240 * @brief Sends a menssage from client to server or vice-versa.
241 *
242 * Writes the message in the shared file \c filedes.
243 *
244 * @param[in] buffer_void Message to be sent.
245 * @param[in] buffer_size Size of the message to send
246 * @param[in] filedes Socket handle.
247 * @param[in] blockAmount Timeout in milliseconds.
248 *
249 * @retval 0 Success
250 * @retval -1 Timeout.
251 * @retval -1 Socket is closed.
252 * @retval -1 A signal was received.
253 */
254INTERNAL int SHMMessageSend(void *buffer_void, uint64_t buffer_size,
255	int32_t filedes, int32_t blockAmount)
256{
257	char *buffer = (char *)buffer_void;
258
259	/*
260	 * default is success
261	 */
262	int retval = 0;
263	/*
264	 * record the time when we started
265	 */
266	time_t start = time(0);
267	/*
268	 * how many bytes remains to be written
269	 */
270	size_t remaining = buffer_size;
271
272	LogXxd(PCSC_LOG_DEBUG, "==> SHMMessageSend:\n", (const unsigned char *)buffer, buffer_size);
273
274	/*
275	 * repeat until all data is written
276	 */
277	while (remaining > 0)
278	{
279		fd_set write_fd;
280		struct timeval timeout;
281		int selret;
282
283		FD_ZERO(&write_fd);
284		FD_SET(filedes, &write_fd);
285
286		timeout.tv_usec = 0;
287		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
288		{
289			/*
290			 * we already timed out
291			 */
292			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: we already timed out");
293			retval = -1;
294			break;
295		}
296
297		selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout);
298
299		/*
300		 * try to write only when the file descriptor is writable
301		 */
302		if (selret > 0)
303		{
304			int written;
305
306			if (!FD_ISSET(filedes, &write_fd))
307			{
308				/*
309				 * very strange situation. it should be an assert really
310				 */
311				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: very strange situation: !FD_ISSET");
312				retval = -1;
313				break;
314			}
315			written = write(filedes, buffer, remaining);
316
317			if (written > 0)
318			{
319				/*
320				 * we wrote something
321				 */
322				buffer += written;
323				remaining -= written;
324			} else if (written == 0)
325			{
326				/*
327				 * peer closed the socket
328				 */
329				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: peer closed the socket");
330				retval = -1;
331				break;
332			} else
333			{
334				/*
335				 * we ignore the signals and socket full situations, all
336				 * other errors are fatal
337				 */
338				if (errno != EINTR && errno != EAGAIN)
339				{
340					retval = -1;
341					break;
342				}
343			}
344		} else if (selret == 0)
345		{
346			/*
347			 * timeout
348			 */
349			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: selret == 0 [timeout]");
350			retval = -1;
351			break;
352		} else
353		{
354			/*
355			 * ignore signals
356			 */
357			if (errno != EINTR)
358			{
359				Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
360					strerror(errno));
361				retval = -1;
362				break;
363			}
364		}
365	}
366
367	if (remaining > 0)
368		Log3(PCSC_LOG_ERROR, "failure to write all bytes, remaining: %d, err: ", remaining, strerror(errno));
369
370	return retval;
371}
372
373/**
374 * @brief Called by the Client to get the reponse from the server or vice-versa.
375 *
376 * Reads the message from the file \c filedes.
377 *
378 * @param[out] buffer_void Message read.
379 * @param[in] buffer_size Size to read
380 * @param[in] filedes Socket handle.
381 * @param[in] blockAmount Timeout in milliseconds.
382 *
383 * @retval 0 Success.
384 * @retval -1 Timeout.
385 * @retval -1 Socket is closed.
386 * @retval -1 A signal was received.
387 */
388INTERNAL int SHMMessageReceive(void *buffer_void, uint64_t buffer_size,
389	int32_t filedes, int32_t blockAmount)
390{
391	char *buffer = (char *)buffer_void;
392
393	/*
394	 * default is success
395	 */
396	int retval = 0;
397	/*
398	 * record the time when we started
399	 */
400	time_t start = time(0);
401	/*
402	 * how many bytes we must read
403	 */
404	size_t remaining = buffer_size;
405
406	/*
407	 * repeat until we get the whole message
408	 */
409	while (remaining > 0)
410	{
411		fd_set read_fd;
412		struct timeval timeout;
413		int selret;
414
415		FD_ZERO(&read_fd);
416		FD_SET(filedes, &read_fd);
417
418		timeout.tv_usec = 0;
419		if ((timeout.tv_sec = start + blockAmount - time(0)) < 0)
420		{
421			/*
422			 * we already timed out
423			 */
424			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: we already timed out");
425			retval = -1;
426			break;
427		}
428
429		selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
430
431		/*
432		 * try to read only when socket is readable
433		 */
434		if (selret > 0)
435		{
436			int readed;
437
438			if (!FD_ISSET(filedes, &read_fd))
439			{
440				/*
441				 * very strange situation. it should be an assert really
442				 */
443				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: very strange situation: !FD_ISSET");
444				retval = -1;
445				break;
446			}
447			readed = read(filedes, buffer, remaining);
448
449			if (readed > 0)
450			{
451				/*
452				 * we got something
453				 */
454				buffer += readed;
455				remaining -= readed;
456			} else if (readed == 0)
457			{
458				/*
459				 * peer closed the socket
460				 */
461				Log1(PCSC_LOG_ERROR, "SHMMessageReceive: peer closed the socket");
462				retval = -1;
463				break;
464			} else
465			{
466				/*
467				 * we ignore the signals and empty socket situations, all
468				 * other errors are fatal
469				 */
470				if (errno != EINTR && errno != EAGAIN)
471				{
472					retval = -1;
473					break;
474				}
475			}
476		} else if (selret == 0)
477		{
478			/*
479			 * timeout
480			 */
481			Log1(PCSC_LOG_ERROR, "SHMMessageReceive: selret == 0 [timeout]");
482			retval = -1;
483			break;
484		} else
485		{
486			/*
487			 * we ignore signals, all other errors are fatal
488			 */
489			if (errno != EINTR)
490			{
491				Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
492					strerror(errno));
493				retval = -1;
494				break;
495			}
496		}
497	}
498
499	size_t bytesRead = (buffer_size - remaining);
500	Log3(PCSC_LOG_DEBUG, "SHMMessageReceive errno: 0x%08X: %s", errno, errno?strerror(errno):"no error");
501	Log3(retval?PCSC_LOG_ERROR:PCSC_LOG_DEBUG, "SHMMessageReceive retval: 0x%08X, bytes read: %d", retval, bytesRead);
502	LogXxd(PCSC_LOG_DEBUG, "<== SHMMessageReceive:\n", (const unsigned char *)buffer_void, bytesRead);
503	return retval;
504}
505
506/**
507 * @brief Wrapper for the SHMMessageSend() function.
508 *
509 * Called by clients to send messages to the server.
510 * The parameters \p command and \p data are set in the \c sharedSegmentMsg
511 * struct in order to be sent.
512 *
513 * @param[in] command Command to be sent.
514 * @param[in] dwClientID Client socket handle.
515 * @param[in] size Size of the message (\p data).
516 * @param[in] blockAmount Timeout to the operation in ms.
517 * @param[in] data_void Data to be sent.
518 *
519 * @return Same error codes as SHMMessageSend().
520 */
521INTERNAL int32_t WrapSHMWrite(uint32_t command, uint32_t dwClientID,
522	uint64_t size, uint32_t blockAmount, void *data_void)
523{
524	char *data = (char *)data_void;
525
526	sharedSegmentMsg msgStruct;
527	int ret;
528
529	/*
530	 * Set the appropriate packet parameters
531	 */
532
533	memset(&msgStruct, 0, sizeof(msgStruct));
534	msgStruct.headerTag = WINSCARD_MSG_HEADER_TAG;
535	msgStruct.msgSize = sizeof(sharedSegmentMsg) - sizeof(msgStruct.data) + size;
536	msgStruct.mtype = (command == CMD_VERSION)?CMD_VERSION:CMD_FUNCTION;
537	msgStruct.user_id = SYS_GetUID();
538	msgStruct.group_id = SYS_GetGID();
539	msgStruct.command = command;
540	msgStruct.date = time(NULL);
541	memset(msgStruct.key, 0, sizeof(msgStruct.key));
542
543	if ((SCARD_TRANSMIT_EXTENDED == command)
544		|| (SCARD_CONTROL_EXTENDED == command))
545	{
546		/* first block */
547		size_t sizeToSend = (msgStruct.msgSize <= PCSCLITE_MAX_MESSAGE_SIZE)?msgStruct.msgSize:PCSCLITE_MAX_MESSAGE_SIZE;
548		size_t sizeRemaining = (msgStruct.msgSize <= PCSCLITE_MAX_MESSAGE_SIZE)?0:
549			(msgStruct.msgSize - PCSCLITE_MAX_MESSAGE_SIZE);
550		memcpy(msgStruct.data, data, sizeToSend);
551
552		SHSharedSegmentMsgToNetworkOrder(&msgStruct);
553		ret = SHMMessageSend(&msgStruct, sizeToSend, dwClientID, blockAmount);
554		if (ret)
555			return ret;
556
557		// Warning: this code only works for sizes of 2 blocks or less
558		if (sizeRemaining > sizeof(msgStruct.data))
559		{
560			Log2(PCSC_LOG_ERROR, "WrapSHMWrite: cannot send message of size %d", sizeRemaining);
561			return -1;
562		}
563
564		// Message header already has the correct byte order
565		/* do not send an empty second block */
566		if (sizeRemaining > 0)
567		{
568			memcpy(msgStruct.data, data, sizeRemaining);
569			ret = SHMMessageSend(&msgStruct, sizeToSend, dwClientID, blockAmount);
570			if (ret)
571				return ret;
572		}
573	}
574	else
575	if (size > sizeof(msgStruct.data))
576	{
577		Log3(PCSC_LOG_ERROR, "WrapSHMWrite: cannot send message of size %d with this command: %d", size, command);
578		return -1;
579	}
580	else
581	{
582		size_t sizeToSend = msgStruct.msgSize;
583		memcpy(msgStruct.data, data, size);
584		SHSharedSegmentMsgToNetworkOrder(&msgStruct);
585		ret = SHMMessageSend(&msgStruct, sizeToSend, dwClientID, blockAmount);
586	}
587	return ret;
588}
589
590/**
591 * @brief Closes the communications channel used by the server to talk to the
592 * clients.
593 *
594 * The socket used is closed and the file it is bound to is removed.
595 *
596 * @param[in] sockValue Socket to be closed.
597 * @param[in] pcFilePath File used by the socket.
598 */
599INTERNAL void SHMCleanupSharedSegment(int sockValue, const char *pcFilePath)
600{
601	SYS_CloseFile(sockValue);
602	SYS_Unlink((char *)pcFilePath);
603}
604
605#pragma mark -------------------- Byte ordering functions --------------------
606
607/**
608 * @brief Convert fields in the psharedSegmentMsg struct to network byte order for sending
609 *
610 * Call this before each call to SHMMessageSend. Note: the data fields are not processed
611 * and need to be done individually. Also have to look for WrapSHMWrite.
612 *
613 * @param[in/out] msgStruct Message read.
614 *
615 */
616INTERNAL void SHSharedSegmentMsgToNetworkOrder(psharedSegmentMsg msg)
617{
618	if (msg)
619	{
620		msg->headerTag = htonl(msg->headerTag);
621		msg->msgSize = htonl(msg->msgSize);
622		msg->mtype = htonl(msg->mtype);
623		msg->user_id = htonl(msg->user_id);
624		msg->group_id = htonl(msg->group_id);
625		msg->command = htonl(msg->command);
626		msg->date = htonl(msg->date);
627	}
628}
629
630/**
631 * @brief Convert fields in the psharedSegmentMsg struct to host byte order on receive
632 *
633 * Call this after each call to SHMMessageReceive. Note: the data fields are not processed
634 * and need to be done individually, e.g. in MSGFunctionDemarshall
635 *
636 * @param[in/out] msgStruct Message read.
637 *
638 */
639INTERNAL void SHSharedSegmentMsgToHostOrder(psharedSegmentMsg msg)
640{
641	if (msg)
642	{
643		msg->headerTag = ntohl(msg->headerTag);
644		msg->msgSize = ntohl(msg->msgSize);
645		msg->mtype = ntohl(msg->mtype);
646		msg->user_id = ntohl(msg->user_id);
647		msg->group_id = ntohl(msg->group_id);
648		msg->command = ntohl(msg->command);
649		msg->date = ntohl(msg->date);
650	}
651}
652
653INTERNAL void htonlControlStructExtended(control_struct_extended *cs)
654{
655	if (cs)
656	{
657		cs->hCard = htonl(cs->hCard);
658		cs->dwControlCode = htonl(cs->dwControlCode);
659		cs->cbSendLength = htonl(cs->cbSendLength);
660		cs->cbRecvLength = htonl(cs->cbRecvLength);
661		cs->size = OSSwapHostToBigInt64(cs->size);
662		cs->rv = htonl(cs->rv);			// so we don't forget about it
663	}
664}
665
666INTERNAL void ntohlControlStructExtended(control_struct_extended *cs)
667{
668	if (cs)
669	{
670		cs->hCard = ntohl(cs->hCard);
671		cs->dwControlCode = ntohl(cs->dwControlCode);
672		cs->cbSendLength = ntohl(cs->cbSendLength);
673		cs->cbRecvLength = ntohl(cs->cbRecvLength);
674		cs->size = OSSwapBigToHostInt64(cs->size);
675		cs->rv = ntohl(cs->rv);
676	}
677}
678
679INTERNAL void htonlTransmitStruct(transmit_struct *ts)
680{
681	if (ts)
682	{
683		ts->hCard = htonl(ts->hCard);
684		ts->pioSendPciProtocol = htonl(ts->pioSendPciProtocol);
685		ts->pioSendPciLength = htonl(ts->pioSendPciLength);
686		ts->cbSendLength = htonl(ts->cbSendLength);
687		ts->pioRecvPciProtocol = htonl(ts->pioRecvPciProtocol);
688		ts->pioRecvPciLength = htonl(ts->pioRecvPciLength);
689		ts->pcbRecvLength = htonl(ts->pcbRecvLength);
690		ts->rv = htonl(ts->rv);			// so we don't forget about it
691	}
692}
693
694INTERNAL void ntohlTransmitStruct(transmit_struct *ts)
695{
696	if (ts)
697	{
698		ts->hCard = ntohl(ts->hCard);
699		ts->pioSendPciProtocol = ntohl(ts->pioSendPciProtocol);
700		ts->pioSendPciLength = ntohl(ts->pioSendPciLength);
701		ts->cbSendLength = ntohl(ts->cbSendLength);
702		ts->pioRecvPciProtocol = ntohl(ts->pioRecvPciProtocol);
703		ts->pioRecvPciLength = ntohl(ts->pioRecvPciLength);
704		ts->pcbRecvLength = ntohl(ts->pcbRecvLength);
705		ts->rv = ntohl(ts->rv);
706	}
707}
708
709INTERNAL void htonlTransmitStructExtended(transmit_struct_extended *ts)
710{
711	if (ts)
712	{
713		ts->hCard = htonl(ts->hCard);
714		ts->pioSendPciProtocol = htonl(ts->pioSendPciProtocol);
715		ts->pioSendPciLength = htonl(ts->pioSendPciLength);
716		ts->cbSendLength = htonl(ts->cbSendLength);
717		ts->pioRecvPciProtocol = htonl(ts->pioRecvPciProtocol);
718		ts->pioRecvPciLength = htonl(ts->pioRecvPciLength);
719		ts->pcbRecvLength = htonl(ts->pcbRecvLength);
720		/* Networks generally use big-endian order, and thus it is called network order when sending information over a network in a common format. */
721		ts->size = OSSwapHostToBigInt64(ts->size);
722		ts->rv = htonl(ts->rv);			// so we don't forget about it
723	}
724}
725
726INTERNAL void ntohlTransmitStructExtended(transmit_struct_extended *ts)
727{
728	if (ts)
729	{
730		ts->hCard = ntohl(ts->hCard);
731		ts->pioSendPciProtocol = ntohl(ts->pioSendPciProtocol);
732		ts->pioSendPciLength = ntohl(ts->pioSendPciLength);
733		ts->cbSendLength = ntohl(ts->cbSendLength);
734		ts->pioRecvPciLength = ntohl(ts->pioRecvPciLength);
735		ts->pcbRecvLength = ntohl(ts->pcbRecvLength);
736		ts->size = OSSwapBigToHostInt64(ts->size);
737		ts->rv = ntohl(ts->rv);
738	}
739}
740
741INTERNAL void htonlEstablishStruct(establish_struct *es)
742{
743	if (es)
744	{
745		es->dwScope = htonl(es->dwScope);
746		es->phContext = htonl(es->phContext);
747		es->rv = htonl(es->rv);
748	}
749}
750
751INTERNAL void ntohlEstablishStruct(establish_struct *es)
752{
753	if (es)
754	{
755		es->dwScope = ntohl(es->dwScope);
756		es->phContext = ntohl(es->phContext);
757		es->rv = ntohl(es->rv);
758	}
759}
760
761INTERNAL void htonlReleaseStruct(release_struct *rs)
762{
763	if (rs)
764	{
765		rs->hContext = htonl(rs->hContext);
766		rs->rv = htonl(rs->rv);
767	}
768}
769
770INTERNAL void ntohlReleaseStruct(release_struct *rs)
771{
772	if (rs)
773	{
774		rs->hContext = ntohl(rs->hContext);
775		rs->rv = ntohl(rs->rv);
776	}
777}
778
779INTERNAL void htonlConnectStruct(connect_struct *cs)
780{
781	if (cs)
782	{
783		cs->hContext = htonl(cs->hContext);
784		cs->dwShareMode = htonl(cs->dwShareMode);
785		cs->dwPreferredProtocols = htonl(cs->dwPreferredProtocols);
786		cs->phCard = htonl(cs->phCard);
787		cs->pdwActiveProtocol = htonl(cs->pdwActiveProtocol);
788		cs->rv = htonl(cs->rv);
789	}
790}
791
792INTERNAL void ntohlConnectStruct(connect_struct *cs)
793{
794	if (cs)
795	{
796		cs->hContext = ntohl(cs->hContext);
797		cs->dwShareMode = ntohl(cs->dwShareMode);
798		cs->dwPreferredProtocols = ntohl(cs->dwPreferredProtocols);
799		cs->phCard = ntohl(cs->phCard);
800		cs->pdwActiveProtocol = ntohl(cs->pdwActiveProtocol);
801		cs->rv = ntohl(cs->rv);
802	}
803}
804
805INTERNAL void htonlReconnectStruct(reconnect_struct *rc)
806{
807	if (rc)
808	{
809		rc->hCard = htonl(rc->hCard);
810		rc->dwShareMode = htonl(rc->dwShareMode);
811		rc->dwPreferredProtocols = htonl(rc->dwPreferredProtocols);
812		rc->dwInitialization = htonl(rc->dwInitialization);
813		rc->pdwActiveProtocol = htonl(rc->pdwActiveProtocol);
814		rc->rv = htonl(rc->rv);
815	}
816}
817
818INTERNAL void ntohlReconnectStruct(reconnect_struct *rc)
819{
820	if (rc)
821	{
822		rc->hCard = ntohl(rc->hCard);
823		rc->dwShareMode = ntohl(rc->dwShareMode);
824		rc->dwPreferredProtocols = ntohl(rc->dwPreferredProtocols);
825		rc->dwInitialization = ntohl(rc->dwInitialization);
826		rc->pdwActiveProtocol = ntohl(rc->pdwActiveProtocol);
827		rc->rv = ntohl(rc->rv);
828	}
829}
830
831INTERNAL void htonlDisconnectStruct(disconnect_struct *dc)
832{
833	if (dc)
834	{
835		dc->hCard = htonl(dc->hCard);
836		dc->dwDisposition = htonl(dc->dwDisposition);
837		dc->rv = htonl(dc->rv);
838	}
839}
840
841INTERNAL void ntohlDisconnectStruct(disconnect_struct *dc)
842{
843	if (dc)
844	{
845		dc->hCard = ntohl(dc->hCard);
846		dc->dwDisposition = ntohl(dc->dwDisposition);
847		dc->rv = ntohl(dc->rv);
848	}
849}
850
851INTERNAL void htonlBeginStruct(begin_struct *bs)
852{
853	if (bs)
854	{
855		bs->hCard = htonl(bs->hCard);
856		bs->rv = htonl(bs->rv);
857	}
858}
859
860INTERNAL void ntohlBeginStruct(begin_struct *bs)
861{
862	if (bs)
863	{
864		bs->hCard = ntohl(bs->hCard);
865		bs->rv = ntohl(bs->rv);
866	}
867}
868
869INTERNAL void htonlCancelStruct(cancel_struct *cs)
870{
871	if (cs)
872	{
873		cs->hCard = htonl(cs->hCard);
874		cs->rv = htonl(cs->rv);
875	}
876}
877
878INTERNAL void ntohlCancelStruct(cancel_struct *cs)
879{
880	if (cs)
881	{
882		cs->hCard = ntohl(cs->hCard);
883		cs->rv = ntohl(cs->rv);
884	}
885}
886
887INTERNAL void htonlEndStruct(end_struct *es)
888{
889	if (es)
890	{
891		es->hCard = htonl(es->hCard);
892		es->dwDisposition = htonl(es->dwDisposition);
893		es->rv = htonl(es->rv);
894	}
895}
896
897INTERNAL void ntohlEndStruct(end_struct *es)
898{
899	if (es)
900	{
901		es->hCard = ntohl(es->hCard);
902		es->dwDisposition = ntohl(es->dwDisposition);
903		es->rv = ntohl(es->rv);
904	}
905}
906
907INTERNAL void htonlStatusStruct(status_struct *ss)
908{
909	if (ss)
910	{
911		ss->hCard = htonl(ss->hCard);
912		ss->pcchReaderLen = htonl(ss->pcchReaderLen);
913		ss->pdwState = htonl(ss->pdwState);
914		ss->pdwProtocol = htonl(ss->pdwProtocol);
915		ss->pcbAtrLen = htonl(ss->pcbAtrLen);
916		ss->rv = htonl(ss->rv);
917	}
918}
919
920INTERNAL void ntohlStatusStruct(status_struct *ss)
921{
922	if (ss)
923	{
924		ss->hCard = ntohl(ss->hCard);
925		ss->pcchReaderLen = ntohl(ss->pcchReaderLen);
926		ss->pdwState = ntohl(ss->pdwState);
927		ss->pdwProtocol = ntohl(ss->pdwProtocol);
928		ss->pcbAtrLen = ntohl(ss->pcbAtrLen);
929		ss->rv = ntohl(ss->rv);
930	}
931}
932
933INTERNAL void htonlControlStruct(control_struct *cs)
934{
935	if (cs)
936	{
937		cs->hCard = htonl(cs->hCard);
938		cs->dwControlCode = htonl(cs->dwControlCode);
939		cs->cbSendLength = htonl(cs->cbSendLength);
940		cs->cbRecvLength = htonl(cs->cbRecvLength);
941		cs->dwBytesReturned = htonl(cs->dwBytesReturned);
942		cs->rv = htonl(cs->rv);
943	}
944}
945
946INTERNAL void ntohlControlStruct(control_struct *cs)
947{
948	if (cs)
949	{
950		cs->hCard = ntohl(cs->hCard);
951		cs->dwControlCode = ntohl(cs->dwControlCode);
952		cs->cbSendLength = ntohl(cs->cbSendLength);
953		cs->cbRecvLength = ntohl(cs->cbRecvLength);
954		cs->dwBytesReturned = ntohl(cs->dwBytesReturned);
955		cs->rv = ntohl(cs->rv);
956	}
957}
958
959INTERNAL void htonlGetSetStruct(getset_struct *gs)
960{
961	if (gs)
962	{
963		gs->hCard = htonl(gs->hCard);
964		gs->dwAttrId = htonl(gs->dwAttrId);
965		gs->cbAttrLen = htonl(gs->cbAttrLen);
966		gs->rv = htonl(gs->rv);
967	}
968}
969
970INTERNAL void ntohlGetSetStruct(getset_struct *gs)
971{
972	if (gs)
973	{
974		gs->hCard = ntohl(gs->hCard);
975		gs->dwAttrId = ntohl(gs->dwAttrId);
976		gs->cbAttrLen = ntohl(gs->cbAttrLen);
977		gs->rv = ntohl(gs->rv);
978	}
979}
980
981INTERNAL void htonlVersionStruct(version_struct *vs)
982{
983	if (vs)
984	{
985		vs->major = htonl(vs->major);
986		vs->minor = htonl(vs->minor);
987		vs->rv = htonl(vs->rv);
988	}
989}
990
991INTERNAL void ntohlVersionStruct(version_struct *vs)
992{
993	if (vs)
994	{
995		vs->major = ntohl(vs->major);
996		vs->minor = ntohl(vs->minor);
997		vs->rv = ntohl(vs->rv);
998	}
999}
1000
1001