1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2016 by Delphix. All rights reserved.
25  */
26 
27 #ifndef	_REPCACHE_PROTOCOL_H
28 #define	_REPCACHE_PROTOCOL_H
29 
30 /*
31  * The Repository Cache Protocol
32  * -----------------------------
33  *
34  * 1. Introduction
35  * ---------------
36  * This header file defines the private protocols between libscf(3lib) and
37  * svc.configd(8).  There are two separate protocols:
38  *
39  * 1.	The 'global' protocol, accessible via an fattach(3C)ed door located
40  *	at REPOSITORY_DOOR_NAME.
41  *
42  * 2.	The 'client' protocol, accessible through a door created using the
43  *	global protocol, which allows access to the repository.
44  *
45  * 1.1 Design restrictions
46  * -----------------------
47  * A basic constraint of the door IPC mechanism is that there is no reliable
48  * delivery.  In particular:
49  *
50  * 1.	If libscf(3lib) recieves an EINTR from door_call(), it doesn't know
51  *      whether or not the server recieved (and is processing) its request.
52  *
53  * 2.	When svc.configd(8) calls door_return(), the client may have already
54  *	received an EINTR, aborting its door_call().  In this case, the
55  *	returned values are dropped on the floor.
56  *
57  * The practical upshot of all of this is simple:
58  *
59  *	Every individual protocol action must be idempotent.
60  *
61  * That is, a client must be able to retry any single request multiple times,
62  * and get the correct results.
63  *
64  * 1.2. Protocol shorthand
65  * -----------------------
66  * We represent by "REQUEST(arg1, arg2) -> result, res1, [desc]" a request code
67  * of REP_PROTOCOL_REQUEST (or REPOSITORY_DOOR_REQUEST), which takes two
68  * additional arguments, arg1 and arg2, and returns a result code, res1, and
69  * a file descriptor desc.
70  *
71  * If an error occurs, the server will usually only send the result code. (a
72  * short return)
73  *
74  * Inside the protocol destription, <foo> indicates the type foo indicates.
75  *
76  * 2. The Global protocol
77  * ----------------------
78  * Everything starting with "REPOSITORY_DOOR" or "repository_door" belongs
79  * to the global protocol.
80  *
81  * 2.1. Global requests
82  * --------------------
83  *
84  * REQUEST_CONNECT(rdr_flags, ...) -> result, [new_door]
85  *	Request a new Client door.  rdr_flags determines attributes of the
86  *	connection:
87  *
88  *	    FLAG_DEBUG
89  *		Sets connection debugging flags to those in rdr_debug.
90  *
91  *	The new door is returned with DOOR_RELEASE set, so if the client does
92  *	not recieve the response, the new door will recieve an unref
93  *	notification.  This makes this request idempotent.
94  *
95  * 2.2. Global reponse codes
96  * -------------------------
97  * GLXXX: This needs to be thought through.
98  *
99  * SUCCESS
100  * FAIL_BAD_REQUEST
101  * FAIL_VERSION_MISMATCH
102  * FAIL_BAD_FLAG
103  * FAIL_BAD_USER
104  * FAIL_NO_RESOURCES
105  *
106  * 3. The Client protocol
107  * ----------------------
108  * Everything starting with "REP_PROTOCOL" or "rep_protocol" belongs to the
109  * client protocol.
110  *
111  * 3.1. Techniques used
112  * --------------------
113  * 3.1.1. Client-controlled identifiers
114  *
115  * An idiom the protocol uses to lower the number of round trips is
116  * client-controlled identifiers.  The basic idea is this:  whenever a
117  * client wants to set up and use a piece of server state, it picks an
118  * integer *which it knows is not in use* to identify it.  The server then
119  * maintains per-client, per-resource id->resource maps.  This has a number
120  * of advantages:
121  *
122  * 1.	Since the client allocates the identifiers, we don't need to do
123  *	a round-trip just to allocate a number.
124  *
125  * 2.	Since it is the client's job to make sure identifiers don't collide,
126  *	idempotency for setup (destroy) are simple:  If the identifier
127  *	already exists (does not exist), we just return success.
128  *
129  * 3.	Since the identifiers are per-client, the design automatically
130  *	precludes clients being able to manipulate other client's state.
131  *
132  * 3.1.2 Sequence numbers
133  *
134  * A standard way of gaining idempotency is introducing sequence numbers.
135  * These are simply integers which get incremented at points in the protocol,
136  * and make sure the client and server are in sync.
137  *
138  * In this protocol, we use sequence numbers for requests (like ITER_READ)
139  * which are repeated, returning different data each time.  Since requests
140  * can also be repeated due to unreliable dispatch, the client increments
141  * the sequence number after every successful request.  This allows the server
142  * to differentiate the two cases. (note that this means that failing
143  * requests have no side effects and are repeatable)
144  *
145  * 3.2. Client abstractions
146  * ------------------------
147  * 3.2.1 Entities
148  *
149  * An "entity" is a typed register which the client can manipulate.
150  * Entities are named in the protocol by client-controlled identifiers.
151  * They have a fixed type for their entire lifetime, and may be in one
152  * of two states:
153  *
154  * valid
155  *	The entity has a valid value, and may be read from.  This state
156  *	is reached by a successful write to the entity by some protocol
157  *	step.
158  *
159  * invalid
160  *	The entity does not contain a valid value.  There are a number
161  *	of ways to reach this state:
162  *
163  *	1.  The entity was just created.
164  *	2.  The underlying object that this entity refers to was destroyed.
165  *	3.  A protocol request which would have modified this entity
166  *	    failed.
167  *
168  * An entity is an element in the tree of repository data.  Every entity
169  * (except for the most distant SCOPE) has exactly one parent.  Entities
170  * can have multiple children of different types, restricted by its base
171  * type.
172  *
173  * The ENTITY_GET call is used to get the root of the tree (the most local
174  * scope)
175  *
176  * 3.2.2. The entity tree
177  * ----------------------
178  * The structure of a scope is as follows:
179  *
180  *	 _______
181  *	| SCOPE |
182  *	|_______|
183  *	    \ .
184  *	     \ .
185  *	      \_________
186  *	      | SERVICE |
187  *	      |_________|
188  *		/.    \ .
189  *	       /.      \ .
190  *	  ____/		\__________
191  *	 | PG |		| INSTANCE |
192  *	 |____|		|__________|
193  *			  /.	 \ .
194  *			 /.	  \ .
195  *		    ____/	   \__________
196  *		   | PG |	   | SNAPSHOT |
197  *		   |____|	   |__________|
198  *					\ .
199  *					 \ .
200  *					  \___________
201  *					  | SNAPLEVEL |
202  *					  |___________|
203  *					     /.
204  *					    /.
205  *				       ____/
206  *				      | PG |
207  *				      |____|
208  *
209  * Where the dots indicate an arbitrary number (including 0) of children.
210  *
211  * For a given scope, the next scope (in the sense of distance) is its
212  * TYPE_SCOPE parent.  The furthest out scope has no parent.
213  *
214  * 3.2.2 Iterators
215  *
216  * GLXXX
217  *
218  * 3.3. Client requests
219  * --------------------
220  *
221  * CLOSE() -> result
222  *	Closes the connection, revoking the door.  After this call completes,
223  *	no further calls will succeed.
224  *
225  * ENTITY_SETUP(entity_id, type) -> result
226  *	Sets up an entity, identified by entity_id, to identify a single
227  *	<type>.  <type> may not be TYPE_NONE.
228  *
229  * ENTITY_NAME(entity_id, name_type) -> result, name
230  *	Returns the name of entity_id.  name_type determines which type of
231  *	name to get.
232  *
233  * ENTITY_PARENT_TYPE(entity_id) -> result, parent_type
234  *	Retrieves the type of entity_id's parent
235  *
236  * ENTITY_GET_CHILD(entity_id, child_id, name) -> result
237  *	Puts entity_id's child (of child_id's type) named 'name' into child_id.
238  *
239  * ENTITY_GET_PARENT(entity_id, out_id) -> result
240  *	Puts entity_id's parent into out_id.
241  *
242  * ENTITY_GET(entity_id, number) -> result
243  *	Makes entity_id point to a particular object.  If any error
244  *	occurs, dest_id will be invalid.
245  *
246  * ENTITY_UPDATE(entity_id, changeid) -> result
247  *	Updates the entity to pick up any new changes.
248  *
249  * ENTITY_CREATE_CHILD(entity_id, type, name, child_id, changeid) -> result
250  *	Attaches the object of type /type/ in child_id as the child of
251  *	entity_id named 'name'.
252  *
253  * ENTITY_CREATE_PG(entity_id, name, type, flags, child_id, changeid) -> result
254  *	Creates a property group child of entity_id named 'name', type 'type'
255  *	and flags 'flags', and puts the resulting object in child_id.
256  *
257  * ENTITY_DELETE(entity_id, changeid) -> result
258  *	Deletes the entity represented by entity_id.
259  *
260  * ENTITY_RESET(entity_id) -> result
261  *	Resets the entity.
262  *
263  * ENTITY_TEARDOWN(entity_id) -> result
264  *	Destroys the entity entity_id.
265  *
266  * ITER_SETUP(iter_id) -> result
267  *	Sets up an iterator id.
268  *
269  * ITER_START(iter_id, entity_id, itertype, flags, pattern) -> result
270  *	Sets up an iterator, identified by iter_id, which will iterate the
271  *	<itertype> children of entity_id whose names match 'pattern',
272  *	with the matching controlled by flags.  Initializing an iterator
273  *	counts as the first sequence number (1).
274  *
275  * ITER_READ(iter_id, sequence, entity_id) -> result
276  *	Retrieves the next element of iterator iter_id.  Sequence starts at 2,
277  *	and is incremented by the client after each successful iteration.
278  *	The result is written to entity_id, which must be of the same type
279  *	as the iterator result.  The iterator must not be iterating values.
280  *
281  * ITER_READ_VALUE(iter_id, sequence) -> result, type, value
282  *	Retrieves the next value for iterator iter_id.  Sequence starts at 2,
283  *	and is incremented by the client after each successful iteration.
284  *	The iterator must be iterating a property's values.
285  *
286  * ITER_RESET(iter_id) -> result
287  *	Throws away any accumulated state.
288  *
289  * ITER_TEARDOWN(iter_id) -> result
290  *	Destroys the iterator iter_id.
291  *
292  * NEXT_SNAPLEVEL(entity_src, entity_dst) -> result
293  *	If entity_src is a snapshot, set entity_dst to the first snaplevel
294  *	in it.  If entity_src is a snaplevel, set entity_dst to the next
295  *	snaplevel, or fail if there isn't one.
296  *
297  * SNAPSHOT_TAKE(entity_id, name, dest_id, flags) -> result
298  *	Takes a snapshot of entity_id, creating snaplevels for the instance and
299  *	its parent service.  If flags is REP_SNAPSHOT_NEW, a new snapshot named
300  *	'name' is created as a child of entity_id, dest_id is pointed to it,
301  *	and the new snaplevels are attached to it.  If flags is
302  *	REP_SNAPSHOT_ATTACH, name must be empty, and the new snaplevels are
303  *	attached to the snapshot dest_id points to.
304  *
305  * SNAPSHOT_TAKE_NAMED(entity_id, instname, svcname, name, dest_id) -> result
306  *	Like SNAPSHOT_TAKE, but always acts as if REP_SNAPSHOT_NEW is
307  *	specified, and instname and svcname override the actual service and
308  *	instance names, respectively, written into the snaplevels.
309  *
310  *	Note that this is only useful for writing snapshots which will later
311  *	be transferred to another instance (svc:/svcname:instname/)
312  *
313  * SNAPSHOT_ATTACH(source_id, dest_id) -> result
314  *	The snaplevels attached to the snapshot referenced by source_id are
315  *	attached to the snapshot dest_id is pointed at.
316  *
317  * PROPERTY_GET_TYPE(entity_id) -> result, value type
318  *	Finds the value type of entity_id, which must be a property.
319  *
320  * PROPERTY_GET_VALUE(entity_id) -> result, type, value
321  *	If the property contains a single value, returns it and its type.
322  *
323  * PROPERTYGRP_SETUP_WAIT(entity_id) -> result, [pipe fd]
324  *	Sets up a notification for changes to the object entity_id currently
325  *	references.  On success, returns one side of a pipe -- when there
326  *	has been a change (or the daemon dies), the other end of the pipe will
327  *	be closed.
328  *
329  *	Only one of these can be set up per client -- attempts to set up more
330  *	than one will cause the previous one to get closed.
331  *
332  * PROPERTYGRP_TX_START(entity_id_tx, entity_id) -> result
333  *	Makes entity_id_tx point to the same property group as entity_id,
334  *	then attempts to set up entity_id_tx as a transaction on that group.
335  *	entity_id and entity_id_tx must be distinct.  On failure, entity_id_tx
336  *	is reset.
337  *
338  * PROPERTYGRP_TX_COMMIT(entity_id, data) -> result
339  *	Gives the actual steps to follow, and attempts to commit them.
340  *
341  * CLIENT_ADD_NOTIFY(type, pattern) -> result
342  *	Adds a new property group name or type pattern to the notify list
343  *	(see CLIENT_WAIT).  If successful, takes effect immediately.
344  *
345  * CLIENT_WAIT(entity_id) -> result, fmri
346  *	Waits for a change to a propertygroup that matches the patterns
347  *	set up using CLIENT_ADD_NOTIFY, and puts the resultant propertygroup
348  *	in entity_id.  Note that if an error occurs, you can loose
349  *	notifications.  Either entity_id is set to a changed propertygroup,
350  *	or fmri is a non-zero-length string identifying a deleted thing.
351  *
352  * BACKUP(name) -> result
353  *	Backs up the persistant repository with a particular name.
354  *
355  * SET_ANNOTATION(operation, file)
356  *	Set up a security audit annotation event.  operation is the name of
357  *	the operation that is being annotated, and file is the file being
358  *	processed.  This will be used to mark operations which comprise
359  *	multiple primitive operations such as svccfg import.
360  *
361  * SWITCH(flag) -> result
362  *	The flag is used to indicate the direction of the switch operation.
363  *	When the flag is set to 'fast', move the main repository from the
364  *	default location (/etc/svc) to the tmpfs locationa (/etc/svc/volatile).
365  *	When it is set to 'perm', the switch is reversed.
366  */
367 
368 #include <door.h>
369 #include <stddef.h>
370 #include <sys/sysmacros.h>
371 
372 #ifdef	__cplusplus
373 extern "C" {
374 #endif
375 
376 /*
377  * svc.configd initial protocol details
378  */
379 #define	REPOSITORY_DOOR_BASEVER	(('R' << 24) | ('e' << 16) | ('p' << 8))
380 #define	REPOSITORY_DOOR_NAME	"/etc/svc/volatile/repository_door"
381 #define	REPOSITORY_DOOR_COOKIE	((void *)REPOSITORY_DOOR_BASEVER)
382 
383 #define	REPOSITORY_BOOT_BACKUP	((const char *)"boot")
384 
385 /*
386  * This value should be incremented any time the protocol changes.  When in
387  * doubt, bump it.
388  */
389 #define	REPOSITORY_DOOR_VERSION			(21 + REPOSITORY_DOOR_BASEVER)
390 
391 /*
392  * flags for rdr_flags
393  */
394 #define	REPOSITORY_DOOR_FLAG_DEBUG		0x00000001	/* rdr_debug */
395 
396 #define	REPOSITORY_DOOR_FLAG_ALL		0x00000001	/* all flags */
397 
398 /*
399  * Request IDs
400  */
401 enum repository_door_requestid {
402 	REPOSITORY_DOOR_REQUEST_CONNECT = (('M' << 8) | 1)
403 };
404 
405 enum repository_door_statusid {
406 	REPOSITORY_DOOR_SUCCESS			= 0,
407 	REPOSITORY_DOOR_FAIL_BAD_REQUEST	= 1,
408 	REPOSITORY_DOOR_FAIL_VERSION_MISMATCH	= 2,
409 	REPOSITORY_DOOR_FAIL_BAD_FLAG		= 3,
410 	REPOSITORY_DOOR_FAIL_NO_RESOURCES	= 4,
411 	REPOSITORY_DOOR_FAIL_PERMISSION_DENIED	= 5
412 };
413 
414 /*
415  * You may only add elements to the end of this structure.
416  */
417 typedef struct repository_door_request {
418 	uint32_t rdr_version;			/* must be first element */
419 	enum repository_door_requestid rdr_request;
420 	uint32_t rdr_flags;
421 	uint32_t rdr_debug;
422 } repository_door_request_t;
423 
424 typedef struct repository_door_response {
425 	enum repository_door_statusid rdr_status;
426 } repository_door_response_t;
427 
428 /*
429  * Client interface.  Used on doors returned by REQUEST_CONNECT
430  */
431 
432 #define	REP_PROTOCOL_NAME_LEN		120	/* maximum name length */
433 #define	REP_PROTOCOL_VALUE_LEN		4096	/* maximum value length */
434 
435 #define	REP_PROTOCOL_FMRI_LEN		(6 * REP_PROTOCOL_NAME_LEN)
436 
437 #define	REP_PROTOCOL_BASE		('C' << 8)
438 
439 /*
440  * Request codes
441  */
442 enum rep_protocol_requestid {
443 	REP_PROTOCOL_CLOSE		= REP_PROTOCOL_BASE,
444 
445 	REP_PROTOCOL_ENTITY_SETUP,
446 	REP_PROTOCOL_ENTITY_NAME,
447 	REP_PROTOCOL_ENTITY_PARENT_TYPE,
448 	REP_PROTOCOL_ENTITY_GET_CHILD,
449 	REP_PROTOCOL_ENTITY_GET_PARENT,
450 	REP_PROTOCOL_ENTITY_GET,
451 	REP_PROTOCOL_ENTITY_UPDATE,
452 	REP_PROTOCOL_ENTITY_CREATE_CHILD,
453 	REP_PROTOCOL_ENTITY_CREATE_PG,
454 	REP_PROTOCOL_ENTITY_DELETE,
455 	REP_PROTOCOL_ENTITY_RESET,
456 	REP_PROTOCOL_ENTITY_TEARDOWN,
457 
458 	REP_PROTOCOL_ITER_SETUP,
459 	REP_PROTOCOL_ITER_START,
460 	REP_PROTOCOL_ITER_READ,
461 	REP_PROTOCOL_ITER_READ_VALUE,
462 	REP_PROTOCOL_ITER_RESET,
463 	REP_PROTOCOL_ITER_TEARDOWN,
464 
465 	REP_PROTOCOL_NEXT_SNAPLEVEL,
466 
467 	REP_PROTOCOL_SNAPSHOT_TAKE,
468 	REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,
469 	REP_PROTOCOL_SNAPSHOT_ATTACH,
470 
471 	REP_PROTOCOL_PROPERTY_GET_TYPE,
472 	REP_PROTOCOL_PROPERTY_GET_VALUE,
473 
474 	REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT,
475 	REP_PROTOCOL_PROPERTYGRP_TX_START,
476 	REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,
477 
478 	REP_PROTOCOL_CLIENT_ADD_NOTIFY,
479 	REP_PROTOCOL_CLIENT_WAIT,
480 
481 	REP_PROTOCOL_BACKUP,
482 
483 	REP_PROTOCOL_SET_AUDIT_ANNOTATION,
484 
485 	REP_PROTOCOL_SWITCH,
486 
487 	REP_PROTOCOL_MAX_REQUEST
488 };
489 
490 /*
491  * Response codes.  These are returned to the client, and the errors are
492  * translated into scf_error_t's by libscf (see proto_error()).
493  */
494 typedef int32_t rep_protocol_responseid_t;
495 enum rep_protocol_responseid {
496 	REP_PROTOCOL_SUCCESS =			0,
497 	/* iterators: No more values. */
498 	REP_PROTOCOL_DONE =			1,
499 
500 	/* Request from client was malformed. */
501 	REP_PROTOCOL_FAIL_BAD_REQUEST =		-1,
502 	/* Prerequisite call has not been made. */
503 	REP_PROTOCOL_FAIL_MISORDERED =		-2,
504 	/* Register for ID has not been created. */
505 	REP_PROTOCOL_FAIL_UNKNOWN_ID =		-3,
506 	/* Out of memory or other resource. */
507 	REP_PROTOCOL_FAIL_NO_RESOURCES =	-4,
508 	/* Type argument is invalid. */
509 	REP_PROTOCOL_FAIL_INVALID_TYPE =	-5,
510 	/* Requested object does not exist. */
511 	REP_PROTOCOL_FAIL_NOT_FOUND =		-6,
512 	/* Register for given ID does not point to an object. */
513 	REP_PROTOCOL_FAIL_NOT_SET =		-7,
514 
515 	/* Requested name is longer than supplied buffer. */
516 	REP_PROTOCOL_FAIL_TRUNCATED =		-8,
517 	/* Operation requires different type. */
518 	REP_PROTOCOL_FAIL_TYPE_MISMATCH =	-9,
519 
520 	/* Changeable object has been changed since last update. */
521 	REP_PROTOCOL_FAIL_NOT_LATEST =		-10,
522 	/* Creation failed because object with given name exists. */
523 	REP_PROTOCOL_FAIL_EXISTS =		-11,
524 	/* Transaction is invalid. */
525 	REP_PROTOCOL_FAIL_BAD_TX =		-12,
526 	/* Operation is not applicable to indicated object. */
527 	REP_PROTOCOL_FAIL_NOT_APPLICABLE =	-13,
528 	/* Two IDs for operation were unexpectedly equal. */
529 	REP_PROTOCOL_FAIL_DUPLICATE_ID =	-14,
530 
531 	/* Permission denied. */
532 	REP_PROTOCOL_FAIL_PERMISSION_DENIED =	-15,
533 	/* Backend does not exist or otherwise refused access. */
534 	REP_PROTOCOL_FAIL_BACKEND_ACCESS =	-16,
535 	/* Backend is read-only. */
536 	REP_PROTOCOL_FAIL_BACKEND_READONLY =	-17,
537 
538 	/* Object has been deleted. */
539 	REP_PROTOCOL_FAIL_DELETED =		-18,
540 
541 	REP_PROTOCOL_FAIL_UNKNOWN =		-0xfd
542 };
543 
544 /*
545  * Types
546  */
547 typedef enum rep_protocol_entity {
548 	REP_PROTOCOL_ENTITY_NONE,
549 	REP_PROTOCOL_ENTITY_SCOPE,
550 	REP_PROTOCOL_ENTITY_SERVICE,
551 	REP_PROTOCOL_ENTITY_INSTANCE,
552 	REP_PROTOCOL_ENTITY_SNAPSHOT,
553 	REP_PROTOCOL_ENTITY_SNAPLEVEL,
554 	REP_PROTOCOL_ENTITY_PROPERTYGRP,
555 	REP_PROTOCOL_ENTITY_CPROPERTYGRP,	/* "composed" property group */
556 	REP_PROTOCOL_ENTITY_PROPERTY,
557 	REP_PROTOCOL_ENTITY_VALUE,
558 
559 	REP_PROTOCOL_ENTITY_MAX
560 } rep_protocol_entity_t;
561 
562 typedef enum rep_protocol_value_type {
563 	REP_PROTOCOL_TYPE_INVALID	= '\0',
564 	REP_PROTOCOL_TYPE_BOOLEAN	= 'b',
565 	REP_PROTOCOL_TYPE_COUNT		= 'c',
566 	REP_PROTOCOL_TYPE_INTEGER	= 'i',
567 	REP_PROTOCOL_TYPE_TIME		= 't',
568 	REP_PROTOCOL_TYPE_STRING	= 's',
569 	REP_PROTOCOL_TYPE_OPAQUE	= 'o',
570 
571 	REP_PROTOCOL_SUBTYPE_USTRING	= REP_PROTOCOL_TYPE_STRING|('u' << 8),
572 	REP_PROTOCOL_SUBTYPE_URI	= REP_PROTOCOL_TYPE_STRING|('U' << 8),
573 	REP_PROTOCOL_SUBTYPE_FMRI	= REP_PROTOCOL_TYPE_STRING|('f' << 8),
574 
575 	REP_PROTOCOL_SUBTYPE_HOST	= REP_PROTOCOL_TYPE_STRING|('h' << 8),
576 	REP_PROTOCOL_SUBTYPE_HOSTNAME	= REP_PROTOCOL_TYPE_STRING|('N' << 8),
577 	REP_PROTOCOL_SUBTYPE_NETADDR	= REP_PROTOCOL_TYPE_STRING|('n' << 8),
578 	REP_PROTOCOL_SUBTYPE_NETADDR_V4	= REP_PROTOCOL_TYPE_STRING|('4' << 8),
579 	REP_PROTOCOL_SUBTYPE_NETADDR_V6	= REP_PROTOCOL_TYPE_STRING|('6' << 8)
580 } rep_protocol_value_type_t;
581 
582 
583 #define	REP_PROTOCOL_BASE_TYPE(t)	((t) & 0x00ff)
584 #define	REP_PROTOCOL_SUBTYPE(t)		(((t) & 0xff00) >> 8)
585 
586 /*
587  * Request structures
588  */
589 typedef struct rep_protocol_request {
590 	enum rep_protocol_requestid rpr_request;
591 } rep_protocol_request_t;
592 
593 struct rep_protocol_iter_request {
594 	enum rep_protocol_requestid rpr_request;
595 	uint32_t rpr_iterid;
596 };
597 
598 struct rep_protocol_iter_start {
599 	enum rep_protocol_requestid rpr_request;	/* ITER_START */
600 	uint32_t rpr_iterid;
601 
602 	uint32_t rpr_entity;
603 	uint32_t rpr_itertype;
604 	uint32_t rpr_flags;
605 	char	rpr_pattern[REP_PROTOCOL_NAME_LEN];
606 };
607 #define	RP_ITER_START_ALL	0x00000001	/* ignore pattern, match all */
608 #define	RP_ITER_START_EXACT	0x00000002	/* exact match with pattern */
609 #define	RP_ITER_START_PGTYPE	0x00000003	/* exact match pg type */
610 #define	RP_ITER_START_FILT_MASK	0x00000003
611 #define	RP_ITER_START_COMPOSED	0x00000004	/* composed */
612 
613 struct rep_protocol_iter_read {
614 	enum rep_protocol_requestid rpr_request;	/* ITER_READ */
615 	uint32_t rpr_iterid;
616 	uint32_t rpr_sequence;		/* client increments upon success */
617 	uint32_t rpr_entityid;		/* entity to write result to */
618 };
619 
620 struct rep_protocol_iter_read_value {
621 	enum rep_protocol_requestid rpr_request;	/* ITER_READ_VALUE */
622 	uint32_t rpr_iterid;
623 	uint32_t rpr_sequence;		/* client increments upon success */
624 };
625 
626 struct rep_protocol_entity_setup {
627 	enum rep_protocol_requestid rpr_request;	/* ENTITY_SETUP */
628 	uint32_t rpr_entityid;
629 	uint32_t rpr_entitytype;
630 };
631 
632 struct rep_protocol_entity_name {
633 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
634 	uint32_t rpr_entityid;
635 	uint32_t rpr_answertype;
636 };
637 #define	RP_ENTITY_NAME_NAME			0
638 #define	RP_ENTITY_NAME_PGTYPE			1
639 #define	RP_ENTITY_NAME_PGFLAGS			2
640 #define	RP_ENTITY_NAME_SNAPLEVEL_SCOPE		3
641 #define	RP_ENTITY_NAME_SNAPLEVEL_SERVICE	4
642 #define	RP_ENTITY_NAME_SNAPLEVEL_INSTANCE	5
643 #define	RP_ENTITY_NAME_PGREADPROT		6
644 
645 struct rep_protocol_entity_update {
646 	enum rep_protocol_requestid rpr_request;	/* ENTITY_UPDATE */
647 	uint32_t rpr_entityid;
648 	uint32_t rpr_changeid;
649 };
650 
651 struct rep_protocol_entity_parent_type {
652 	enum rep_protocol_requestid rpr_request;	/* ENTITY_PARENT_TYPE */
653 	uint32_t rpr_entityid;
654 };
655 
656 struct rep_protocol_entity_parent {
657 	enum rep_protocol_requestid rpr_request;	/* ENTITY_GET_PARENT */
658 	uint32_t rpr_entityid;
659 	uint32_t rpr_outid;
660 };
661 
662 struct rep_protocol_entity_get {
663 	enum rep_protocol_requestid rpr_request;	/* ENTITY_SET */
664 	uint32_t rpr_entityid;
665 	uint32_t rpr_object;
666 };
667 #define	RP_ENTITY_GET_INVALIDATE	1
668 #define	RP_ENTITY_GET_MOST_LOCAL_SCOPE	2
669 
670 struct rep_protocol_entity_create_child {
671 	enum rep_protocol_requestid rpr_request; /* ENTITY_CREATE_CHILD */
672 	uint32_t rpr_entityid;
673 	uint32_t rpr_childtype;
674 	uint32_t rpr_childid;
675 	uint32_t rpr_changeid;
676 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
677 };
678 
679 struct rep_protocol_entity_create_pg {
680 	enum rep_protocol_requestid rpr_request; /* ENTITY_CREATE_PG */
681 	uint32_t rpr_entityid;
682 	uint32_t rpr_childtype;
683 	uint32_t rpr_childid;
684 	uint32_t rpr_changeid;
685 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
686 	char	rpr_type[REP_PROTOCOL_NAME_LEN];
687 	uint32_t rpr_flags;
688 };
689 
690 struct rep_protocol_entity_get_child {
691 	enum rep_protocol_requestid rpr_request;	/* ENTITY_GET_CHILD */
692 	uint32_t rpr_entityid;
693 	uint32_t rpr_childid;
694 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
695 };
696 
697 struct rep_protocol_entity_delete {
698 	enum rep_protocol_requestid rpr_request; /* ENTITY_DELETE_CHILD */
699 	uint32_t rpr_entityid;
700 	uint32_t rpr_changeid;
701 };
702 
703 struct rep_protocol_entity_reset {
704 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
705 	uint32_t rpr_entityid;
706 };
707 
708 struct rep_protocol_entity_request {
709 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
710 	uint32_t rpr_entityid;
711 };
712 
713 struct rep_protocol_entity_teardown {
714 	enum rep_protocol_requestid rpr_request;	/* ENTITY_TEARDOWN */
715 	uint32_t rpr_entityid;
716 };
717 
718 struct rep_protocol_entity_pair {
719 	enum rep_protocol_requestid rpr_request;	/* NEXT_SNAPLEVEL */
720 	uint32_t rpr_entity_src;
721 	uint32_t rpr_entity_dst;
722 };
723 
724 struct rep_protocol_transaction_start {
725 	enum rep_protocol_requestid rpr_request;	/* TX_SETUP */
726 	uint32_t rpr_entityid_tx;		/* property group tx entity */
727 	uint32_t rpr_entityid;			/* property group entity */
728 };
729 
730 struct rep_protocol_transaction_commit {
731 	enum rep_protocol_requestid rpr_request; /* TX_COMMIT */
732 	uint32_t rpr_entityid;
733 	uint32_t rpr_size;			/* size of entire structure */
734 	uint8_t rpr_cmd[1];
735 };
736 
737 #define	REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(sz) \
738 	    (offsetof(struct rep_protocol_transaction_commit, rpr_cmd[sz]))
739 
740 #define	REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE \
741 	    REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(0)
742 
743 enum rep_protocol_transaction_action {
744 	REP_PROTOCOL_TX_ENTRY_INVALID,	/* N/A */
745 	REP_PROTOCOL_TX_ENTRY_NEW,	/* new property */
746 	REP_PROTOCOL_TX_ENTRY_CLEAR,	/* clear old property */
747 	REP_PROTOCOL_TX_ENTRY_REPLACE,	/* change type of old property */
748 	REP_PROTOCOL_TX_ENTRY_DELETE	/* delete property (no values) */
749 };
750 
751 struct rep_protocol_transaction_cmd {
752 	enum	rep_protocol_transaction_action rptc_action;
753 	uint32_t rptc_type;
754 	uint32_t rptc_size;		/* size of entire structure */
755 	uint32_t rptc_name_len;
756 	uint8_t	rptc_data[1];
757 };
758 
759 #define	REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz) \
760 	    (offsetof(struct rep_protocol_transaction_cmd, rptc_data[sz]))
761 
762 #define	REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE \
763 	    REP_PROTOCOL_TRANSACTION_CMD_SIZE(0)
764 
765 #define	TX_SIZE(x)	P2ROUNDUP((x), sizeof (uint32_t))
766 
767 struct rep_protocol_transaction_request {
768 	enum rep_protocol_requestid rpr_request; /* SETUP, ABORT or TEARDOWN */
769 	uint32_t rpr_txid;
770 };
771 
772 struct rep_protocol_property_request {
773 	enum rep_protocol_requestid rpr_request;
774 	uint32_t rpr_entityid;
775 };
776 
777 struct rep_protocol_propertygrp_request {
778 	enum rep_protocol_requestid rpr_request;
779 	uint32_t rpr_entityid;
780 };
781 
782 struct rep_protocol_notify_request {
783 	enum rep_protocol_requestid rpr_request;
784 	uint32_t rpr_type;
785 	char	rpr_pattern[REP_PROTOCOL_NAME_LEN];
786 };
787 #define	REP_PROTOCOL_NOTIFY_PGNAME 1
788 #define	REP_PROTOCOL_NOTIFY_PGTYPE 2
789 
790 struct rep_protocol_wait_request {
791 	enum rep_protocol_requestid rpr_request;
792 	uint32_t rpr_entityid;
793 };
794 
795 struct rep_protocol_snapshot_take {
796 	enum rep_protocol_requestid rpr_request;	/* SNAPSHOT_TAKE */
797 	uint32_t rpr_entityid_src;
798 	uint32_t rpr_entityid_dest;
799 	int	rpr_flags;
800 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
801 };
802 #define	REP_SNAPSHOT_NEW	0x00000001
803 #define	REP_SNAPSHOT_ATTACH	0x00000002
804 
805 struct rep_protocol_snapshot_take_named {
806 	enum rep_protocol_requestid rpr_request; /* SNAPSHOT_TAKE_NAMED */
807 	uint32_t rpr_entityid_src;
808 	uint32_t rpr_entityid_dest;
809 	char	rpr_svcname[REP_PROTOCOL_NAME_LEN];
810 	char	rpr_instname[REP_PROTOCOL_NAME_LEN];
811 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
812 };
813 
814 struct rep_protocol_snapshot_attach {
815 	enum rep_protocol_requestid rpr_request;	/* SNAPSHOT_ATTACH */
816 	uint32_t rpr_entityid_src;
817 	uint32_t rpr_entityid_dest;
818 };
819 
820 struct rep_protocol_backup_request {
821 	enum rep_protocol_requestid rpr_request;	/* BACKUP */
822 	uint32_t rpr_changeid;
823 	char rpr_name[REP_PROTOCOL_NAME_LEN];
824 };
825 
826 struct rep_protocol_annotation {
827 	enum rep_protocol_requestid rpr_request;	/* SET_ANNOTATION */
828 	char rpr_operation[REP_PROTOCOL_NAME_LEN];
829 	char rpr_file[MAXPATHLEN];
830 };
831 
832 struct rep_protocol_switch_request {
833 	enum rep_protocol_requestid rpr_request;	/* SWITCH */
834 	uint32_t rpr_changeid;
835 	int rpr_flag;
836 };
837 
838 /*
839  * Response structures
840  */
841 typedef struct rep_protocol_response {
842 	rep_protocol_responseid_t rpr_response;
843 } rep_protocol_response_t;
844 
845 struct rep_protocol_integer_response {
846 	rep_protocol_responseid_t rpr_response;
847 	uint32_t rpr_value;
848 };
849 
850 struct rep_protocol_name_response {	/* response to ENTITY_NAME */
851 	rep_protocol_responseid_t rpr_response;
852 	char rpr_name[REP_PROTOCOL_NAME_LEN];
853 };
854 
855 struct rep_protocol_fmri_response {
856 	rep_protocol_responseid_t rpr_response;
857 	char rpr_fmri[REP_PROTOCOL_FMRI_LEN];
858 };
859 
860 struct rep_protocol_value_response {
861 	rep_protocol_responseid_t rpr_response;
862 	rep_protocol_value_type_t rpr_type;
863 	char			rpr_value[2 * REP_PROTOCOL_VALUE_LEN + 1];
864 };
865 
866 #ifdef	__cplusplus
867 }
868 #endif
869 
870 #endif	/* _REPCACHE_PROTOCOL_H */
871