1 /*
2 * Copyright 1991-1998 by Open Software Foundation, Inc.
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21 /*
22 * MkLinux
23 */
24 /* CMU_HIST */
25 /*
26 * Revision 2.5.2.2 92/03/28 10:09:23 jeffreyh
27 * NORMA_IPC: Don't send send_once notification if port is dead.
28 * [92/03/25 dlb]
29 *
30 * Revision 2.5.2.1 92/01/03 16:35:29 jsb
31 * Did I say ndproxy? I meant to say nsproxy.
32 * [91/12/31 21:40:41 jsb]
33 *
34 * Changes for IP_NORMA_REQUEST macros being renamed to ip_ndproxy{,m,p}.
35 * [91/12/30 07:57:26 jsb]
36 *
37 * Use IP_IS_NORMA_NSREQUEST macro.
38 * [91/12/28 17:05:21 jsb]
39 *
40 * Added norma_ipc_notify_no_senders hook in ipc_notify_no_senders.
41 * [91/12/24 14:37:56 jsb]
42 *
43 * Revision 2.5 91/08/28 11:13:41 jsb
44 * Changed msgh_kind to msgh_seqno.
45 * [91/08/09 rpd]
46 *
47 * Revision 2.4 91/05/14 16:34:24 mrt
48 * Correcting copyright
49 *
50 * Revision 2.3 91/02/05 17:22:33 mrt
51 * Changed to new Mach copyright
52 * [91/02/01 15:46:58 mrt]
53 *
54 * Revision 2.2 90/06/02 14:50:50 rpd
55 * Created for new IPC.
56 * [90/03/26 20:57:58 rpd]
57 *
58 */
59 /* CMU_ENDHIST */
60 /*
61 * Mach Operating System
62 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
63 * All Rights Reserved.
64 *
65 * Permission to use, copy, modify and distribute this software and its
66 * documentation is hereby granted, provided that both the copyright
67 * notice and this permission notice appear in all copies of the
68 * software, derivative works or modified versions, and any portions
69 * thereof, and that both notices appear in supporting documentation.
70 *
71 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
72 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
73 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
74 *
75 * Carnegie Mellon requests users of this software to return to
76 *
77 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
78 * School of Computer Science
79 * Carnegie Mellon University
80 * Pittsburgh PA 15213-3890
81 *
82 * any improvements or extensions that they make and grant Carnegie Mellon
83 * the rights to redistribute these changes.
84 */
85 /*
86 */
87 /*
88 * File: ipc/ipc_notify.c
89 * Author: Rich Draves
90 * Date: 1989
91 *
92 * Notification-sending functions.
93 */
94
95
96 #include <sys/mach/port.h>
97 #include <sys/mach/message.h>
98 #include <sys/mach/notify.h>
99 #if 0
100 #include <kern/assert.h>
101 #include <kern/misc_protos.h>
102 #endif
103 #include <sys/mach/ipc/ipc_kmsg.h>
104 #include <sys/mach/ipc/ipc_mqueue.h>
105 #include <sys/mach/ipc/ipc_notify.h>
106 #include <sys/mach/ipc/ipc_port.h>
107
108 /*
109 * Forward declarations
110 */
111 void ipc_notify_init_port_deleted(
112 mach_port_deleted_notification_t *n);
113
114 void ipc_notify_init_port_destroyed(
115 mach_port_destroyed_notification_t *n);
116
117 void ipc_notify_init_no_senders(
118 mach_no_senders_notification_t *n);
119
120 void ipc_notify_init_send_once(
121 mach_send_once_notification_t *n);
122
123 void ipc_notify_init_dead_name(
124 mach_dead_name_notification_t *n);
125
126 mach_port_deleted_notification_t ipc_notify_port_deleted_template;
127 mach_port_destroyed_notification_t ipc_notify_port_destroyed_template;
128 mach_no_senders_notification_t ipc_notify_no_senders_template;
129 mach_send_once_notification_t ipc_notify_send_once_template;
130 mach_dead_name_notification_t ipc_notify_dead_name_template;
131
132 /*
133 * Routine: ipc_notify_init_port_deleted
134 * Purpose:
135 * Initialize a template for port-deleted notifications.
136 */
137
138 void
ipc_notify_init_port_deleted(mach_port_deleted_notification_t * n)139 ipc_notify_init_port_deleted(
140 mach_port_deleted_notification_t *n)
141 {
142 mach_msg_header_t *m = &n->not_header;
143
144 m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0);
145 m->msgh_local_port = MACH_PORT_NULL;
146 m->msgh_remote_port = MACH_PORT_NULL;
147 m->msgh_id = MACH_NOTIFY_PORT_DELETED;
148 m->msgh_size = ((int)sizeof *n) - sizeof(mach_msg_format_0_trailer_t);
149
150 n->not_port = MACH_PORT_NAME_NULL;
151 n->NDR = NDR_record;
152 n->trailer.msgh_seqno = 0;
153 n->trailer.msgh_sender = KERNEL_SECURITY_TOKEN;
154 n->trailer.msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
155 n->trailer.msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
156 }
157
158 /*
159 * Routine: ipc_notify_init_port_destroyed
160 * Purpose:
161 * Initialize a template for port-destroyed notifications.
162 */
163
164 void
ipc_notify_init_port_destroyed(mach_port_destroyed_notification_t * n)165 ipc_notify_init_port_destroyed(
166 mach_port_destroyed_notification_t *n)
167 {
168 mach_msg_header_t *m = &n->not_header;
169
170 m->msgh_bits = MACH_MSGH_BITS_COMPLEX |
171 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0);
172 m->msgh_local_port = MACH_PORT_NULL;
173 m->msgh_remote_port = MACH_PORT_NULL;
174 m->msgh_id = MACH_NOTIFY_PORT_DESTROYED;
175 m->msgh_size = ((int)sizeof *n) - sizeof(mach_msg_format_0_trailer_t);
176
177 n->not_body.msgh_descriptor_count = 1;
178 n->not_port.disposition = MACH_MSG_TYPE_PORT_RECEIVE;
179 n->not_port.name = MACH_PORT_NULL;
180 n->not_port.type = MACH_MSG_PORT_DESCRIPTOR;
181 n->trailer.msgh_seqno = 0;
182 n->trailer.msgh_sender = KERNEL_SECURITY_TOKEN;
183 n->trailer.msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
184 n->trailer.msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
185 }
186
187 /*
188 * Routine: ipc_notify_init_no_senders
189 * Purpose:
190 * Initialize a template for no-senders notifications.
191 */
192
193 void
ipc_notify_init_no_senders(mach_no_senders_notification_t * n)194 ipc_notify_init_no_senders(
195 mach_no_senders_notification_t *n)
196 {
197 mach_msg_header_t *m = &n->not_header;
198
199 m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0);
200 m->msgh_local_port = MACH_PORT_NULL;
201 m->msgh_remote_port = MACH_PORT_NULL;
202 m->msgh_id = MACH_NOTIFY_NO_SENDERS;
203 m->msgh_size = ((int)sizeof *n) - sizeof(mach_msg_format_0_trailer_t);
204
205 n->NDR = NDR_record;
206 n->trailer.msgh_seqno = 0;
207 n->trailer.msgh_sender = KERNEL_SECURITY_TOKEN;
208 n->trailer.msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
209 n->trailer.msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
210 n->not_count = 0;
211 }
212
213 /*
214 * Routine: ipc_notify_init_send_once
215 * Purpose:
216 * Initialize a template for send-once notifications.
217 */
218
219 void
ipc_notify_init_send_once(mach_send_once_notification_t * n)220 ipc_notify_init_send_once(
221 mach_send_once_notification_t *n)
222 {
223 mach_msg_header_t *m = &n->not_header;
224
225 m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0);
226 m->msgh_local_port = MACH_PORT_NULL;
227 m->msgh_remote_port = MACH_PORT_NULL;
228 m->msgh_id = MACH_NOTIFY_SEND_ONCE;
229 m->msgh_size = ((int)sizeof *n) - sizeof(mach_msg_format_0_trailer_t);
230 n->trailer.msgh_seqno = 0;
231 n->trailer.msgh_sender = KERNEL_SECURITY_TOKEN;
232 n->trailer.msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
233 n->trailer.msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
234 }
235
236 /*
237 * Routine: ipc_notify_init_dead_name
238 * Purpose:
239 * Initialize a template for dead-name notifications.
240 */
241
242 void
ipc_notify_init_dead_name(mach_dead_name_notification_t * n)243 ipc_notify_init_dead_name(
244 mach_dead_name_notification_t *n)
245 {
246 mach_msg_header_t *m = &n->not_header;
247
248 m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0);
249 m->msgh_local_port = MACH_PORT_NULL;
250 m->msgh_remote_port = MACH_PORT_NULL;
251 m->msgh_id = MACH_NOTIFY_DEAD_NAME;
252 m->msgh_size = ((int)sizeof *n) - sizeof(mach_msg_format_0_trailer_t);
253
254 n->not_port = MACH_PORT_NAME_NULL;
255 n->NDR = NDR_record;
256 n->trailer.msgh_seqno = 0;
257 n->trailer.msgh_sender = KERNEL_SECURITY_TOKEN;
258 n->trailer.msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
259 n->trailer.msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
260 }
261
262 /*
263 * Routine: ipc_notify_init
264 * Purpose:
265 * Initialize the notification subsystem.
266 */
267
268 void
ipc_notify_init(void)269 ipc_notify_init(void)
270 {
271 ipc_notify_init_port_deleted(&ipc_notify_port_deleted_template);
272 ipc_notify_init_port_destroyed(&ipc_notify_port_destroyed_template);
273 ipc_notify_init_no_senders(&ipc_notify_no_senders_template);
274 ipc_notify_init_send_once(&ipc_notify_send_once_template);
275 ipc_notify_init_dead_name(&ipc_notify_dead_name_template);
276 }
277
278 /*
279 * Routine: ipc_notify_port_deleted
280 * Purpose:
281 * Send a port-deleted notification.
282 * Conditions:
283 * Nothing locked.
284 * Consumes a ref/soright for port.
285 */
286
287 void
ipc_notify_port_deleted(ipc_port_t port,mach_port_name_t name)288 ipc_notify_port_deleted(
289 ipc_port_t port,
290 mach_port_name_t name)
291 {
292 ipc_kmsg_t kmsg;
293 mach_port_deleted_notification_t *n;
294
295 kmsg = ikm_alloc(sizeof *n);
296 if (kmsg == IKM_NULL) {
297 printf("dropped port-deleted (%p, 0x%x)\n", port, name);
298 ipc_port_release_sonce(port);
299 return;
300 }
301
302 ikm_init(kmsg, sizeof *n);
303 n = (mach_port_deleted_notification_t *) kmsg->ikm_header;
304 *n = ipc_notify_port_deleted_template;
305
306 n->not_header.msgh_remote_port = (mach_port_t) port;
307 n->not_port = name;
308
309 ipc_mqueue_send_always(kmsg);
310 }
311
312 /*
313 * Routine: ipc_notify_port_destroyed
314 * Purpose:
315 * Send a port-destroyed notification.
316 * Conditions:
317 * Nothing locked.
318 * Consumes a ref/soright for port.
319 * Consumes a ref for right, which should be a receive right
320 * prepped for placement into a message. (In-transit,
321 * or in-limbo if a circularity was detected.)
322 */
323
324 void
ipc_notify_port_destroyed(ipc_port_t port,ipc_port_t right)325 ipc_notify_port_destroyed(
326 ipc_port_t port,
327 ipc_port_t right)
328 {
329 ipc_kmsg_t kmsg;
330 mach_port_destroyed_notification_t *n;
331
332 kmsg = ikm_alloc(sizeof *n);
333 if (kmsg == IKM_NULL) {
334 printf("dropped port-destroyed (%p, %p)\n",
335 port, right);
336 ipc_port_release_sonce(port);
337 ipc_port_release_receive(right);
338 return;
339 }
340
341 ikm_init(kmsg, sizeof *n);
342 n = (mach_port_destroyed_notification_t *) kmsg->ikm_header;
343 *n = ipc_notify_port_destroyed_template;
344
345 n->not_header.msgh_remote_port = (mach_port_t) port;
346 n->not_port.name = (mach_port_t)right;
347
348 ipc_mqueue_send_always(kmsg);
349 }
350
351 /*
352 * Routine: ipc_notify_no_senders
353 * Purpose:
354 * Send a no-senders notification.
355 * Conditions:
356 * Nothing locked.
357 * Consumes a ref/soright for port.
358 */
359
360 void
ipc_notify_no_senders(ipc_port_t port,mach_port_mscount_t mscount)361 ipc_notify_no_senders(
362 ipc_port_t port,
363 mach_port_mscount_t mscount)
364 {
365 ipc_kmsg_t kmsg;
366 mach_no_senders_notification_t *n;
367
368 kmsg = ikm_alloc(sizeof *n);
369 if (kmsg == IKM_NULL) {
370 printf("dropped no-senders (%p, %u)\n", port, mscount);
371 ipc_port_release_sonce(port);
372 return;
373 }
374
375 ikm_init(kmsg, sizeof *n);
376 n = (mach_no_senders_notification_t *) kmsg->ikm_header;
377 *n = ipc_notify_no_senders_template;
378
379 n->not_header.msgh_remote_port = (mach_port_t) port;
380 n->not_count = mscount;
381
382 ipc_mqueue_send_always(kmsg);
383 }
384
385 /*
386 * Routine: ipc_notify_send_once
387 * Purpose:
388 * Send a send-once notification.
389 * Conditions:
390 * Nothing locked.
391 * Consumes a ref/soright for port.
392 */
393
394 void
ipc_notify_send_once(ipc_port_t port)395 ipc_notify_send_once(
396 ipc_port_t port)
397 {
398 ipc_kmsg_t kmsg;
399 mach_send_once_notification_t *n;
400
401 kmsg = ikm_alloc(sizeof *n);
402 if (kmsg == IKM_NULL) {
403 printf("dropped send-once (%p)\n", port);
404 ipc_port_release_sonce(port);
405 return;
406 }
407
408 ikm_init(kmsg, sizeof *n);
409 n = (mach_send_once_notification_t *) kmsg->ikm_header;
410 *n = ipc_notify_send_once_template;
411
412 n->not_header.msgh_remote_port = (mach_port_t) port;
413
414 ipc_mqueue_send_always(kmsg);
415 }
416
417 /*
418 * Routine: ipc_notify_dead_name
419 * Purpose:
420 * Send a dead-name notification.
421 * Conditions:
422 * Nothing locked.
423 * Consumes a ref/soright for port.
424 */
425
426 void
ipc_notify_dead_name(ipc_port_t port,mach_port_name_t name)427 ipc_notify_dead_name(
428 ipc_port_t port,
429 mach_port_name_t name)
430 {
431 ipc_kmsg_t kmsg;
432 mach_dead_name_notification_t *n;
433
434 kmsg = ikm_alloc(sizeof *n);
435 if (kmsg == IKM_NULL) {
436 printf("dropped dead-name (%p, 0x%x)\n", port, name);
437 ipc_port_release_sonce(port);
438 return;
439 }
440
441 ikm_init(kmsg, sizeof *n);
442 n = (mach_dead_name_notification_t *) kmsg->ikm_header;
443 *n = ipc_notify_dead_name_template;
444
445 n->not_header.msgh_remote_port = (mach_port_t) port;
446 n->not_port = name;
447
448 ipc_mqueue_send_always(kmsg);
449 }
450