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