v2.6.22.22-op1-rc1
[linux-2.6.22.y-op.git] / ipc / msgutil.c
blobc82c215693d7c9c54ae93dfa90d7f162085900d5
1 /*
2 * linux/ipc/msgutil.c
3 * Copyright (C) 1999, 2004 Manfred Spraul
5 * This file is released under GNU General Public Licence version 2 or
6 * (at your option) any later version.
8 * See the file COPYING for more details.
9 */
11 #include <linux/spinlock.h>
12 #include <linux/init.h>
13 #include <linux/security.h>
14 #include <linux/slab.h>
15 #include <linux/ipc.h>
16 #include <asm/uaccess.h>
18 #include "util.h"
20 struct msg_msgseg {
21 struct msg_msgseg* next;
22 /* the next part of the message follows immediately */
25 #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
26 #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
28 struct msg_msg *load_msg(const void __user *src, int len)
30 struct msg_msg *msg;
31 struct msg_msgseg **pseg;
32 int err;
33 int alen;
35 alen = len;
36 if (alen > DATALEN_MSG)
37 alen = DATALEN_MSG;
39 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
40 if (msg == NULL)
41 return ERR_PTR(-ENOMEM);
43 msg->next = NULL;
44 msg->security = NULL;
46 if (copy_from_user(msg + 1, src, alen)) {
47 err = -EFAULT;
48 goto out_err;
51 len -= alen;
52 src = ((char __user *)src) + alen;
53 pseg = &msg->next;
54 while (len > 0) {
55 struct msg_msgseg *seg;
56 alen = len;
57 if (alen > DATALEN_SEG)
58 alen = DATALEN_SEG;
59 seg = kmalloc(sizeof(*seg) + alen,
60 GFP_KERNEL);
61 if (seg == NULL) {
62 err = -ENOMEM;
63 goto out_err;
65 *pseg = seg;
66 seg->next = NULL;
67 if (copy_from_user(seg + 1, src, alen)) {
68 err = -EFAULT;
69 goto out_err;
71 pseg = &seg->next;
72 len -= alen;
73 src = ((char __user *)src) + alen;
76 err = security_msg_msg_alloc(msg);
77 if (err)
78 goto out_err;
80 return msg;
82 out_err:
83 free_msg(msg);
84 return ERR_PTR(err);
87 int store_msg(void __user *dest, struct msg_msg *msg, int len)
89 int alen;
90 struct msg_msgseg *seg;
92 alen = len;
93 if (alen > DATALEN_MSG)
94 alen = DATALEN_MSG;
95 if (copy_to_user(dest, msg + 1, alen))
96 return -1;
98 len -= alen;
99 dest = ((char __user *)dest) + alen;
100 seg = msg->next;
101 while (len > 0) {
102 alen = len;
103 if (alen > DATALEN_SEG)
104 alen = DATALEN_SEG;
105 if (copy_to_user(dest, seg + 1, alen))
106 return -1;
107 len -= alen;
108 dest = ((char __user *)dest) + alen;
109 seg = seg->next;
111 return 0;
114 void free_msg(struct msg_msg *msg)
116 struct msg_msgseg *seg;
118 security_msg_msg_free(msg);
120 seg = msg->next;
121 kfree(msg);
122 while (seg != NULL) {
123 struct msg_msgseg *tmp = seg->next;
124 kfree(seg);
125 seg = tmp;