18c2ecf20Sopenharmony_ci==============================
28c2ecf20Sopenharmony_ciGeneral notification mechanism
38c2ecf20Sopenharmony_ci==============================
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ciThe general notification mechanism is built on top of the standard pipe driver
68c2ecf20Sopenharmony_ciwhereby it effectively splices notification messages from the kernel into pipes
78c2ecf20Sopenharmony_ciopened by userspace.  This can be used in conjunction with::
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci  * Key/keyring notifications
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciThe notifications buffers can be enabled by:
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	"General setup"/"General notification queue"
158c2ecf20Sopenharmony_ci	(CONFIG_WATCH_QUEUE)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciThis document has the following sections:
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci.. contents:: :local:
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciOverview
238c2ecf20Sopenharmony_ci========
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciThis facility appears as a pipe that is opened in a special mode.  The pipe's
268c2ecf20Sopenharmony_ciinternal ring buffer is used to hold messages that are generated by the kernel.
278c2ecf20Sopenharmony_ciThese messages are then read out by read().  Splice and similar are disabled on
288c2ecf20Sopenharmony_cisuch pipes due to them wanting to, under some circumstances, revert their
298c2ecf20Sopenharmony_ciadditions to the ring - which might end up interleaved with notification
308c2ecf20Sopenharmony_cimessages.
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciThe owner of the pipe has to tell the kernel which sources it would like to
338c2ecf20Sopenharmony_ciwatch through that pipe.  Only sources that have been connected to a pipe will
348c2ecf20Sopenharmony_ciinsert messages into it.  Note that a source may be bound to multiple pipes and
358c2ecf20Sopenharmony_ciinsert messages into all of them simultaneously.
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciFilters may also be emplaced on a pipe so that certain source types and
388c2ecf20Sopenharmony_cisubevents can be ignored if they're not of interest.
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciA message will be discarded if there isn't a slot available in the ring or if
418c2ecf20Sopenharmony_cino preallocated message buffer is available.  In both of these cases, read()
428c2ecf20Sopenharmony_ciwill insert a WATCH_META_LOSS_NOTIFICATION message into the output buffer after
438c2ecf20Sopenharmony_cithe last message currently in the buffer has been read.
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciNote that when producing a notification, the kernel does not wait for the
468c2ecf20Sopenharmony_ciconsumers to collect it, but rather just continues on.  This means that
478c2ecf20Sopenharmony_cinotifications can be generated whilst spinlocks are held and also protects the
488c2ecf20Sopenharmony_cikernel from being held up indefinitely by a userspace malfunction.
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciMessage Structure
528c2ecf20Sopenharmony_ci=================
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciNotification messages begin with a short header::
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	struct watch_notification {
578c2ecf20Sopenharmony_ci		__u32	type:24;
588c2ecf20Sopenharmony_ci		__u32	subtype:8;
598c2ecf20Sopenharmony_ci		__u32	info;
608c2ecf20Sopenharmony_ci	};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci"type" indicates the source of the notification record and "subtype" indicates
638c2ecf20Sopenharmony_cithe type of record from that source (see the Watch Sources section below).  The
648c2ecf20Sopenharmony_citype may also be "WATCH_TYPE_META".  This is a special record type generated
658c2ecf20Sopenharmony_ciinternally by the watch queue itself.  There are two subtypes:
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci  * WATCH_META_REMOVAL_NOTIFICATION
688c2ecf20Sopenharmony_ci  * WATCH_META_LOSS_NOTIFICATION
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciThe first indicates that an object on which a watch was installed was removed
718c2ecf20Sopenharmony_cior destroyed and the second indicates that some messages have been lost.
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci"info" indicates a bunch of things, including:
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci  * The length of the message in bytes, including the header (mask with
768c2ecf20Sopenharmony_ci    WATCH_INFO_LENGTH and shift by WATCH_INFO_LENGTH__SHIFT).  This indicates
778c2ecf20Sopenharmony_ci    the size of the record, which may be between 8 and 127 bytes.
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci  * The watch ID (mask with WATCH_INFO_ID and shift by WATCH_INFO_ID__SHIFT).
808c2ecf20Sopenharmony_ci    This indicates that caller's ID of the watch, which may be between 0
818c2ecf20Sopenharmony_ci    and 255.  Multiple watches may share a queue, and this provides a means to
828c2ecf20Sopenharmony_ci    distinguish them.
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci  * A type-specific field (WATCH_INFO_TYPE_INFO).  This is set by the
858c2ecf20Sopenharmony_ci    notification producer to indicate some meaning specific to the type and
868c2ecf20Sopenharmony_ci    subtype.
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ciEverything in info apart from the length can be used for filtering.
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciThe header can be followed by supplementary information.  The format of this is
918c2ecf20Sopenharmony_ciat the discretion is defined by the type and subtype.
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciWatch List (Notification Source) API
958c2ecf20Sopenharmony_ci====================================
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciA "watch list" is a list of watchers that are subscribed to a source of
988c2ecf20Sopenharmony_cinotifications.  A list may be attached to an object (say a key or a superblock)
998c2ecf20Sopenharmony_cior may be global (say for device events).  From a userspace perspective, a
1008c2ecf20Sopenharmony_cinon-global watch list is typically referred to by reference to the object it
1018c2ecf20Sopenharmony_cibelongs to (such as using KEYCTL_NOTIFY and giving it a key serial number to
1028c2ecf20Sopenharmony_ciwatch that specific key).
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciTo manage a watch list, the following functions are provided:
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci  * ::
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	void init_watch_list(struct watch_list *wlist,
1098c2ecf20Sopenharmony_ci			     void (*release_watch)(struct watch *wlist));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci    Initialise a watch list.  If ``release_watch`` is not NULL, then this
1128c2ecf20Sopenharmony_ci    indicates a function that should be called when the watch_list object is
1138c2ecf20Sopenharmony_ci    destroyed to discard any references the watch list holds on the watched
1148c2ecf20Sopenharmony_ci    object.
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci  * ``void remove_watch_list(struct watch_list *wlist);``
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci    This removes all of the watches subscribed to a watch_list and frees them
1198c2ecf20Sopenharmony_ci    and then destroys the watch_list object itself.
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciWatch Queue (Notification Output) API
1238c2ecf20Sopenharmony_ci=====================================
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciA "watch queue" is the buffer allocated by an application that notification
1268c2ecf20Sopenharmony_cirecords will be written into.  The workings of this are hidden entirely inside
1278c2ecf20Sopenharmony_ciof the pipe device driver, but it is necessary to gain a reference to it to set
1288c2ecf20Sopenharmony_cia watch.  These can be managed with:
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci  * ``struct watch_queue *get_watch_queue(int fd);``
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci    Since watch queues are indicated to the kernel by the fd of the pipe that
1338c2ecf20Sopenharmony_ci    implements the buffer, userspace must hand that fd through a system call.
1348c2ecf20Sopenharmony_ci    This can be used to look up an opaque pointer to the watch queue from the
1358c2ecf20Sopenharmony_ci    system call.
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci  * ``void put_watch_queue(struct watch_queue *wqueue);``
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci    This discards the reference obtained from ``get_watch_queue()``.
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciWatch Subscription API
1438c2ecf20Sopenharmony_ci======================
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciA "watch" is a subscription on a watch list, indicating the watch queue, and
1468c2ecf20Sopenharmony_cithus the buffer, into which notification records should be written.  The watch
1478c2ecf20Sopenharmony_ciqueue object may also carry filtering rules for that object, as set by
1488c2ecf20Sopenharmony_ciuserspace.  Some parts of the watch struct can be set by the driver::
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	struct watch {
1518c2ecf20Sopenharmony_ci		union {
1528c2ecf20Sopenharmony_ci			u32		info_id;	/* ID to be OR'd in to info field */
1538c2ecf20Sopenharmony_ci			...
1548c2ecf20Sopenharmony_ci		};
1558c2ecf20Sopenharmony_ci		void			*private;	/* Private data for the watched object */
1568c2ecf20Sopenharmony_ci		u64			id;		/* Internal identifier */
1578c2ecf20Sopenharmony_ci		...
1588c2ecf20Sopenharmony_ci	};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ciThe ``info_id`` value should be an 8-bit number obtained from userspace and
1618c2ecf20Sopenharmony_cishifted by WATCH_INFO_ID__SHIFT.  This is OR'd into the WATCH_INFO_ID field of
1628c2ecf20Sopenharmony_cistruct watch_notification::info when and if the notification is written into
1638c2ecf20Sopenharmony_cithe associated watch queue buffer.
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciThe ``private`` field is the driver's data associated with the watch_list and
1668c2ecf20Sopenharmony_ciis cleaned up by the ``watch_list::release_watch()`` method.
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ciThe ``id`` field is the source's ID.  Notifications that are posted with a
1698c2ecf20Sopenharmony_cidifferent ID are ignored.
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciThe following functions are provided to manage watches:
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci  * ``void init_watch(struct watch *watch, struct watch_queue *wqueue);``
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci    Initialise a watch object, setting its pointer to the watch queue, using
1768c2ecf20Sopenharmony_ci    appropriate barriering to avoid lockdep complaints.
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci  * ``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);``
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci    Subscribe a watch to a watch list (notification source).  The
1818c2ecf20Sopenharmony_ci    driver-settable fields in the watch struct must have been set before this
1828c2ecf20Sopenharmony_ci    is called.
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci  * ::
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	int remove_watch_from_object(struct watch_list *wlist,
1878c2ecf20Sopenharmony_ci				     struct watch_queue *wqueue,
1888c2ecf20Sopenharmony_ci				     u64 id, false);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci    Remove a watch from a watch list, where the watch must match the specified
1918c2ecf20Sopenharmony_ci    watch queue (``wqueue``) and object identifier (``id``).  A notification
1928c2ecf20Sopenharmony_ci    (``WATCH_META_REMOVAL_NOTIFICATION``) is sent to the watch queue to
1938c2ecf20Sopenharmony_ci    indicate that the watch got removed.
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci  * ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);``
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci    Remove all the watches from a watch list.  It is expected that this will be
1988c2ecf20Sopenharmony_ci    called preparatory to destruction and that the watch list will be
1998c2ecf20Sopenharmony_ci    inaccessible to new watches by this point.  A notification
2008c2ecf20Sopenharmony_ci    (``WATCH_META_REMOVAL_NOTIFICATION``) is sent to the watch queue of each
2018c2ecf20Sopenharmony_ci    subscribed watch to indicate that the watch got removed.
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ciNotification Posting API
2058c2ecf20Sopenharmony_ci========================
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciTo post a notification to watch list so that the subscribed watches can see it,
2088c2ecf20Sopenharmony_cithe following function should be used::
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	void post_watch_notification(struct watch_list *wlist,
2118c2ecf20Sopenharmony_ci				     struct watch_notification *n,
2128c2ecf20Sopenharmony_ci				     const struct cred *cred,
2138c2ecf20Sopenharmony_ci				     u64 id);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciThe notification should be preformatted and a pointer to the header (``n``)
2168c2ecf20Sopenharmony_cishould be passed in.  The notification may be larger than this and the size in
2178c2ecf20Sopenharmony_ciunits of buffer slots is noted in ``n->info & WATCH_INFO_LENGTH``.
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ciThe ``cred`` struct indicates the credentials of the source (subject) and is
2208c2ecf20Sopenharmony_cipassed to the LSMs, such as SELinux, to allow or suppress the recording of the
2218c2ecf20Sopenharmony_cinote in each individual queue according to the credentials of that queue
2228c2ecf20Sopenharmony_ci(object).
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciThe ``id`` is the ID of the source object (such as the serial number on a key).
2258c2ecf20Sopenharmony_ciOnly watches that have the same ID set in them will see this notification.
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ciWatch Sources
2298c2ecf20Sopenharmony_ci=============
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciAny particular buffer can be fed from multiple sources.  Sources include:
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci  * WATCH_TYPE_KEY_NOTIFY
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci    Notifications of this type indicate changes to keys and keyrings, including
2368c2ecf20Sopenharmony_ci    the changes of keyring contents or the attributes of keys.
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci    See Documentation/security/keys/core.rst for more information.
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ciEvent Filtering
2428c2ecf20Sopenharmony_ci===============
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ciOnce a watch queue has been created, a set of filters can be applied to limit
2458c2ecf20Sopenharmony_cithe events that are received using::
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	struct watch_notification_filter filter = {
2488c2ecf20Sopenharmony_ci		...
2498c2ecf20Sopenharmony_ci	};
2508c2ecf20Sopenharmony_ci	ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ciThe filter description is a variable of type::
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	struct watch_notification_filter {
2558c2ecf20Sopenharmony_ci		__u32	nr_filters;
2568c2ecf20Sopenharmony_ci		__u32	__reserved;
2578c2ecf20Sopenharmony_ci		struct watch_notification_type_filter filters[];
2588c2ecf20Sopenharmony_ci	};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciWhere "nr_filters" is the number of filters in filters[] and "__reserved"
2618c2ecf20Sopenharmony_cishould be 0.  The "filters" array has elements of the following type::
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	struct watch_notification_type_filter {
2648c2ecf20Sopenharmony_ci		__u32	type;
2658c2ecf20Sopenharmony_ci		__u32	info_filter;
2668c2ecf20Sopenharmony_ci		__u32	info_mask;
2678c2ecf20Sopenharmony_ci		__u32	subtype_filter[8];
2688c2ecf20Sopenharmony_ci	};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciWhere:
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci  * ``type`` is the event type to filter for and should be something like
2738c2ecf20Sopenharmony_ci    "WATCH_TYPE_KEY_NOTIFY"
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci  * ``info_filter`` and ``info_mask`` act as a filter on the info field of the
2768c2ecf20Sopenharmony_ci    notification record.  The notification is only written into the buffer if::
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	(watch.info & info_mask) == info_filter
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci    This could be used, for example, to ignore events that are not exactly on
2818c2ecf20Sopenharmony_ci    the watched point in a mount tree.
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci  * ``subtype_filter`` is a bitmask indicating the subtypes that are of
2848c2ecf20Sopenharmony_ci    interest.  Bit 0 of subtype_filter[0] corresponds to subtype 0, bit 1 to
2858c2ecf20Sopenharmony_ci    subtype 1, and so on.
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ciIf the argument to the ioctl() is NULL, then the filters will be removed and
2888c2ecf20Sopenharmony_ciall events from the watched sources will come through.
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciUserspace Code Example
2928c2ecf20Sopenharmony_ci======================
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ciA buffer is created with something like the following::
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	pipe2(fds, O_TMPFILE);
2978c2ecf20Sopenharmony_ci	ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciIt can then be set to receive keyring change notifications::
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ciThe notifications can then be consumed by something like the following::
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	static void consumer(int rfd, struct watch_queue_buffer *buf)
3068c2ecf20Sopenharmony_ci	{
3078c2ecf20Sopenharmony_ci		unsigned char buffer[128];
3088c2ecf20Sopenharmony_ci		ssize_t buf_len;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		while (buf_len = read(rfd, buffer, sizeof(buffer)),
3118c2ecf20Sopenharmony_ci		       buf_len > 0
3128c2ecf20Sopenharmony_ci		       ) {
3138c2ecf20Sopenharmony_ci			void *p = buffer;
3148c2ecf20Sopenharmony_ci			void *end = buffer + buf_len;
3158c2ecf20Sopenharmony_ci			while (p < end) {
3168c2ecf20Sopenharmony_ci				union {
3178c2ecf20Sopenharmony_ci					struct watch_notification n;
3188c2ecf20Sopenharmony_ci					unsigned char buf1[128];
3198c2ecf20Sopenharmony_ci				} n;
3208c2ecf20Sopenharmony_ci				size_t largest, len;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci				largest = end - p;
3238c2ecf20Sopenharmony_ci				if (largest > 128)
3248c2ecf20Sopenharmony_ci					largest = 128;
3258c2ecf20Sopenharmony_ci				memcpy(&n, p, largest);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci				len = (n->info & WATCH_INFO_LENGTH) >>
3288c2ecf20Sopenharmony_ci					WATCH_INFO_LENGTH__SHIFT;
3298c2ecf20Sopenharmony_ci				if (len == 0 || len > largest)
3308c2ecf20Sopenharmony_ci					return;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci				switch (n.n.type) {
3338c2ecf20Sopenharmony_ci				case WATCH_TYPE_META:
3348c2ecf20Sopenharmony_ci					got_meta(&n.n);
3358c2ecf20Sopenharmony_ci				case WATCH_TYPE_KEY_NOTIFY:
3368c2ecf20Sopenharmony_ci					saw_key_change(&n.n);
3378c2ecf20Sopenharmony_ci					break;
3388c2ecf20Sopenharmony_ci				}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci				p += len;
3418c2ecf20Sopenharmony_ci			}
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
344