Nfcd

From iPhone Development Wiki

nfcd is a daemon running under the mobile user. It handles the communications between PassKit and the underlying hardware and libraries.

Core objects

  • NFDaemon
  • NFFieldDetectController
  • NFCoreTelephonyConnection
  • NFPowerManager
  • NFAbstractController
  • NFCardEmulationController
  • NFSecureElementController

Launchd plist

{
    EnablePressuredExit = 1;
    EnableTransactions = 1;
    ExitTimeOut = 45;
    Label = "com.apple.nfcd";
    MachServices =     {
        "com.apple.nfcd" = 1;
    };
    ProcessType = Interactive;
    Program = "/usr/libexec/nfcd";
    UserName = mobile;
}

Where the XPC service is registered under the "com.apple.nfcd" name

Supported XPC Commands

ID Command
1 q_registerConnection:info:
2 q_unregisterConnection:
3-64 send command to SE controller
65 q_updateSecureElementPowerState
66 _seIsInRestrictedMode
67 restrictedModeChanged
68-239 callSEContoller
240 setDeviceString
241 q_getControllerInfo
242 q_getSecureElementInfo
243 q_getBoosterInfo
244 q_readBoosterRegister
245 q_sendBoosterCommand
246 q_triggerAssertion
>247 throw error

Sending XPC Commands

Four XPC keys are sent for the XPC command:

  • NFMsgObject - dictionary containing values to sent to receiving objects
  • NFMsgType - uint64, sending is a 0, receiving a 1
  • NFMsgCode - uint64, "command" as described above
  • NFMsgId - uint64, undetermined

Example of XPC command to the nfcd:

#include <xpc/xpc.h>

int main(int argc, char **argv, char **envp) {
	// Create connection to mach service
	xpc_connection_t connection = xpc_connection_create_mach_service("com.apple.nfcd", NULL, 0);
	xpc_connection_set_event_handler(connection, ^(xpc_object_t object) {
		char *description = xpc_copy_description(object);
		printf("Sending object: %s\n", description);
		free(description);
	});
	xpc_connection_resume(connection);

	while (true) {
		// Send message to mach service, and wait for a response
		xpc_object_t msgobject = xpc_dictionary_create(NULL,NULL,0); 
		xpc_object_t object = xpc_dictionary_create(NULL, NULL, 0);
		xpc_dictionary_set_int64(msgobject, "Controller", 6);
		xpc_dictionary_set_value(object, "NFMsgObject", msgobject);
		xpc_dictionary_set_uint64(object, "NFMsgType", 0x00); 
		xpc_dictionary_set_uint64(object, "NFMsgCode", 0x01); 
		xpc_dictionary_set_uint64(object, "NFMsgId", 17);

		char *description = xpc_copy_description(object);
		printf("Sending object: %s\n", description);
		free(description);

		xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, object);
		description = xpc_copy_description(object);
		printf("Received reply object: %s\n\n", description);
		free(description);
		sleep(1);
	}

	return 0;
}

see https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/xpc_dictionary_set_uint64.3.html

NFDaemon methods

Signature -(void)XPCConnection:(id)connection didReceiveCommand:(id)command;
Available in 8.0 - 9.0.1
Signature -(int)q_registerConnection:(id)connection info:(id)info;
Available in 8.0 - 9.0.1

This function checks for an existing controller

  • [NFCardEmulationController embeddedCardEmulationController]
  • [NFCardEmulationController UICCCardEmulationController]
  • [NFSecureElementController seController]
  • [NFFieldDetectController fieldDetectController]

When it finds the appropriate controller it calls the unregister function for it.

Signature -(unsigned int)q_unregisterConnection:(id)connection;
Available in 8.0 - 9.0.1