1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "dlm_internal.h"
28#include "lowcomms.h"
29#include "config.h"
30#include "lock.h"
31#include "midcomms.h"
32
33
34static void copy_from_cb(void *dst, const void *base, unsigned offset,
35 unsigned len, unsigned limit)
36{
37 unsigned copy = len;
38
39 if ((copy + offset) > limit)
40 copy = limit - offset;
41 memcpy(dst, base + offset, copy);
42 len -= copy;
43 if (len)
44 memcpy(dst + copy, base, len);
45}
46
47
48
49
50
51
52
53
54
55
56
57
58int dlm_process_incoming_buffer(int nodeid, const void *base,
59 unsigned offset, unsigned len, unsigned limit)
60{
61 union {
62 unsigned char __buf[DLM_INBUF_LEN];
63
64 union dlm_packet p;
65 } __tmp;
66 union dlm_packet *p = &__tmp.p;
67 int ret = 0;
68 int err = 0;
69 uint16_t msglen;
70 uint32_t lockspace;
71
72 while (len > sizeof(struct dlm_header)) {
73
74
75
76
77
78 copy_from_cb(p, base, offset, sizeof(struct dlm_header),
79 limit);
80
81 msglen = le16_to_cpu(p->header.h_length);
82 lockspace = p->header.h_lockspace;
83
84 err = -EINVAL;
85 if (msglen < sizeof(struct dlm_header))
86 break;
87 if (p->header.h_cmd == DLM_MSG) {
88 if (msglen < sizeof(struct dlm_message))
89 break;
90 } else {
91 if (msglen < sizeof(struct dlm_rcom))
92 break;
93 }
94 err = -E2BIG;
95 if (msglen > dlm_config.ci_buffer_size) {
96 log_print("message size %d from %d too big, buf len %d",
97 msglen, nodeid, len);
98 break;
99 }
100 err = 0;
101
102
103
104
105
106
107 if (msglen > len)
108 break;
109
110
111
112
113
114 if (msglen > sizeof(__tmp) && p == &__tmp.p) {
115 p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS);
116 if (p == NULL)
117 return ret;
118 }
119
120 copy_from_cb(p, base, offset, msglen, limit);
121
122 BUG_ON(lockspace != p->header.h_lockspace);
123
124 ret += msglen;
125 offset += msglen;
126 offset &= (limit - 1);
127 len -= msglen;
128
129 dlm_receive_buffer(p, nodeid);
130 }
131
132 if (p != &__tmp.p)
133 kfree(p);
134
135 return err ? err : ret;
136}
137
138