This source file includes following definitions.
- msg_init
- real_msgsnd
- kd_timeout
- real_msgrcv
- sys_msgsnd
- sys_msgrcv
- findkey
- newque
- sys_msgget
- freeque
- sys_msgctl
- kerneld_exit
- kerneld_send
1
2
3
4
5
6
7
8
9 #include <linux/config.h>
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/msg.h>
13 #include <linux/stat.h>
14 #include <linux/malloc.h>
15 #include <linux/kerneld.h>
16
17 #include <asm/segment.h>
18
19 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
20
21 static void freeque (int id);
22 static int newque (key_t key, int msgflg);
23 static int findkey (key_t key);
24
25 static struct msqid_ds *msgque[MSGMNI];
26 static int msgbytes = 0;
27 static int msghdrs = 0;
28 static unsigned short msg_seq = 0;
29 static int used_queues = 0;
30 static int max_msqid = 0;
31 static struct wait_queue *msg_lock = NULL;
32 static int kerneld_msqid = -1;
33
34 #define MAX_KERNELDS 20
35 static int kerneld_arr[MAX_KERNELDS];
36 static int n_kernelds = 0;
37
38 void msg_init (void)
39 {
40 int id;
41
42 for (id = 0; id < MSGMNI; id++)
43 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
44 msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
45 msg_lock = NULL;
46 return;
47 }
48
49 static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
50 {
51 int id, err;
52 struct msqid_ds *msq;
53 struct ipc_perm *ipcp;
54 struct msg *msgh;
55 long mtype;
56
57 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
58 return -EINVAL;
59 if (!msgp)
60 return -EFAULT;
61
62
63
64
65 if ((msgflg & IPC_KERNELD))
66 mtype = msgp->mtype;
67 else {
68 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
69 if (err)
70 return err;
71 if ((mtype = get_user (&msgp->mtype)) < 1)
72 return -EINVAL;
73 }
74 id = (unsigned int) msqid % MSGMNI;
75 msq = msgque [id];
76 if (msq == IPC_UNUSED || msq == IPC_NOID)
77 return -EINVAL;
78 ipcp = &msq->msg_perm;
79
80 slept:
81 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
82 return -EIDRM;
83
84
85
86
87
88 if ((msgflg & IPC_KERNELD) == 0)
89 if (ipcperms(ipcp, S_IWUGO))
90 return -EACCES;
91
92 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
93
94 if (msgflg & IPC_NOWAIT)
95 return -EAGAIN;
96 if (current->signal & ~current->blocked)
97 return -EINTR;
98 if (intr_count) {
99
100 printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
101 return -EINTR;
102 }
103 interruptible_sleep_on (&msq->wwait);
104 goto slept;
105 }
106
107
108 msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz,
109 (intr_count ? GFP_ATOMIC : GFP_USER));
110 if (!msgh)
111 return -ENOMEM;
112 msgh->msg_spot = (char *) (msgh + 1);
113
114
115
116
117
118 if (msgflg & IPC_KERNELD) {
119 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
120
121
122
123
124
125 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long));
126 memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
127 msgsz - sizeof(long));
128 }
129 else
130 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
131
132 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
133 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
134 kfree(msgh);
135 return -EIDRM;
136 }
137
138 msgh->msg_next = NULL;
139 if (!msq->msg_first)
140 msq->msg_first = msq->msg_last = msgh;
141 else {
142 msq->msg_last->msg_next = msgh;
143 msq->msg_last = msgh;
144 }
145 msgh->msg_ts = msgsz;
146 msgh->msg_type = mtype;
147 msq->msg_cbytes += msgsz;
148 msgbytes += msgsz;
149 msghdrs++;
150 msq->msg_qnum++;
151 msq->msg_lspid = current->pid;
152 msq->msg_stime = CURRENT_TIME;
153 if (msq->rwait)
154 wake_up (&msq->rwait);
155 return 0;
156 }
157
158
159
160
161 #define KERNELD_TIMEOUT 1 * (HZ)
162 #define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)
163
164 static void kd_timeout(unsigned long msgid)
165 {
166 struct msqid_ds *msq;
167 struct msg *tmsg;
168
169 msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
170 if (msq == IPC_NOID || msq == IPC_UNUSED)
171 return;
172
173 for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
174 if (*(long *)(tmsg->msg_spot) == msgid)
175 break;
176 if (tmsg) {
177 struct kerneld_msg kmsp = { msgid, -ENODEV, "" };
178
179 printk(KERN_ALERT "Ouch, kerneld timed out, message failed\n");
180 real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp,
181 sizeof(long),
182 S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
183 }
184 }
185
186 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
187 {
188 struct timer_list kd_timer;
189 struct msqid_ds *msq;
190 struct ipc_perm *ipcp;
191 struct msg *tmsg, *leastp = NULL;
192 struct msg *nmsg = NULL;
193 int id, err;
194
195 if (msqid < 0 || (long) msgsz < 0)
196 return -EINVAL;
197 if (!msgp || !msgp->mtext)
198 return -EFAULT;
199
200
201
202
203 if ((msgflg & IPC_KERNELD) == 0) {
204 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
205 if (err)
206 return err;
207 }
208
209 id = (unsigned int) msqid % MSGMNI;
210 msq = msgque [id];
211 if (msq == IPC_NOID || msq == IPC_UNUSED)
212 return -EINVAL;
213 ipcp = &msq->msg_perm;
214
215
216
217
218 if (msgflg & IPC_KERNELD) {
219 kd_timer.data = (unsigned long)msgtyp;
220 kd_timer.expires = jiffies + KERNELD_TIMEOUT;
221 kd_timer.function = kd_timeout;
222 add_timer(&kd_timer);
223 }
224
225
226
227
228
229
230
231 while (!nmsg) {
232 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
233 return -EIDRM;
234 if ((msgflg & IPC_KERNELD) == 0) {
235
236
237
238
239
240 if (ipcperms (ipcp, S_IRUGO))
241 return -EACCES;
242 }
243 if (msgtyp == 0)
244 nmsg = msq->msg_first;
245 else if (msgtyp > 0) {
246 if (msgflg & MSG_EXCEPT) {
247 for (tmsg = msq->msg_first; tmsg;
248 tmsg = tmsg->msg_next)
249 if (tmsg->msg_type != msgtyp)
250 break;
251 nmsg = tmsg;
252 } else {
253 for (tmsg = msq->msg_first; tmsg;
254 tmsg = tmsg->msg_next)
255 if (tmsg->msg_type == msgtyp)
256 break;
257 nmsg = tmsg;
258 }
259 } else {
260 for (leastp = tmsg = msq->msg_first; tmsg;
261 tmsg = tmsg->msg_next)
262 if (tmsg->msg_type < leastp->msg_type)
263 leastp = tmsg;
264 if (leastp && leastp->msg_type <= - msgtyp)
265 nmsg = leastp;
266 }
267
268 if (nmsg) {
269 DROP_TIMER;
270 if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
271 return -E2BIG;
272 msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
273 if (nmsg == msq->msg_first)
274 msq->msg_first = nmsg->msg_next;
275 else {
276 for (tmsg = msq->msg_first; tmsg;
277 tmsg = tmsg->msg_next)
278 if (tmsg->msg_next == nmsg)
279 break;
280 tmsg->msg_next = nmsg->msg_next;
281 if (nmsg == msq->msg_last)
282 msq->msg_last = tmsg;
283 }
284 if (!(--msq->msg_qnum))
285 msq->msg_last = msq->msg_first = NULL;
286
287 msq->msg_rtime = CURRENT_TIME;
288 msq->msg_lrpid = current->pid;
289 msgbytes -= nmsg->msg_ts;
290 msghdrs--;
291 msq->msg_cbytes -= nmsg->msg_ts;
292 if (msq->wwait)
293 wake_up (&msq->wwait);
294
295
296
297
298 if (msgflg & IPC_KERNELD) {
299 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
300
301 memcpy((char *)(&(kdmp->id)),
302 nmsg->msg_spot,
303 sizeof(long));
304
305
306
307
308 if ((msgsz > sizeof(long)) && kdmp->text)
309 memcpy(kdmp->text,
310 nmsg->msg_spot + sizeof(long),
311 msgsz - sizeof(long));
312 }
313 else {
314 put_user (nmsg->msg_type, &msgp->mtype);
315 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
316 }
317 kfree(nmsg);
318 return msgsz;
319 } else {
320 if (msgflg & IPC_NOWAIT) {
321 DROP_TIMER;
322 return -ENOMSG;
323 }
324 if (current->signal & ~current->blocked) {
325 DROP_TIMER;
326 return -EINTR;
327 }
328 if (intr_count) {
329 DROP_TIMER;
330
331 printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
332 return -EINTR;
333 }
334 interruptible_sleep_on (&msq->rwait);
335 }
336 }
337 DROP_TIMER;
338 return -1;
339 }
340
341 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
342 {
343
344 return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
345 }
346
347 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
348 long msgtyp, int msgflg)
349 {
350
351 return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
352 }
353
354 static int findkey (key_t key)
355 {
356 int id;
357 struct msqid_ds *msq;
358
359 for (id = 0; id <= max_msqid; id++) {
360 while ((msq = msgque[id]) == IPC_NOID)
361 interruptible_sleep_on (&msg_lock);
362 if (msq == IPC_UNUSED)
363 continue;
364 if (key == msq->msg_perm.key)
365 return id;
366 }
367 return -1;
368 }
369
370 static int newque (key_t key, int msgflg)
371 {
372 int id;
373 struct msqid_ds *msq;
374 struct ipc_perm *ipcp;
375
376 for (id = 0; id < MSGMNI; id++)
377 if (msgque[id] == IPC_UNUSED) {
378 msgque[id] = (struct msqid_ds *) IPC_NOID;
379 goto found;
380 }
381 return -ENOSPC;
382
383 found:
384 msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
385 if (!msq) {
386 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
387 if (msg_lock)
388 wake_up (&msg_lock);
389 return -ENOMEM;
390 }
391 ipcp = &msq->msg_perm;
392 ipcp->mode = (msgflg & S_IRWXUGO);
393 ipcp->key = key;
394 ipcp->cuid = ipcp->uid = current->euid;
395 ipcp->gid = ipcp->cgid = current->egid;
396 msq->msg_perm.seq = msg_seq;
397 msq->msg_first = msq->msg_last = NULL;
398 msq->rwait = msq->wwait = NULL;
399 msq->msg_cbytes = msq->msg_qnum = 0;
400 msq->msg_lspid = msq->msg_lrpid = 0;
401 msq->msg_stime = msq->msg_rtime = 0;
402 msq->msg_qbytes = MSGMNB;
403 msq->msg_ctime = CURRENT_TIME;
404 if (id > max_msqid)
405 max_msqid = id;
406 msgque[id] = msq;
407 used_queues++;
408 if (msg_lock)
409 wake_up (&msg_lock);
410 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
411 }
412
413 asmlinkage int sys_msgget (key_t key, int msgflg)
414 {
415 int id;
416 struct msqid_ds *msq;
417
418
419
420
421
422 if ((msgflg & IPC_KERNELD)) {
423 int i;
424 if (!suser())
425 return -EPERM;
426 if ((kerneld_msqid == -1) && (kerneld_msqid =
427 newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
428 return -ENOSPC;
429 for (i = 0; i < MAX_KERNELDS; ++i) {
430 if (kerneld_arr[i] == 0) {
431 kerneld_arr[i] = current->pid;
432 ++n_kernelds;
433 return kerneld_msqid;
434 }
435 }
436 return -ENOSPC;
437 }
438
439 if (key == IPC_PRIVATE)
440 return newque(key, msgflg);
441 if ((id = findkey (key)) == -1) {
442 if (!(msgflg & IPC_CREAT))
443 return -ENOENT;
444 return newque(key, msgflg);
445 }
446 if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
447 return -EEXIST;
448 msq = msgque[id];
449 if (msq == IPC_UNUSED || msq == IPC_NOID)
450 return -EIDRM;
451 if (ipcperms(&msq->msg_perm, msgflg))
452 return -EACCES;
453 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
454 }
455
456 static void freeque (int id)
457 {
458 struct msqid_ds *msq = msgque[id];
459 struct msg *msgp, *msgh;
460
461 msq->msg_perm.seq++;
462 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
463 msgbytes -= msq->msg_cbytes;
464 if (id == max_msqid)
465 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
466 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
467 used_queues--;
468 while (msq->rwait || msq->wwait) {
469 if (msq->rwait)
470 wake_up (&msq->rwait);
471 if (msq->wwait)
472 wake_up (&msq->wwait);
473 schedule();
474 }
475 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
476 msgh = msgp->msg_next;
477 msghdrs--;
478 kfree(msgp);
479 }
480 kfree(msq);
481 }
482
483 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
484 {
485 int id, err;
486 struct msqid_ds *msq;
487 struct msqid_ds tbuf;
488 struct ipc_perm *ipcp;
489
490 if (msqid < 0 || cmd < 0)
491 return -EINVAL;
492 switch (cmd) {
493 case IPC_INFO:
494 case MSG_INFO:
495 if (!buf)
496 return -EFAULT;
497 {
498 struct msginfo msginfo;
499 msginfo.msgmni = MSGMNI;
500 msginfo.msgmax = MSGMAX;
501 msginfo.msgmnb = MSGMNB;
502 msginfo.msgmap = MSGMAP;
503 msginfo.msgpool = MSGPOOL;
504 msginfo.msgtql = MSGTQL;
505 msginfo.msgssz = MSGSSZ;
506 msginfo.msgseg = MSGSEG;
507 if (cmd == MSG_INFO) {
508 msginfo.msgpool = used_queues;
509 msginfo.msgmap = msghdrs;
510 msginfo.msgtql = msgbytes;
511 }
512 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
513 if (err)
514 return err;
515 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
516 return max_msqid;
517 }
518 case MSG_STAT:
519 if (!buf)
520 return -EFAULT;
521 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
522 if (err)
523 return err;
524 if (msqid > max_msqid)
525 return -EINVAL;
526 msq = msgque[msqid];
527 if (msq == IPC_UNUSED || msq == IPC_NOID)
528 return -EINVAL;
529 if (ipcperms (&msq->msg_perm, S_IRUGO))
530 return -EACCES;
531 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
532 tbuf.msg_perm = msq->msg_perm;
533 tbuf.msg_stime = msq->msg_stime;
534 tbuf.msg_rtime = msq->msg_rtime;
535 tbuf.msg_ctime = msq->msg_ctime;
536 tbuf.msg_cbytes = msq->msg_cbytes;
537 tbuf.msg_qnum = msq->msg_qnum;
538 tbuf.msg_qbytes = msq->msg_qbytes;
539 tbuf.msg_lspid = msq->msg_lspid;
540 tbuf.msg_lrpid = msq->msg_lrpid;
541 memcpy_tofs (buf, &tbuf, sizeof(*buf));
542 return id;
543 case IPC_SET:
544 if (!buf)
545 return -EFAULT;
546 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
547 if (err)
548 return err;
549 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
550 break;
551 case IPC_STAT:
552 if (!buf)
553 return -EFAULT;
554 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
555 if (err)
556 return err;
557 break;
558 }
559
560 id = (unsigned int) msqid % MSGMNI;
561 msq = msgque [id];
562 if (msq == IPC_UNUSED || msq == IPC_NOID)
563 return -EINVAL;
564 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
565 return -EIDRM;
566 ipcp = &msq->msg_perm;
567
568 switch (cmd) {
569 case IPC_STAT:
570 if (ipcperms (ipcp, S_IRUGO))
571 return -EACCES;
572 tbuf.msg_perm = msq->msg_perm;
573 tbuf.msg_stime = msq->msg_stime;
574 tbuf.msg_rtime = msq->msg_rtime;
575 tbuf.msg_ctime = msq->msg_ctime;
576 tbuf.msg_cbytes = msq->msg_cbytes;
577 tbuf.msg_qnum = msq->msg_qnum;
578 tbuf.msg_qbytes = msq->msg_qbytes;
579 tbuf.msg_lspid = msq->msg_lspid;
580 tbuf.msg_lrpid = msq->msg_lrpid;
581 memcpy_tofs (buf, &tbuf, sizeof (*buf));
582 return 0;
583 case IPC_SET:
584 if (!suser() && current->euid != ipcp->cuid &&
585 current->euid != ipcp->uid)
586 return -EPERM;
587 if (tbuf.msg_qbytes > MSGMNB && !suser())
588 return -EPERM;
589 msq->msg_qbytes = tbuf.msg_qbytes;
590 ipcp->uid = tbuf.msg_perm.uid;
591 ipcp->gid = tbuf.msg_perm.gid;
592 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
593 (S_IRWXUGO & tbuf.msg_perm.mode);
594 msq->msg_ctime = CURRENT_TIME;
595 return 0;
596 case IPC_RMID:
597 if (!suser() && current->euid != ipcp->cuid &&
598 current->euid != ipcp->uid)
599 return -EPERM;
600
601
602
603
604 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
605 kerneld_msqid = -1;
606 freeque (id);
607 return 0;
608 default:
609 return -EINVAL;
610 }
611 }
612
613
614
615
616
617
618
619
620 void kerneld_exit(void)
621 {
622 int i;
623
624 if (kerneld_msqid == -1)
625 return;
626 for (i = 0; i < MAX_KERNELDS; ++i) {
627 if (kerneld_arr[i] == current->pid) {
628 kerneld_arr[i] = 0;
629 --n_kernelds;
630 if (n_kernelds == 0)
631 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
632 break;
633 }
634 }
635 }
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669 int kerneld_send(int msgtype, int ret_size, int msgsz,
670 const char *text, const char *ret_val)
671 {
672 int status = -ENOSYS;
673 #ifdef CONFIG_KERNELD
674 static int id = KERNELD_MINSEQ;
675 struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
676 int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
677
678 if (kerneld_msqid == -1)
679 return -ENODEV;
680
681
682 if (intr_count)
683 ret_size &= ~KERNELD_WAIT;
684
685 msgsz += sizeof(long);
686 if (ret_size & KERNELD_WAIT) {
687 if (++id <= 0)
688 id = KERNELD_MINSEQ;
689 kmsp.id = id;
690 }
691
692 status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
693 if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
694 ret_size &= ~KERNELD_WAIT;
695 kmsp.text = (char *)ret_val;
696 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
697 sizeof(long) + ((ret_val)?ret_size:0),
698 kmsp.id, msgflg);
699 if (status > 0)
700 status = kmsp.id;
701 }
702
703 #endif
704 return status;
705 }