Commit 4e9b82693542003b028c8494e9e3c49615b91ce7
Committed by
David S. Miller
1 parent
d61c167dd0
Exists in
master
and in
7 other branches
[NETLINK]: Remove unused dst_pid field in netlink_skb_parms
The destination PID is passed directly to netlink_unicast() respectively netlink_multicast(). Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 7 changed files with 2 additions and 13 deletions Inline Diff
include/linux/netlink.h
1 | #ifndef __LINUX_NETLINK_H | 1 | #ifndef __LINUX_NETLINK_H |
2 | #define __LINUX_NETLINK_H | 2 | #define __LINUX_NETLINK_H |
3 | 3 | ||
4 | #include <linux/socket.h> /* for sa_family_t */ | 4 | #include <linux/socket.h> /* for sa_family_t */ |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | 6 | ||
7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ | 7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ |
8 | #define NETLINK_UNUSED 1 /* Unused number */ | 8 | #define NETLINK_UNUSED 1 /* Unused number */ |
9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ | 9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ |
10 | #define NETLINK_FIREWALL 3 /* Firewalling hook */ | 10 | #define NETLINK_FIREWALL 3 /* Firewalling hook */ |
11 | #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ | 11 | #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ |
12 | #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ | 12 | #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ |
13 | #define NETLINK_XFRM 6 /* ipsec */ | 13 | #define NETLINK_XFRM 6 /* ipsec */ |
14 | #define NETLINK_SELINUX 7 /* SELinux event notifications */ | 14 | #define NETLINK_SELINUX 7 /* SELinux event notifications */ |
15 | #define NETLINK_ISCSI 8 /* Open-iSCSI */ | 15 | #define NETLINK_ISCSI 8 /* Open-iSCSI */ |
16 | #define NETLINK_AUDIT 9 /* auditing */ | 16 | #define NETLINK_AUDIT 9 /* auditing */ |
17 | #define NETLINK_FIB_LOOKUP 10 | 17 | #define NETLINK_FIB_LOOKUP 10 |
18 | #define NETLINK_CONNECTOR 11 | 18 | #define NETLINK_CONNECTOR 11 |
19 | #define NETLINK_NETFILTER 12 /* netfilter subsystem */ | 19 | #define NETLINK_NETFILTER 12 /* netfilter subsystem */ |
20 | #define NETLINK_IP6_FW 13 | 20 | #define NETLINK_IP6_FW 13 |
21 | #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ | 21 | #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ |
22 | #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ | 22 | #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ |
23 | #define NETLINK_GENERIC 16 | 23 | #define NETLINK_GENERIC 16 |
24 | /* leave room for NETLINK_DM (DM Events) */ | 24 | /* leave room for NETLINK_DM (DM Events) */ |
25 | #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ | 25 | #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ |
26 | 26 | ||
27 | #define MAX_LINKS 32 | 27 | #define MAX_LINKS 32 |
28 | 28 | ||
29 | struct sockaddr_nl | 29 | struct sockaddr_nl |
30 | { | 30 | { |
31 | sa_family_t nl_family; /* AF_NETLINK */ | 31 | sa_family_t nl_family; /* AF_NETLINK */ |
32 | unsigned short nl_pad; /* zero */ | 32 | unsigned short nl_pad; /* zero */ |
33 | __u32 nl_pid; /* process pid */ | 33 | __u32 nl_pid; /* process pid */ |
34 | __u32 nl_groups; /* multicast groups mask */ | 34 | __u32 nl_groups; /* multicast groups mask */ |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct nlmsghdr | 37 | struct nlmsghdr |
38 | { | 38 | { |
39 | __u32 nlmsg_len; /* Length of message including header */ | 39 | __u32 nlmsg_len; /* Length of message including header */ |
40 | __u16 nlmsg_type; /* Message content */ | 40 | __u16 nlmsg_type; /* Message content */ |
41 | __u16 nlmsg_flags; /* Additional flags */ | 41 | __u16 nlmsg_flags; /* Additional flags */ |
42 | __u32 nlmsg_seq; /* Sequence number */ | 42 | __u32 nlmsg_seq; /* Sequence number */ |
43 | __u32 nlmsg_pid; /* Sending process PID */ | 43 | __u32 nlmsg_pid; /* Sending process PID */ |
44 | }; | 44 | }; |
45 | 45 | ||
46 | /* Flags values */ | 46 | /* Flags values */ |
47 | 47 | ||
48 | #define NLM_F_REQUEST 1 /* It is request message. */ | 48 | #define NLM_F_REQUEST 1 /* It is request message. */ |
49 | #define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ | 49 | #define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ |
50 | #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ | 50 | #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ |
51 | #define NLM_F_ECHO 8 /* Echo this request */ | 51 | #define NLM_F_ECHO 8 /* Echo this request */ |
52 | 52 | ||
53 | /* Modifiers to GET request */ | 53 | /* Modifiers to GET request */ |
54 | #define NLM_F_ROOT 0x100 /* specify tree root */ | 54 | #define NLM_F_ROOT 0x100 /* specify tree root */ |
55 | #define NLM_F_MATCH 0x200 /* return all matching */ | 55 | #define NLM_F_MATCH 0x200 /* return all matching */ |
56 | #define NLM_F_ATOMIC 0x400 /* atomic GET */ | 56 | #define NLM_F_ATOMIC 0x400 /* atomic GET */ |
57 | #define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) | 57 | #define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) |
58 | 58 | ||
59 | /* Modifiers to NEW request */ | 59 | /* Modifiers to NEW request */ |
60 | #define NLM_F_REPLACE 0x100 /* Override existing */ | 60 | #define NLM_F_REPLACE 0x100 /* Override existing */ |
61 | #define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ | 61 | #define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ |
62 | #define NLM_F_CREATE 0x400 /* Create, if it does not exist */ | 62 | #define NLM_F_CREATE 0x400 /* Create, if it does not exist */ |
63 | #define NLM_F_APPEND 0x800 /* Add to end of list */ | 63 | #define NLM_F_APPEND 0x800 /* Add to end of list */ |
64 | 64 | ||
65 | /* | 65 | /* |
66 | 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL | 66 | 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL |
67 | 4.4BSD CHANGE NLM_F_REPLACE | 67 | 4.4BSD CHANGE NLM_F_REPLACE |
68 | 68 | ||
69 | True CHANGE NLM_F_CREATE|NLM_F_REPLACE | 69 | True CHANGE NLM_F_CREATE|NLM_F_REPLACE |
70 | Append NLM_F_CREATE | 70 | Append NLM_F_CREATE |
71 | Check NLM_F_EXCL | 71 | Check NLM_F_EXCL |
72 | */ | 72 | */ |
73 | 73 | ||
74 | #define NLMSG_ALIGNTO 4 | 74 | #define NLMSG_ALIGNTO 4 |
75 | #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) | 75 | #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) |
76 | #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) | 76 | #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) |
77 | #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) | 77 | #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) |
78 | #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) | 78 | #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) |
79 | #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) | 79 | #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) |
80 | #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ | 80 | #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ |
81 | (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) | 81 | (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) |
82 | #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ | 82 | #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ |
83 | (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ | 83 | (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ |
84 | (nlh)->nlmsg_len <= (len)) | 84 | (nlh)->nlmsg_len <= (len)) |
85 | #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) | 85 | #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) |
86 | 86 | ||
87 | #define NLMSG_NOOP 0x1 /* Nothing. */ | 87 | #define NLMSG_NOOP 0x1 /* Nothing. */ |
88 | #define NLMSG_ERROR 0x2 /* Error */ | 88 | #define NLMSG_ERROR 0x2 /* Error */ |
89 | #define NLMSG_DONE 0x3 /* End of a dump */ | 89 | #define NLMSG_DONE 0x3 /* End of a dump */ |
90 | #define NLMSG_OVERRUN 0x4 /* Data lost */ | 90 | #define NLMSG_OVERRUN 0x4 /* Data lost */ |
91 | 91 | ||
92 | #define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ | 92 | #define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ |
93 | 93 | ||
94 | struct nlmsgerr | 94 | struct nlmsgerr |
95 | { | 95 | { |
96 | int error; | 96 | int error; |
97 | struct nlmsghdr msg; | 97 | struct nlmsghdr msg; |
98 | }; | 98 | }; |
99 | 99 | ||
100 | #define NETLINK_ADD_MEMBERSHIP 1 | 100 | #define NETLINK_ADD_MEMBERSHIP 1 |
101 | #define NETLINK_DROP_MEMBERSHIP 2 | 101 | #define NETLINK_DROP_MEMBERSHIP 2 |
102 | #define NETLINK_PKTINFO 3 | 102 | #define NETLINK_PKTINFO 3 |
103 | 103 | ||
104 | struct nl_pktinfo | 104 | struct nl_pktinfo |
105 | { | 105 | { |
106 | __u32 group; | 106 | __u32 group; |
107 | }; | 107 | }; |
108 | 108 | ||
109 | #define NET_MAJOR 36 /* Major 36 is reserved for networking */ | 109 | #define NET_MAJOR 36 /* Major 36 is reserved for networking */ |
110 | 110 | ||
111 | enum { | 111 | enum { |
112 | NETLINK_UNCONNECTED = 0, | 112 | NETLINK_UNCONNECTED = 0, |
113 | NETLINK_CONNECTED, | 113 | NETLINK_CONNECTED, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | /* | 116 | /* |
117 | * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> | 117 | * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> |
118 | * +---------------------+- - -+- - - - - - - - - -+- - -+ | 118 | * +---------------------+- - -+- - - - - - - - - -+- - -+ |
119 | * | Header | Pad | Payload | Pad | | 119 | * | Header | Pad | Payload | Pad | |
120 | * | (struct nlattr) | ing | | ing | | 120 | * | (struct nlattr) | ing | | ing | |
121 | * +---------------------+- - -+- - - - - - - - - -+- - -+ | 121 | * +---------------------+- - -+- - - - - - - - - -+- - -+ |
122 | * <-------------- nlattr->nla_len --------------> | 122 | * <-------------- nlattr->nla_len --------------> |
123 | */ | 123 | */ |
124 | 124 | ||
125 | struct nlattr | 125 | struct nlattr |
126 | { | 126 | { |
127 | __u16 nla_len; | 127 | __u16 nla_len; |
128 | __u16 nla_type; | 128 | __u16 nla_type; |
129 | }; | 129 | }; |
130 | 130 | ||
131 | #define NLA_ALIGNTO 4 | 131 | #define NLA_ALIGNTO 4 |
132 | #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) | 132 | #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) |
133 | #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) | 133 | #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) |
134 | 134 | ||
135 | #ifdef __KERNEL__ | 135 | #ifdef __KERNEL__ |
136 | 136 | ||
137 | #include <linux/capability.h> | 137 | #include <linux/capability.h> |
138 | #include <linux/skbuff.h> | 138 | #include <linux/skbuff.h> |
139 | 139 | ||
140 | struct netlink_skb_parms | 140 | struct netlink_skb_parms |
141 | { | 141 | { |
142 | struct ucred creds; /* Skb credentials */ | 142 | struct ucred creds; /* Skb credentials */ |
143 | __u32 pid; | 143 | __u32 pid; |
144 | __u32 dst_pid; | ||
145 | __u32 dst_group; | 144 | __u32 dst_group; |
146 | kernel_cap_t eff_cap; | 145 | kernel_cap_t eff_cap; |
147 | __u32 loginuid; /* Login (audit) uid */ | 146 | __u32 loginuid; /* Login (audit) uid */ |
148 | __u32 sid; /* SELinux security id */ | 147 | __u32 sid; /* SELinux security id */ |
149 | }; | 148 | }; |
150 | 149 | ||
151 | #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) | 150 | #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) |
152 | #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) | 151 | #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) |
153 | 152 | ||
154 | 153 | ||
155 | extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module); | 154 | extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module); |
156 | extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); | 155 | extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); |
157 | extern int netlink_has_listeners(struct sock *sk, unsigned int group); | 156 | extern int netlink_has_listeners(struct sock *sk, unsigned int group); |
158 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); | 157 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); |
159 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, | 158 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, |
160 | __u32 group, gfp_t allocation); | 159 | __u32 group, gfp_t allocation); |
161 | extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); | 160 | extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); |
162 | extern int netlink_register_notifier(struct notifier_block *nb); | 161 | extern int netlink_register_notifier(struct notifier_block *nb); |
163 | extern int netlink_unregister_notifier(struct notifier_block *nb); | 162 | extern int netlink_unregister_notifier(struct notifier_block *nb); |
164 | 163 | ||
165 | /* finegrained unicast helpers: */ | 164 | /* finegrained unicast helpers: */ |
166 | struct sock *netlink_getsockbyfilp(struct file *filp); | 165 | struct sock *netlink_getsockbyfilp(struct file *filp); |
167 | int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, | 166 | int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, |
168 | long timeo, struct sock *ssk); | 167 | long timeo, struct sock *ssk); |
169 | void netlink_detachskb(struct sock *sk, struct sk_buff *skb); | 168 | void netlink_detachskb(struct sock *sk, struct sk_buff *skb); |
170 | int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); | 169 | int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); |
171 | 170 | ||
172 | /* | 171 | /* |
173 | * skb should fit one page. This choice is good for headerless malloc. | 172 | * skb should fit one page. This choice is good for headerless malloc. |
174 | */ | 173 | */ |
175 | #define NLMSG_GOODORDER 0 | 174 | #define NLMSG_GOODORDER 0 |
176 | #define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER)) | 175 | #define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER)) |
177 | #define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) | 176 | #define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) |
178 | 177 | ||
179 | 178 | ||
180 | struct netlink_callback | 179 | struct netlink_callback |
181 | { | 180 | { |
182 | struct sk_buff *skb; | 181 | struct sk_buff *skb; |
183 | struct nlmsghdr *nlh; | 182 | struct nlmsghdr *nlh; |
184 | int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); | 183 | int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); |
185 | int (*done)(struct netlink_callback *cb); | 184 | int (*done)(struct netlink_callback *cb); |
186 | int family; | 185 | int family; |
187 | long args[5]; | 186 | long args[5]; |
188 | }; | 187 | }; |
189 | 188 | ||
190 | struct netlink_notify | 189 | struct netlink_notify |
191 | { | 190 | { |
192 | int pid; | 191 | int pid; |
193 | int protocol; | 192 | int protocol; |
194 | }; | 193 | }; |
195 | 194 | ||
196 | static __inline__ struct nlmsghdr * | 195 | static __inline__ struct nlmsghdr * |
197 | __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) | 196 | __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) |
198 | { | 197 | { |
199 | struct nlmsghdr *nlh; | 198 | struct nlmsghdr *nlh; |
200 | int size = NLMSG_LENGTH(len); | 199 | int size = NLMSG_LENGTH(len); |
201 | 200 | ||
202 | nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size)); | 201 | nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size)); |
203 | nlh->nlmsg_type = type; | 202 | nlh->nlmsg_type = type; |
204 | nlh->nlmsg_len = size; | 203 | nlh->nlmsg_len = size; |
205 | nlh->nlmsg_flags = flags; | 204 | nlh->nlmsg_flags = flags; |
206 | nlh->nlmsg_pid = pid; | 205 | nlh->nlmsg_pid = pid; |
207 | nlh->nlmsg_seq = seq; | 206 | nlh->nlmsg_seq = seq; |
208 | memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); | 207 | memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); |
209 | return nlh; | 208 | return nlh; |
210 | } | 209 | } |
211 | 210 | ||
212 | #define NLMSG_NEW(skb, pid, seq, type, len, flags) \ | 211 | #define NLMSG_NEW(skb, pid, seq, type, len, flags) \ |
213 | ({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \ | 212 | ({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \ |
214 | goto nlmsg_failure; \ | 213 | goto nlmsg_failure; \ |
215 | __nlmsg_put(skb, pid, seq, type, len, flags); }) | 214 | __nlmsg_put(skb, pid, seq, type, len, flags); }) |
216 | 215 | ||
217 | #define NLMSG_PUT(skb, pid, seq, type, len) \ | 216 | #define NLMSG_PUT(skb, pid, seq, type, len) \ |
218 | NLMSG_NEW(skb, pid, seq, type, len, 0) | 217 | NLMSG_NEW(skb, pid, seq, type, len, 0) |
219 | 218 | ||
220 | #define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \ | 219 | #define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \ |
221 | NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \ | 220 | NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \ |
222 | (cb)->nlh->nlmsg_seq, type, len, flags) | 221 | (cb)->nlh->nlmsg_seq, type, len, flags) |
223 | 222 | ||
224 | #define NLMSG_END(skb, nlh) \ | 223 | #define NLMSG_END(skb, nlh) \ |
225 | ({ (nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \ | 224 | ({ (nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \ |
226 | (skb)->len; }) | 225 | (skb)->len; }) |
227 | 226 | ||
228 | #define NLMSG_CANCEL(skb, nlh) \ | 227 | #define NLMSG_CANCEL(skb, nlh) \ |
229 | ({ skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \ | 228 | ({ skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \ |
230 | -1; }) | 229 | -1; }) |
231 | 230 | ||
232 | extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 231 | extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
233 | struct nlmsghdr *nlh, | 232 | struct nlmsghdr *nlh, |
234 | int (*dump)(struct sk_buff *skb, struct netlink_callback*), | 233 | int (*dump)(struct sk_buff *skb, struct netlink_callback*), |
235 | int (*done)(struct netlink_callback*)); | 234 | int (*done)(struct netlink_callback*)); |
236 | 235 | ||
237 | 236 | ||
238 | #define NL_NONROOT_RECV 0x1 | 237 | #define NL_NONROOT_RECV 0x1 |
239 | #define NL_NONROOT_SEND 0x2 | 238 | #define NL_NONROOT_SEND 0x2 |
240 | extern void netlink_set_nonroot(int protocol, unsigned flag); | 239 | extern void netlink_set_nonroot(int protocol, unsigned flag); |
241 | 240 | ||
242 | #endif /* __KERNEL__ */ | 241 | #endif /* __KERNEL__ */ |
243 | 242 | ||
244 | #endif /* __LINUX_NETLINK_H */ | 243 | #endif /* __LINUX_NETLINK_H */ |
245 | 244 |
net/decnet/dn_route.c
1 | /* | 1 | /* |
2 | * DECnet An implementation of the DECnet protocol suite for the LINUX | 2 | * DECnet An implementation of the DECnet protocol suite for the LINUX |
3 | * operating system. DECnet is implemented using the BSD Socket | 3 | * operating system. DECnet is implemented using the BSD Socket |
4 | * interface as the means of communication with the user level. | 4 | * interface as the means of communication with the user level. |
5 | * | 5 | * |
6 | * DECnet Routing Functions (Endnode and Router) | 6 | * DECnet Routing Functions (Endnode and Router) |
7 | * | 7 | * |
8 | * Authors: Steve Whitehouse <SteveW@ACM.org> | 8 | * Authors: Steve Whitehouse <SteveW@ACM.org> |
9 | * Eduardo Marcelo Serrat <emserrat@geocities.com> | 9 | * Eduardo Marcelo Serrat <emserrat@geocities.com> |
10 | * | 10 | * |
11 | * Changes: | 11 | * Changes: |
12 | * Steve Whitehouse : Fixes to allow "intra-ethernet" and | 12 | * Steve Whitehouse : Fixes to allow "intra-ethernet" and |
13 | * "return-to-sender" bits on outgoing | 13 | * "return-to-sender" bits on outgoing |
14 | * packets. | 14 | * packets. |
15 | * Steve Whitehouse : Timeouts for cached routes. | 15 | * Steve Whitehouse : Timeouts for cached routes. |
16 | * Steve Whitehouse : Use dst cache for input routes too. | 16 | * Steve Whitehouse : Use dst cache for input routes too. |
17 | * Steve Whitehouse : Fixed error values in dn_send_skb. | 17 | * Steve Whitehouse : Fixed error values in dn_send_skb. |
18 | * Steve Whitehouse : Rework routing functions to better fit | 18 | * Steve Whitehouse : Rework routing functions to better fit |
19 | * DECnet routing design | 19 | * DECnet routing design |
20 | * Alexey Kuznetsov : New SMP locking | 20 | * Alexey Kuznetsov : New SMP locking |
21 | * Steve Whitehouse : More SMP locking changes & dn_cache_dump() | 21 | * Steve Whitehouse : More SMP locking changes & dn_cache_dump() |
22 | * Steve Whitehouse : Prerouting NF hook, now really is prerouting. | 22 | * Steve Whitehouse : Prerouting NF hook, now really is prerouting. |
23 | * Fixed possible skb leak in rtnetlink funcs. | 23 | * Fixed possible skb leak in rtnetlink funcs. |
24 | * Steve Whitehouse : Dave Miller's dynamic hash table sizing and | 24 | * Steve Whitehouse : Dave Miller's dynamic hash table sizing and |
25 | * Alexey Kuznetsov's finer grained locking | 25 | * Alexey Kuznetsov's finer grained locking |
26 | * from ipv4/route.c. | 26 | * from ipv4/route.c. |
27 | * Steve Whitehouse : Routing is now starting to look like a | 27 | * Steve Whitehouse : Routing is now starting to look like a |
28 | * sensible set of code now, mainly due to | 28 | * sensible set of code now, mainly due to |
29 | * my copying the IPv4 routing code. The | 29 | * my copying the IPv4 routing code. The |
30 | * hooks here are modified and will continue | 30 | * hooks here are modified and will continue |
31 | * to evolve for a while. | 31 | * to evolve for a while. |
32 | * Steve Whitehouse : Real SMP at last :-) Also new netfilter | 32 | * Steve Whitehouse : Real SMP at last :-) Also new netfilter |
33 | * stuff. Look out raw sockets your days | 33 | * stuff. Look out raw sockets your days |
34 | * are numbered! | 34 | * are numbered! |
35 | * Steve Whitehouse : Added return-to-sender functions. Added | 35 | * Steve Whitehouse : Added return-to-sender functions. Added |
36 | * backlog congestion level return codes. | 36 | * backlog congestion level return codes. |
37 | * Steve Whitehouse : Fixed bug where routes were set up with | 37 | * Steve Whitehouse : Fixed bug where routes were set up with |
38 | * no ref count on net devices. | 38 | * no ref count on net devices. |
39 | * Steve Whitehouse : RCU for the route cache | 39 | * Steve Whitehouse : RCU for the route cache |
40 | * Steve Whitehouse : Preparations for the flow cache | 40 | * Steve Whitehouse : Preparations for the flow cache |
41 | * Steve Whitehouse : Prepare for nonlinear skbs | 41 | * Steve Whitehouse : Prepare for nonlinear skbs |
42 | */ | 42 | */ |
43 | 43 | ||
44 | /****************************************************************************** | 44 | /****************************************************************************** |
45 | (c) 1995-1998 E.M. Serrat emserrat@geocities.com | 45 | (c) 1995-1998 E.M. Serrat emserrat@geocities.com |
46 | 46 | ||
47 | This program is free software; you can redistribute it and/or modify | 47 | This program is free software; you can redistribute it and/or modify |
48 | it under the terms of the GNU General Public License as published by | 48 | it under the terms of the GNU General Public License as published by |
49 | the Free Software Foundation; either version 2 of the License, or | 49 | the Free Software Foundation; either version 2 of the License, or |
50 | any later version. | 50 | any later version. |
51 | 51 | ||
52 | This program is distributed in the hope that it will be useful, | 52 | This program is distributed in the hope that it will be useful, |
53 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 53 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
54 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 54 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
55 | GNU General Public License for more details. | 55 | GNU General Public License for more details. |
56 | *******************************************************************************/ | 56 | *******************************************************************************/ |
57 | 57 | ||
58 | #include <linux/errno.h> | 58 | #include <linux/errno.h> |
59 | #include <linux/types.h> | 59 | #include <linux/types.h> |
60 | #include <linux/socket.h> | 60 | #include <linux/socket.h> |
61 | #include <linux/in.h> | 61 | #include <linux/in.h> |
62 | #include <linux/kernel.h> | 62 | #include <linux/kernel.h> |
63 | #include <linux/sockios.h> | 63 | #include <linux/sockios.h> |
64 | #include <linux/net.h> | 64 | #include <linux/net.h> |
65 | #include <linux/netdevice.h> | 65 | #include <linux/netdevice.h> |
66 | #include <linux/inet.h> | 66 | #include <linux/inet.h> |
67 | #include <linux/route.h> | 67 | #include <linux/route.h> |
68 | #include <linux/in_route.h> | 68 | #include <linux/in_route.h> |
69 | #include <net/sock.h> | 69 | #include <net/sock.h> |
70 | #include <linux/mm.h> | 70 | #include <linux/mm.h> |
71 | #include <linux/proc_fs.h> | 71 | #include <linux/proc_fs.h> |
72 | #include <linux/seq_file.h> | 72 | #include <linux/seq_file.h> |
73 | #include <linux/init.h> | 73 | #include <linux/init.h> |
74 | #include <linux/rtnetlink.h> | 74 | #include <linux/rtnetlink.h> |
75 | #include <linux/string.h> | 75 | #include <linux/string.h> |
76 | #include <linux/netfilter_decnet.h> | 76 | #include <linux/netfilter_decnet.h> |
77 | #include <linux/rcupdate.h> | 77 | #include <linux/rcupdate.h> |
78 | #include <linux/times.h> | 78 | #include <linux/times.h> |
79 | #include <asm/errno.h> | 79 | #include <asm/errno.h> |
80 | #include <net/neighbour.h> | 80 | #include <net/neighbour.h> |
81 | #include <net/dst.h> | 81 | #include <net/dst.h> |
82 | #include <net/flow.h> | 82 | #include <net/flow.h> |
83 | #include <net/fib_rules.h> | 83 | #include <net/fib_rules.h> |
84 | #include <net/dn.h> | 84 | #include <net/dn.h> |
85 | #include <net/dn_dev.h> | 85 | #include <net/dn_dev.h> |
86 | #include <net/dn_nsp.h> | 86 | #include <net/dn_nsp.h> |
87 | #include <net/dn_route.h> | 87 | #include <net/dn_route.h> |
88 | #include <net/dn_neigh.h> | 88 | #include <net/dn_neigh.h> |
89 | #include <net/dn_fib.h> | 89 | #include <net/dn_fib.h> |
90 | 90 | ||
91 | struct dn_rt_hash_bucket | 91 | struct dn_rt_hash_bucket |
92 | { | 92 | { |
93 | struct dn_route *chain; | 93 | struct dn_route *chain; |
94 | spinlock_t lock; | 94 | spinlock_t lock; |
95 | } __attribute__((__aligned__(8))); | 95 | } __attribute__((__aligned__(8))); |
96 | 96 | ||
97 | extern struct neigh_table dn_neigh_table; | 97 | extern struct neigh_table dn_neigh_table; |
98 | 98 | ||
99 | 99 | ||
100 | static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; | 100 | static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; |
101 | 101 | ||
102 | static const int dn_rt_min_delay = 2 * HZ; | 102 | static const int dn_rt_min_delay = 2 * HZ; |
103 | static const int dn_rt_max_delay = 10 * HZ; | 103 | static const int dn_rt_max_delay = 10 * HZ; |
104 | static const int dn_rt_mtu_expires = 10 * 60 * HZ; | 104 | static const int dn_rt_mtu_expires = 10 * 60 * HZ; |
105 | 105 | ||
106 | static unsigned long dn_rt_deadline; | 106 | static unsigned long dn_rt_deadline; |
107 | 107 | ||
108 | static int dn_dst_gc(void); | 108 | static int dn_dst_gc(void); |
109 | static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); | 109 | static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); |
110 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); | 110 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); |
111 | static void dn_dst_link_failure(struct sk_buff *); | 111 | static void dn_dst_link_failure(struct sk_buff *); |
112 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); | 112 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); |
113 | static int dn_route_input(struct sk_buff *); | 113 | static int dn_route_input(struct sk_buff *); |
114 | static void dn_run_flush(unsigned long dummy); | 114 | static void dn_run_flush(unsigned long dummy); |
115 | 115 | ||
116 | static struct dn_rt_hash_bucket *dn_rt_hash_table; | 116 | static struct dn_rt_hash_bucket *dn_rt_hash_table; |
117 | static unsigned dn_rt_hash_mask; | 117 | static unsigned dn_rt_hash_mask; |
118 | 118 | ||
119 | static struct timer_list dn_route_timer; | 119 | static struct timer_list dn_route_timer; |
120 | static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0); | 120 | static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0); |
121 | int decnet_dst_gc_interval = 2; | 121 | int decnet_dst_gc_interval = 2; |
122 | 122 | ||
123 | static struct dst_ops dn_dst_ops = { | 123 | static struct dst_ops dn_dst_ops = { |
124 | .family = PF_DECnet, | 124 | .family = PF_DECnet, |
125 | .protocol = __constant_htons(ETH_P_DNA_RT), | 125 | .protocol = __constant_htons(ETH_P_DNA_RT), |
126 | .gc_thresh = 128, | 126 | .gc_thresh = 128, |
127 | .gc = dn_dst_gc, | 127 | .gc = dn_dst_gc, |
128 | .check = dn_dst_check, | 128 | .check = dn_dst_check, |
129 | .negative_advice = dn_dst_negative_advice, | 129 | .negative_advice = dn_dst_negative_advice, |
130 | .link_failure = dn_dst_link_failure, | 130 | .link_failure = dn_dst_link_failure, |
131 | .update_pmtu = dn_dst_update_pmtu, | 131 | .update_pmtu = dn_dst_update_pmtu, |
132 | .entry_size = sizeof(struct dn_route), | 132 | .entry_size = sizeof(struct dn_route), |
133 | .entries = ATOMIC_INIT(0), | 133 | .entries = ATOMIC_INIT(0), |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static __inline__ unsigned dn_hash(__le16 src, __le16 dst) | 136 | static __inline__ unsigned dn_hash(__le16 src, __le16 dst) |
137 | { | 137 | { |
138 | __u16 tmp = (__u16 __force)(src ^ dst); | 138 | __u16 tmp = (__u16 __force)(src ^ dst); |
139 | tmp ^= (tmp >> 3); | 139 | tmp ^= (tmp >> 3); |
140 | tmp ^= (tmp >> 5); | 140 | tmp ^= (tmp >> 5); |
141 | tmp ^= (tmp >> 10); | 141 | tmp ^= (tmp >> 10); |
142 | return dn_rt_hash_mask & (unsigned)tmp; | 142 | return dn_rt_hash_mask & (unsigned)tmp; |
143 | } | 143 | } |
144 | 144 | ||
145 | static inline void dnrt_free(struct dn_route *rt) | 145 | static inline void dnrt_free(struct dn_route *rt) |
146 | { | 146 | { |
147 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); | 147 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); |
148 | } | 148 | } |
149 | 149 | ||
150 | static inline void dnrt_drop(struct dn_route *rt) | 150 | static inline void dnrt_drop(struct dn_route *rt) |
151 | { | 151 | { |
152 | dst_release(&rt->u.dst); | 152 | dst_release(&rt->u.dst); |
153 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); | 153 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); |
154 | } | 154 | } |
155 | 155 | ||
156 | static void dn_dst_check_expire(unsigned long dummy) | 156 | static void dn_dst_check_expire(unsigned long dummy) |
157 | { | 157 | { |
158 | int i; | 158 | int i; |
159 | struct dn_route *rt, **rtp; | 159 | struct dn_route *rt, **rtp; |
160 | unsigned long now = jiffies; | 160 | unsigned long now = jiffies; |
161 | unsigned long expire = 120 * HZ; | 161 | unsigned long expire = 120 * HZ; |
162 | 162 | ||
163 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 163 | for(i = 0; i <= dn_rt_hash_mask; i++) { |
164 | rtp = &dn_rt_hash_table[i].chain; | 164 | rtp = &dn_rt_hash_table[i].chain; |
165 | 165 | ||
166 | spin_lock(&dn_rt_hash_table[i].lock); | 166 | spin_lock(&dn_rt_hash_table[i].lock); |
167 | while((rt=*rtp) != NULL) { | 167 | while((rt=*rtp) != NULL) { |
168 | if (atomic_read(&rt->u.dst.__refcnt) || | 168 | if (atomic_read(&rt->u.dst.__refcnt) || |
169 | (now - rt->u.dst.lastuse) < expire) { | 169 | (now - rt->u.dst.lastuse) < expire) { |
170 | rtp = &rt->u.rt_next; | 170 | rtp = &rt->u.rt_next; |
171 | continue; | 171 | continue; |
172 | } | 172 | } |
173 | *rtp = rt->u.rt_next; | 173 | *rtp = rt->u.rt_next; |
174 | rt->u.rt_next = NULL; | 174 | rt->u.rt_next = NULL; |
175 | dnrt_free(rt); | 175 | dnrt_free(rt); |
176 | } | 176 | } |
177 | spin_unlock(&dn_rt_hash_table[i].lock); | 177 | spin_unlock(&dn_rt_hash_table[i].lock); |
178 | 178 | ||
179 | if ((jiffies - now) > 0) | 179 | if ((jiffies - now) > 0) |
180 | break; | 180 | break; |
181 | } | 181 | } |
182 | 182 | ||
183 | mod_timer(&dn_route_timer, now + decnet_dst_gc_interval * HZ); | 183 | mod_timer(&dn_route_timer, now + decnet_dst_gc_interval * HZ); |
184 | } | 184 | } |
185 | 185 | ||
186 | static int dn_dst_gc(void) | 186 | static int dn_dst_gc(void) |
187 | { | 187 | { |
188 | struct dn_route *rt, **rtp; | 188 | struct dn_route *rt, **rtp; |
189 | int i; | 189 | int i; |
190 | unsigned long now = jiffies; | 190 | unsigned long now = jiffies; |
191 | unsigned long expire = 10 * HZ; | 191 | unsigned long expire = 10 * HZ; |
192 | 192 | ||
193 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 193 | for(i = 0; i <= dn_rt_hash_mask; i++) { |
194 | 194 | ||
195 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 195 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
196 | rtp = &dn_rt_hash_table[i].chain; | 196 | rtp = &dn_rt_hash_table[i].chain; |
197 | 197 | ||
198 | while((rt=*rtp) != NULL) { | 198 | while((rt=*rtp) != NULL) { |
199 | if (atomic_read(&rt->u.dst.__refcnt) || | 199 | if (atomic_read(&rt->u.dst.__refcnt) || |
200 | (now - rt->u.dst.lastuse) < expire) { | 200 | (now - rt->u.dst.lastuse) < expire) { |
201 | rtp = &rt->u.rt_next; | 201 | rtp = &rt->u.rt_next; |
202 | continue; | 202 | continue; |
203 | } | 203 | } |
204 | *rtp = rt->u.rt_next; | 204 | *rtp = rt->u.rt_next; |
205 | rt->u.rt_next = NULL; | 205 | rt->u.rt_next = NULL; |
206 | dnrt_drop(rt); | 206 | dnrt_drop(rt); |
207 | break; | 207 | break; |
208 | } | 208 | } |
209 | spin_unlock_bh(&dn_rt_hash_table[i].lock); | 209 | spin_unlock_bh(&dn_rt_hash_table[i].lock); |
210 | } | 210 | } |
211 | 211 | ||
212 | return 0; | 212 | return 0; |
213 | } | 213 | } |
214 | 214 | ||
215 | /* | 215 | /* |
216 | * The decnet standards don't impose a particular minimum mtu, what they | 216 | * The decnet standards don't impose a particular minimum mtu, what they |
217 | * do insist on is that the routing layer accepts a datagram of at least | 217 | * do insist on is that the routing layer accepts a datagram of at least |
218 | * 230 bytes long. Here we have to subtract the routing header length from | 218 | * 230 bytes long. Here we have to subtract the routing header length from |
219 | * 230 to get the minimum acceptable mtu. If there is no neighbour, then we | 219 | * 230 to get the minimum acceptable mtu. If there is no neighbour, then we |
220 | * assume the worst and use a long header size. | 220 | * assume the worst and use a long header size. |
221 | * | 221 | * |
222 | * We update both the mtu and the advertised mss (i.e. the segment size we | 222 | * We update both the mtu and the advertised mss (i.e. the segment size we |
223 | * advertise to the other end). | 223 | * advertise to the other end). |
224 | */ | 224 | */ |
225 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) | 225 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) |
226 | { | 226 | { |
227 | u32 min_mtu = 230; | 227 | u32 min_mtu = 230; |
228 | struct dn_dev *dn = dst->neighbour ? | 228 | struct dn_dev *dn = dst->neighbour ? |
229 | (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL; | 229 | (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL; |
230 | 230 | ||
231 | if (dn && dn->use_long == 0) | 231 | if (dn && dn->use_long == 0) |
232 | min_mtu -= 6; | 232 | min_mtu -= 6; |
233 | else | 233 | else |
234 | min_mtu -= 21; | 234 | min_mtu -= 21; |
235 | 235 | ||
236 | if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) { | 236 | if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) { |
237 | if (!(dst_metric_locked(dst, RTAX_MTU))) { | 237 | if (!(dst_metric_locked(dst, RTAX_MTU))) { |
238 | dst->metrics[RTAX_MTU-1] = mtu; | 238 | dst->metrics[RTAX_MTU-1] = mtu; |
239 | dst_set_expires(dst, dn_rt_mtu_expires); | 239 | dst_set_expires(dst, dn_rt_mtu_expires); |
240 | } | 240 | } |
241 | if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { | 241 | if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { |
242 | u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; | 242 | u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; |
243 | if (dst->metrics[RTAX_ADVMSS-1] > mss) | 243 | if (dst->metrics[RTAX_ADVMSS-1] > mss) |
244 | dst->metrics[RTAX_ADVMSS-1] = mss; | 244 | dst->metrics[RTAX_ADVMSS-1] = mss; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | } | 247 | } |
248 | 248 | ||
249 | /* | 249 | /* |
250 | * When a route has been marked obsolete. (e.g. routing cache flush) | 250 | * When a route has been marked obsolete. (e.g. routing cache flush) |
251 | */ | 251 | */ |
252 | static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie) | 252 | static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie) |
253 | { | 253 | { |
254 | return NULL; | 254 | return NULL; |
255 | } | 255 | } |
256 | 256 | ||
257 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst) | 257 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst) |
258 | { | 258 | { |
259 | dst_release(dst); | 259 | dst_release(dst); |
260 | return NULL; | 260 | return NULL; |
261 | } | 261 | } |
262 | 262 | ||
263 | static void dn_dst_link_failure(struct sk_buff *skb) | 263 | static void dn_dst_link_failure(struct sk_buff *skb) |
264 | { | 264 | { |
265 | return; | 265 | return; |
266 | } | 266 | } |
267 | 267 | ||
268 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | 268 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) |
269 | { | 269 | { |
270 | return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | | 270 | return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | |
271 | (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | | 271 | (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | |
272 | (fl1->mark ^ fl2->mark) | | 272 | (fl1->mark ^ fl2->mark) | |
273 | (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | | 273 | (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | |
274 | (fl1->oif ^ fl2->oif) | | 274 | (fl1->oif ^ fl2->oif) | |
275 | (fl1->iif ^ fl2->iif)) == 0; | 275 | (fl1->iif ^ fl2->iif)) == 0; |
276 | } | 276 | } |
277 | 277 | ||
278 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) | 278 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) |
279 | { | 279 | { |
280 | struct dn_route *rth, **rthp; | 280 | struct dn_route *rth, **rthp; |
281 | unsigned long now = jiffies; | 281 | unsigned long now = jiffies; |
282 | 282 | ||
283 | rthp = &dn_rt_hash_table[hash].chain; | 283 | rthp = &dn_rt_hash_table[hash].chain; |
284 | 284 | ||
285 | spin_lock_bh(&dn_rt_hash_table[hash].lock); | 285 | spin_lock_bh(&dn_rt_hash_table[hash].lock); |
286 | while((rth = *rthp) != NULL) { | 286 | while((rth = *rthp) != NULL) { |
287 | if (compare_keys(&rth->fl, &rt->fl)) { | 287 | if (compare_keys(&rth->fl, &rt->fl)) { |
288 | /* Put it first */ | 288 | /* Put it first */ |
289 | *rthp = rth->u.rt_next; | 289 | *rthp = rth->u.rt_next; |
290 | rcu_assign_pointer(rth->u.rt_next, | 290 | rcu_assign_pointer(rth->u.rt_next, |
291 | dn_rt_hash_table[hash].chain); | 291 | dn_rt_hash_table[hash].chain); |
292 | rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth); | 292 | rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth); |
293 | 293 | ||
294 | rth->u.dst.__use++; | 294 | rth->u.dst.__use++; |
295 | dst_hold(&rth->u.dst); | 295 | dst_hold(&rth->u.dst); |
296 | rth->u.dst.lastuse = now; | 296 | rth->u.dst.lastuse = now; |
297 | spin_unlock_bh(&dn_rt_hash_table[hash].lock); | 297 | spin_unlock_bh(&dn_rt_hash_table[hash].lock); |
298 | 298 | ||
299 | dnrt_drop(rt); | 299 | dnrt_drop(rt); |
300 | *rp = rth; | 300 | *rp = rth; |
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | rthp = &rth->u.rt_next; | 303 | rthp = &rth->u.rt_next; |
304 | } | 304 | } |
305 | 305 | ||
306 | rcu_assign_pointer(rt->u.rt_next, dn_rt_hash_table[hash].chain); | 306 | rcu_assign_pointer(rt->u.rt_next, dn_rt_hash_table[hash].chain); |
307 | rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt); | 307 | rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt); |
308 | 308 | ||
309 | dst_hold(&rt->u.dst); | 309 | dst_hold(&rt->u.dst); |
310 | rt->u.dst.__use++; | 310 | rt->u.dst.__use++; |
311 | rt->u.dst.lastuse = now; | 311 | rt->u.dst.lastuse = now; |
312 | spin_unlock_bh(&dn_rt_hash_table[hash].lock); | 312 | spin_unlock_bh(&dn_rt_hash_table[hash].lock); |
313 | *rp = rt; | 313 | *rp = rt; |
314 | return 0; | 314 | return 0; |
315 | } | 315 | } |
316 | 316 | ||
317 | void dn_run_flush(unsigned long dummy) | 317 | void dn_run_flush(unsigned long dummy) |
318 | { | 318 | { |
319 | int i; | 319 | int i; |
320 | struct dn_route *rt, *next; | 320 | struct dn_route *rt, *next; |
321 | 321 | ||
322 | for(i = 0; i < dn_rt_hash_mask; i++) { | 322 | for(i = 0; i < dn_rt_hash_mask; i++) { |
323 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 323 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
324 | 324 | ||
325 | if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL) | 325 | if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL) |
326 | goto nothing_to_declare; | 326 | goto nothing_to_declare; |
327 | 327 | ||
328 | for(; rt; rt=next) { | 328 | for(; rt; rt=next) { |
329 | next = rt->u.rt_next; | 329 | next = rt->u.rt_next; |
330 | rt->u.rt_next = NULL; | 330 | rt->u.rt_next = NULL; |
331 | dst_free((struct dst_entry *)rt); | 331 | dst_free((struct dst_entry *)rt); |
332 | } | 332 | } |
333 | 333 | ||
334 | nothing_to_declare: | 334 | nothing_to_declare: |
335 | spin_unlock_bh(&dn_rt_hash_table[i].lock); | 335 | spin_unlock_bh(&dn_rt_hash_table[i].lock); |
336 | } | 336 | } |
337 | } | 337 | } |
338 | 338 | ||
339 | static DEFINE_SPINLOCK(dn_rt_flush_lock); | 339 | static DEFINE_SPINLOCK(dn_rt_flush_lock); |
340 | 340 | ||
341 | void dn_rt_cache_flush(int delay) | 341 | void dn_rt_cache_flush(int delay) |
342 | { | 342 | { |
343 | unsigned long now = jiffies; | 343 | unsigned long now = jiffies; |
344 | int user_mode = !in_interrupt(); | 344 | int user_mode = !in_interrupt(); |
345 | 345 | ||
346 | if (delay < 0) | 346 | if (delay < 0) |
347 | delay = dn_rt_min_delay; | 347 | delay = dn_rt_min_delay; |
348 | 348 | ||
349 | spin_lock_bh(&dn_rt_flush_lock); | 349 | spin_lock_bh(&dn_rt_flush_lock); |
350 | 350 | ||
351 | if (del_timer(&dn_rt_flush_timer) && delay > 0 && dn_rt_deadline) { | 351 | if (del_timer(&dn_rt_flush_timer) && delay > 0 && dn_rt_deadline) { |
352 | long tmo = (long)(dn_rt_deadline - now); | 352 | long tmo = (long)(dn_rt_deadline - now); |
353 | 353 | ||
354 | if (user_mode && tmo < dn_rt_max_delay - dn_rt_min_delay) | 354 | if (user_mode && tmo < dn_rt_max_delay - dn_rt_min_delay) |
355 | tmo = 0; | 355 | tmo = 0; |
356 | 356 | ||
357 | if (delay > tmo) | 357 | if (delay > tmo) |
358 | delay = tmo; | 358 | delay = tmo; |
359 | } | 359 | } |
360 | 360 | ||
361 | if (delay <= 0) { | 361 | if (delay <= 0) { |
362 | spin_unlock_bh(&dn_rt_flush_lock); | 362 | spin_unlock_bh(&dn_rt_flush_lock); |
363 | dn_run_flush(0); | 363 | dn_run_flush(0); |
364 | return; | 364 | return; |
365 | } | 365 | } |
366 | 366 | ||
367 | if (dn_rt_deadline == 0) | 367 | if (dn_rt_deadline == 0) |
368 | dn_rt_deadline = now + dn_rt_max_delay; | 368 | dn_rt_deadline = now + dn_rt_max_delay; |
369 | 369 | ||
370 | dn_rt_flush_timer.expires = now + delay; | 370 | dn_rt_flush_timer.expires = now + delay; |
371 | add_timer(&dn_rt_flush_timer); | 371 | add_timer(&dn_rt_flush_timer); |
372 | spin_unlock_bh(&dn_rt_flush_lock); | 372 | spin_unlock_bh(&dn_rt_flush_lock); |
373 | } | 373 | } |
374 | 374 | ||
375 | /** | 375 | /** |
376 | * dn_return_short - Return a short packet to its sender | 376 | * dn_return_short - Return a short packet to its sender |
377 | * @skb: The packet to return | 377 | * @skb: The packet to return |
378 | * | 378 | * |
379 | */ | 379 | */ |
380 | static int dn_return_short(struct sk_buff *skb) | 380 | static int dn_return_short(struct sk_buff *skb) |
381 | { | 381 | { |
382 | struct dn_skb_cb *cb; | 382 | struct dn_skb_cb *cb; |
383 | unsigned char *ptr; | 383 | unsigned char *ptr; |
384 | __le16 *src; | 384 | __le16 *src; |
385 | __le16 *dst; | 385 | __le16 *dst; |
386 | __le16 tmp; | 386 | __le16 tmp; |
387 | 387 | ||
388 | /* Add back headers */ | 388 | /* Add back headers */ |
389 | skb_push(skb, skb->data - skb->nh.raw); | 389 | skb_push(skb, skb->data - skb->nh.raw); |
390 | 390 | ||
391 | if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL) | 391 | if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL) |
392 | return NET_RX_DROP; | 392 | return NET_RX_DROP; |
393 | 393 | ||
394 | cb = DN_SKB_CB(skb); | 394 | cb = DN_SKB_CB(skb); |
395 | /* Skip packet length and point to flags */ | 395 | /* Skip packet length and point to flags */ |
396 | ptr = skb->data + 2; | 396 | ptr = skb->data + 2; |
397 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; | 397 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; |
398 | 398 | ||
399 | dst = (__le16 *)ptr; | 399 | dst = (__le16 *)ptr; |
400 | ptr += 2; | 400 | ptr += 2; |
401 | src = (__le16 *)ptr; | 401 | src = (__le16 *)ptr; |
402 | ptr += 2; | 402 | ptr += 2; |
403 | *ptr = 0; /* Zero hop count */ | 403 | *ptr = 0; /* Zero hop count */ |
404 | 404 | ||
405 | /* Swap source and destination */ | 405 | /* Swap source and destination */ |
406 | tmp = *src; | 406 | tmp = *src; |
407 | *src = *dst; | 407 | *src = *dst; |
408 | *dst = tmp; | 408 | *dst = tmp; |
409 | 409 | ||
410 | skb->pkt_type = PACKET_OUTGOING; | 410 | skb->pkt_type = PACKET_OUTGOING; |
411 | dn_rt_finish_output(skb, NULL, NULL); | 411 | dn_rt_finish_output(skb, NULL, NULL); |
412 | return NET_RX_SUCCESS; | 412 | return NET_RX_SUCCESS; |
413 | } | 413 | } |
414 | 414 | ||
415 | /** | 415 | /** |
416 | * dn_return_long - Return a long packet to its sender | 416 | * dn_return_long - Return a long packet to its sender |
417 | * @skb: The long format packet to return | 417 | * @skb: The long format packet to return |
418 | * | 418 | * |
419 | */ | 419 | */ |
420 | static int dn_return_long(struct sk_buff *skb) | 420 | static int dn_return_long(struct sk_buff *skb) |
421 | { | 421 | { |
422 | struct dn_skb_cb *cb; | 422 | struct dn_skb_cb *cb; |
423 | unsigned char *ptr; | 423 | unsigned char *ptr; |
424 | unsigned char *src_addr, *dst_addr; | 424 | unsigned char *src_addr, *dst_addr; |
425 | unsigned char tmp[ETH_ALEN]; | 425 | unsigned char tmp[ETH_ALEN]; |
426 | 426 | ||
427 | /* Add back all headers */ | 427 | /* Add back all headers */ |
428 | skb_push(skb, skb->data - skb->nh.raw); | 428 | skb_push(skb, skb->data - skb->nh.raw); |
429 | 429 | ||
430 | if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL) | 430 | if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL) |
431 | return NET_RX_DROP; | 431 | return NET_RX_DROP; |
432 | 432 | ||
433 | cb = DN_SKB_CB(skb); | 433 | cb = DN_SKB_CB(skb); |
434 | /* Ignore packet length and point to flags */ | 434 | /* Ignore packet length and point to flags */ |
435 | ptr = skb->data + 2; | 435 | ptr = skb->data + 2; |
436 | 436 | ||
437 | /* Skip padding */ | 437 | /* Skip padding */ |
438 | if (*ptr & DN_RT_F_PF) { | 438 | if (*ptr & DN_RT_F_PF) { |
439 | char padlen = (*ptr & ~DN_RT_F_PF); | 439 | char padlen = (*ptr & ~DN_RT_F_PF); |
440 | ptr += padlen; | 440 | ptr += padlen; |
441 | } | 441 | } |
442 | 442 | ||
443 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; | 443 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; |
444 | ptr += 2; | 444 | ptr += 2; |
445 | dst_addr = ptr; | 445 | dst_addr = ptr; |
446 | ptr += 8; | 446 | ptr += 8; |
447 | src_addr = ptr; | 447 | src_addr = ptr; |
448 | ptr += 6; | 448 | ptr += 6; |
449 | *ptr = 0; /* Zero hop count */ | 449 | *ptr = 0; /* Zero hop count */ |
450 | 450 | ||
451 | /* Swap source and destination */ | 451 | /* Swap source and destination */ |
452 | memcpy(tmp, src_addr, ETH_ALEN); | 452 | memcpy(tmp, src_addr, ETH_ALEN); |
453 | memcpy(src_addr, dst_addr, ETH_ALEN); | 453 | memcpy(src_addr, dst_addr, ETH_ALEN); |
454 | memcpy(dst_addr, tmp, ETH_ALEN); | 454 | memcpy(dst_addr, tmp, ETH_ALEN); |
455 | 455 | ||
456 | skb->pkt_type = PACKET_OUTGOING; | 456 | skb->pkt_type = PACKET_OUTGOING; |
457 | dn_rt_finish_output(skb, dst_addr, src_addr); | 457 | dn_rt_finish_output(skb, dst_addr, src_addr); |
458 | return NET_RX_SUCCESS; | 458 | return NET_RX_SUCCESS; |
459 | } | 459 | } |
460 | 460 | ||
461 | /** | 461 | /** |
462 | * dn_route_rx_packet - Try and find a route for an incoming packet | 462 | * dn_route_rx_packet - Try and find a route for an incoming packet |
463 | * @skb: The packet to find a route for | 463 | * @skb: The packet to find a route for |
464 | * | 464 | * |
465 | * Returns: result of input function if route is found, error code otherwise | 465 | * Returns: result of input function if route is found, error code otherwise |
466 | */ | 466 | */ |
467 | static int dn_route_rx_packet(struct sk_buff *skb) | 467 | static int dn_route_rx_packet(struct sk_buff *skb) |
468 | { | 468 | { |
469 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 469 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
470 | int err; | 470 | int err; |
471 | 471 | ||
472 | if ((err = dn_route_input(skb)) == 0) | 472 | if ((err = dn_route_input(skb)) == 0) |
473 | return dst_input(skb); | 473 | return dst_input(skb); |
474 | 474 | ||
475 | if (decnet_debug_level & 4) { | 475 | if (decnet_debug_level & 4) { |
476 | char *devname = skb->dev ? skb->dev->name : "???"; | 476 | char *devname = skb->dev ? skb->dev->name : "???"; |
477 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 477 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
478 | printk(KERN_DEBUG | 478 | printk(KERN_DEBUG |
479 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", | 479 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", |
480 | (int)cb->rt_flags, devname, skb->len, | 480 | (int)cb->rt_flags, devname, skb->len, |
481 | dn_ntohs(cb->src), dn_ntohs(cb->dst), | 481 | dn_ntohs(cb->src), dn_ntohs(cb->dst), |
482 | err, skb->pkt_type); | 482 | err, skb->pkt_type); |
483 | } | 483 | } |
484 | 484 | ||
485 | if ((skb->pkt_type == PACKET_HOST) && (cb->rt_flags & DN_RT_F_RQR)) { | 485 | if ((skb->pkt_type == PACKET_HOST) && (cb->rt_flags & DN_RT_F_RQR)) { |
486 | switch(cb->rt_flags & DN_RT_PKT_MSK) { | 486 | switch(cb->rt_flags & DN_RT_PKT_MSK) { |
487 | case DN_RT_PKT_SHORT: | 487 | case DN_RT_PKT_SHORT: |
488 | return dn_return_short(skb); | 488 | return dn_return_short(skb); |
489 | case DN_RT_PKT_LONG: | 489 | case DN_RT_PKT_LONG: |
490 | return dn_return_long(skb); | 490 | return dn_return_long(skb); |
491 | } | 491 | } |
492 | } | 492 | } |
493 | 493 | ||
494 | kfree_skb(skb); | 494 | kfree_skb(skb); |
495 | return NET_RX_DROP; | 495 | return NET_RX_DROP; |
496 | } | 496 | } |
497 | 497 | ||
498 | static int dn_route_rx_long(struct sk_buff *skb) | 498 | static int dn_route_rx_long(struct sk_buff *skb) |
499 | { | 499 | { |
500 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 500 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
501 | unsigned char *ptr = skb->data; | 501 | unsigned char *ptr = skb->data; |
502 | 502 | ||
503 | if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */ | 503 | if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */ |
504 | goto drop_it; | 504 | goto drop_it; |
505 | 505 | ||
506 | skb_pull(skb, 20); | 506 | skb_pull(skb, 20); |
507 | skb->h.raw = skb->data; | 507 | skb->h.raw = skb->data; |
508 | 508 | ||
509 | /* Destination info */ | 509 | /* Destination info */ |
510 | ptr += 2; | 510 | ptr += 2; |
511 | cb->dst = dn_eth2dn(ptr); | 511 | cb->dst = dn_eth2dn(ptr); |
512 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) | 512 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) |
513 | goto drop_it; | 513 | goto drop_it; |
514 | ptr += 6; | 514 | ptr += 6; |
515 | 515 | ||
516 | 516 | ||
517 | /* Source info */ | 517 | /* Source info */ |
518 | ptr += 2; | 518 | ptr += 2; |
519 | cb->src = dn_eth2dn(ptr); | 519 | cb->src = dn_eth2dn(ptr); |
520 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) | 520 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) |
521 | goto drop_it; | 521 | goto drop_it; |
522 | ptr += 6; | 522 | ptr += 6; |
523 | /* Other junk */ | 523 | /* Other junk */ |
524 | ptr++; | 524 | ptr++; |
525 | cb->hops = *ptr++; /* Visit Count */ | 525 | cb->hops = *ptr++; /* Visit Count */ |
526 | 526 | ||
527 | return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet); | 527 | return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet); |
528 | 528 | ||
529 | drop_it: | 529 | drop_it: |
530 | kfree_skb(skb); | 530 | kfree_skb(skb); |
531 | return NET_RX_DROP; | 531 | return NET_RX_DROP; |
532 | } | 532 | } |
533 | 533 | ||
534 | 534 | ||
535 | 535 | ||
536 | static int dn_route_rx_short(struct sk_buff *skb) | 536 | static int dn_route_rx_short(struct sk_buff *skb) |
537 | { | 537 | { |
538 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 538 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
539 | unsigned char *ptr = skb->data; | 539 | unsigned char *ptr = skb->data; |
540 | 540 | ||
541 | if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */ | 541 | if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */ |
542 | goto drop_it; | 542 | goto drop_it; |
543 | 543 | ||
544 | skb_pull(skb, 5); | 544 | skb_pull(skb, 5); |
545 | skb->h.raw = skb->data; | 545 | skb->h.raw = skb->data; |
546 | 546 | ||
547 | cb->dst = *(__le16 *)ptr; | 547 | cb->dst = *(__le16 *)ptr; |
548 | ptr += 2; | 548 | ptr += 2; |
549 | cb->src = *(__le16 *)ptr; | 549 | cb->src = *(__le16 *)ptr; |
550 | ptr += 2; | 550 | ptr += 2; |
551 | cb->hops = *ptr & 0x3f; | 551 | cb->hops = *ptr & 0x3f; |
552 | 552 | ||
553 | return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet); | 553 | return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet); |
554 | 554 | ||
555 | drop_it: | 555 | drop_it: |
556 | kfree_skb(skb); | 556 | kfree_skb(skb); |
557 | return NET_RX_DROP; | 557 | return NET_RX_DROP; |
558 | } | 558 | } |
559 | 559 | ||
560 | static int dn_route_discard(struct sk_buff *skb) | 560 | static int dn_route_discard(struct sk_buff *skb) |
561 | { | 561 | { |
562 | /* | 562 | /* |
563 | * I know we drop the packet here, but thats considered success in | 563 | * I know we drop the packet here, but thats considered success in |
564 | * this case | 564 | * this case |
565 | */ | 565 | */ |
566 | kfree_skb(skb); | 566 | kfree_skb(skb); |
567 | return NET_RX_SUCCESS; | 567 | return NET_RX_SUCCESS; |
568 | } | 568 | } |
569 | 569 | ||
570 | static int dn_route_ptp_hello(struct sk_buff *skb) | 570 | static int dn_route_ptp_hello(struct sk_buff *skb) |
571 | { | 571 | { |
572 | dn_dev_hello(skb); | 572 | dn_dev_hello(skb); |
573 | dn_neigh_pointopoint_hello(skb); | 573 | dn_neigh_pointopoint_hello(skb); |
574 | return NET_RX_SUCCESS; | 574 | return NET_RX_SUCCESS; |
575 | } | 575 | } |
576 | 576 | ||
577 | int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | 577 | int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) |
578 | { | 578 | { |
579 | struct dn_skb_cb *cb; | 579 | struct dn_skb_cb *cb; |
580 | unsigned char flags = 0; | 580 | unsigned char flags = 0; |
581 | __u16 len = dn_ntohs(*(__le16 *)skb->data); | 581 | __u16 len = dn_ntohs(*(__le16 *)skb->data); |
582 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; | 582 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; |
583 | unsigned char padlen = 0; | 583 | unsigned char padlen = 0; |
584 | 584 | ||
585 | if (dn == NULL) | 585 | if (dn == NULL) |
586 | goto dump_it; | 586 | goto dump_it; |
587 | 587 | ||
588 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) | 588 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) |
589 | goto out; | 589 | goto out; |
590 | 590 | ||
591 | if (!pskb_may_pull(skb, 3)) | 591 | if (!pskb_may_pull(skb, 3)) |
592 | goto dump_it; | 592 | goto dump_it; |
593 | 593 | ||
594 | skb_pull(skb, 2); | 594 | skb_pull(skb, 2); |
595 | 595 | ||
596 | if (len > skb->len) | 596 | if (len > skb->len) |
597 | goto dump_it; | 597 | goto dump_it; |
598 | 598 | ||
599 | skb_trim(skb, len); | 599 | skb_trim(skb, len); |
600 | 600 | ||
601 | flags = *skb->data; | 601 | flags = *skb->data; |
602 | 602 | ||
603 | cb = DN_SKB_CB(skb); | 603 | cb = DN_SKB_CB(skb); |
604 | cb->stamp = jiffies; | 604 | cb->stamp = jiffies; |
605 | cb->iif = dev->ifindex; | 605 | cb->iif = dev->ifindex; |
606 | 606 | ||
607 | /* | 607 | /* |
608 | * If we have padding, remove it. | 608 | * If we have padding, remove it. |
609 | */ | 609 | */ |
610 | if (flags & DN_RT_F_PF) { | 610 | if (flags & DN_RT_F_PF) { |
611 | padlen = flags & ~DN_RT_F_PF; | 611 | padlen = flags & ~DN_RT_F_PF; |
612 | if (!pskb_may_pull(skb, padlen + 1)) | 612 | if (!pskb_may_pull(skb, padlen + 1)) |
613 | goto dump_it; | 613 | goto dump_it; |
614 | skb_pull(skb, padlen); | 614 | skb_pull(skb, padlen); |
615 | flags = *skb->data; | 615 | flags = *skb->data; |
616 | } | 616 | } |
617 | 617 | ||
618 | skb->nh.raw = skb->data; | 618 | skb->nh.raw = skb->data; |
619 | 619 | ||
620 | /* | 620 | /* |
621 | * Weed out future version DECnet | 621 | * Weed out future version DECnet |
622 | */ | 622 | */ |
623 | if (flags & DN_RT_F_VER) | 623 | if (flags & DN_RT_F_VER) |
624 | goto dump_it; | 624 | goto dump_it; |
625 | 625 | ||
626 | cb->rt_flags = flags; | 626 | cb->rt_flags = flags; |
627 | 627 | ||
628 | if (decnet_debug_level & 1) | 628 | if (decnet_debug_level & 1) |
629 | printk(KERN_DEBUG | 629 | printk(KERN_DEBUG |
630 | "dn_route_rcv: got 0x%02x from %s [%d %d %d]\n", | 630 | "dn_route_rcv: got 0x%02x from %s [%d %d %d]\n", |
631 | (int)flags, (dev) ? dev->name : "???", len, skb->len, | 631 | (int)flags, (dev) ? dev->name : "???", len, skb->len, |
632 | padlen); | 632 | padlen); |
633 | 633 | ||
634 | if (flags & DN_RT_PKT_CNTL) { | 634 | if (flags & DN_RT_PKT_CNTL) { |
635 | if (unlikely(skb_linearize(skb))) | 635 | if (unlikely(skb_linearize(skb))) |
636 | goto dump_it; | 636 | goto dump_it; |
637 | 637 | ||
638 | switch(flags & DN_RT_CNTL_MSK) { | 638 | switch(flags & DN_RT_CNTL_MSK) { |
639 | case DN_RT_PKT_INIT: | 639 | case DN_RT_PKT_INIT: |
640 | dn_dev_init_pkt(skb); | 640 | dn_dev_init_pkt(skb); |
641 | break; | 641 | break; |
642 | case DN_RT_PKT_VERI: | 642 | case DN_RT_PKT_VERI: |
643 | dn_dev_veri_pkt(skb); | 643 | dn_dev_veri_pkt(skb); |
644 | break; | 644 | break; |
645 | } | 645 | } |
646 | 646 | ||
647 | if (dn->parms.state != DN_DEV_S_RU) | 647 | if (dn->parms.state != DN_DEV_S_RU) |
648 | goto dump_it; | 648 | goto dump_it; |
649 | 649 | ||
650 | switch(flags & DN_RT_CNTL_MSK) { | 650 | switch(flags & DN_RT_CNTL_MSK) { |
651 | case DN_RT_PKT_HELO: | 651 | case DN_RT_PKT_HELO: |
652 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_route_ptp_hello); | 652 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_route_ptp_hello); |
653 | 653 | ||
654 | case DN_RT_PKT_L1RT: | 654 | case DN_RT_PKT_L1RT: |
655 | case DN_RT_PKT_L2RT: | 655 | case DN_RT_PKT_L2RT: |
656 | return NF_HOOK(PF_DECnet, NF_DN_ROUTE, skb, skb->dev, NULL, dn_route_discard); | 656 | return NF_HOOK(PF_DECnet, NF_DN_ROUTE, skb, skb->dev, NULL, dn_route_discard); |
657 | case DN_RT_PKT_ERTH: | 657 | case DN_RT_PKT_ERTH: |
658 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_router_hello); | 658 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_router_hello); |
659 | 659 | ||
660 | case DN_RT_PKT_EEDH: | 660 | case DN_RT_PKT_EEDH: |
661 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_endnode_hello); | 661 | return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_endnode_hello); |
662 | } | 662 | } |
663 | } else { | 663 | } else { |
664 | if (dn->parms.state != DN_DEV_S_RU) | 664 | if (dn->parms.state != DN_DEV_S_RU) |
665 | goto dump_it; | 665 | goto dump_it; |
666 | 666 | ||
667 | skb_pull(skb, 1); /* Pull flags */ | 667 | skb_pull(skb, 1); /* Pull flags */ |
668 | 668 | ||
669 | switch(flags & DN_RT_PKT_MSK) { | 669 | switch(flags & DN_RT_PKT_MSK) { |
670 | case DN_RT_PKT_LONG: | 670 | case DN_RT_PKT_LONG: |
671 | return dn_route_rx_long(skb); | 671 | return dn_route_rx_long(skb); |
672 | case DN_RT_PKT_SHORT: | 672 | case DN_RT_PKT_SHORT: |
673 | return dn_route_rx_short(skb); | 673 | return dn_route_rx_short(skb); |
674 | } | 674 | } |
675 | } | 675 | } |
676 | 676 | ||
677 | dump_it: | 677 | dump_it: |
678 | kfree_skb(skb); | 678 | kfree_skb(skb); |
679 | out: | 679 | out: |
680 | return NET_RX_DROP; | 680 | return NET_RX_DROP; |
681 | } | 681 | } |
682 | 682 | ||
683 | static int dn_output(struct sk_buff *skb) | 683 | static int dn_output(struct sk_buff *skb) |
684 | { | 684 | { |
685 | struct dst_entry *dst = skb->dst; | 685 | struct dst_entry *dst = skb->dst; |
686 | struct dn_route *rt = (struct dn_route *)dst; | 686 | struct dn_route *rt = (struct dn_route *)dst; |
687 | struct net_device *dev = dst->dev; | 687 | struct net_device *dev = dst->dev; |
688 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 688 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
689 | struct neighbour *neigh; | 689 | struct neighbour *neigh; |
690 | 690 | ||
691 | int err = -EINVAL; | 691 | int err = -EINVAL; |
692 | 692 | ||
693 | if ((neigh = dst->neighbour) == NULL) | 693 | if ((neigh = dst->neighbour) == NULL) |
694 | goto error; | 694 | goto error; |
695 | 695 | ||
696 | skb->dev = dev; | 696 | skb->dev = dev; |
697 | 697 | ||
698 | cb->src = rt->rt_saddr; | 698 | cb->src = rt->rt_saddr; |
699 | cb->dst = rt->rt_daddr; | 699 | cb->dst = rt->rt_daddr; |
700 | 700 | ||
701 | /* | 701 | /* |
702 | * Always set the Intra-Ethernet bit on all outgoing packets | 702 | * Always set the Intra-Ethernet bit on all outgoing packets |
703 | * originated on this node. Only valid flag from upper layers | 703 | * originated on this node. Only valid flag from upper layers |
704 | * is return-to-sender-requested. Set hop count to 0 too. | 704 | * is return-to-sender-requested. Set hop count to 0 too. |
705 | */ | 705 | */ |
706 | cb->rt_flags &= ~DN_RT_F_RQR; | 706 | cb->rt_flags &= ~DN_RT_F_RQR; |
707 | cb->rt_flags |= DN_RT_F_IE; | 707 | cb->rt_flags |= DN_RT_F_IE; |
708 | cb->hops = 0; | 708 | cb->hops = 0; |
709 | 709 | ||
710 | return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output); | 710 | return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output); |
711 | 711 | ||
712 | error: | 712 | error: |
713 | if (net_ratelimit()) | 713 | if (net_ratelimit()) |
714 | printk(KERN_DEBUG "dn_output: This should not happen\n"); | 714 | printk(KERN_DEBUG "dn_output: This should not happen\n"); |
715 | 715 | ||
716 | kfree_skb(skb); | 716 | kfree_skb(skb); |
717 | 717 | ||
718 | return err; | 718 | return err; |
719 | } | 719 | } |
720 | 720 | ||
721 | static int dn_forward(struct sk_buff *skb) | 721 | static int dn_forward(struct sk_buff *skb) |
722 | { | 722 | { |
723 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 723 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
724 | struct dst_entry *dst = skb->dst; | 724 | struct dst_entry *dst = skb->dst; |
725 | struct dn_dev *dn_db = dst->dev->dn_ptr; | 725 | struct dn_dev *dn_db = dst->dev->dn_ptr; |
726 | struct dn_route *rt; | 726 | struct dn_route *rt; |
727 | struct neighbour *neigh = dst->neighbour; | 727 | struct neighbour *neigh = dst->neighbour; |
728 | int header_len; | 728 | int header_len; |
729 | #ifdef CONFIG_NETFILTER | 729 | #ifdef CONFIG_NETFILTER |
730 | struct net_device *dev = skb->dev; | 730 | struct net_device *dev = skb->dev; |
731 | #endif | 731 | #endif |
732 | 732 | ||
733 | if (skb->pkt_type != PACKET_HOST) | 733 | if (skb->pkt_type != PACKET_HOST) |
734 | goto drop; | 734 | goto drop; |
735 | 735 | ||
736 | /* Ensure that we have enough space for headers */ | 736 | /* Ensure that we have enough space for headers */ |
737 | rt = (struct dn_route *)skb->dst; | 737 | rt = (struct dn_route *)skb->dst; |
738 | header_len = dn_db->use_long ? 21 : 6; | 738 | header_len = dn_db->use_long ? 21 : 6; |
739 | if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len)) | 739 | if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len)) |
740 | goto drop; | 740 | goto drop; |
741 | 741 | ||
742 | /* | 742 | /* |
743 | * Hop count exceeded. | 743 | * Hop count exceeded. |
744 | */ | 744 | */ |
745 | if (++cb->hops > 30) | 745 | if (++cb->hops > 30) |
746 | goto drop; | 746 | goto drop; |
747 | 747 | ||
748 | skb->dev = rt->u.dst.dev; | 748 | skb->dev = rt->u.dst.dev; |
749 | 749 | ||
750 | /* | 750 | /* |
751 | * If packet goes out same interface it came in on, then set | 751 | * If packet goes out same interface it came in on, then set |
752 | * the Intra-Ethernet bit. This has no effect for short | 752 | * the Intra-Ethernet bit. This has no effect for short |
753 | * packets, so we don't need to test for them here. | 753 | * packets, so we don't need to test for them here. |
754 | */ | 754 | */ |
755 | cb->rt_flags &= ~DN_RT_F_IE; | 755 | cb->rt_flags &= ~DN_RT_F_IE; |
756 | if (rt->rt_flags & RTCF_DOREDIRECT) | 756 | if (rt->rt_flags & RTCF_DOREDIRECT) |
757 | cb->rt_flags |= DN_RT_F_IE; | 757 | cb->rt_flags |= DN_RT_F_IE; |
758 | 758 | ||
759 | return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output); | 759 | return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output); |
760 | 760 | ||
761 | drop: | 761 | drop: |
762 | kfree_skb(skb); | 762 | kfree_skb(skb); |
763 | return NET_RX_DROP; | 763 | return NET_RX_DROP; |
764 | } | 764 | } |
765 | 765 | ||
766 | /* | 766 | /* |
767 | * Drop packet. This is used for endnodes and for | 767 | * Drop packet. This is used for endnodes and for |
768 | * when we should not be forwarding packets from | 768 | * when we should not be forwarding packets from |
769 | * this dest. | 769 | * this dest. |
770 | */ | 770 | */ |
771 | static int dn_blackhole(struct sk_buff *skb) | 771 | static int dn_blackhole(struct sk_buff *skb) |
772 | { | 772 | { |
773 | kfree_skb(skb); | 773 | kfree_skb(skb); |
774 | return NET_RX_DROP; | 774 | return NET_RX_DROP; |
775 | } | 775 | } |
776 | 776 | ||
777 | /* | 777 | /* |
778 | * Used to catch bugs. This should never normally get | 778 | * Used to catch bugs. This should never normally get |
779 | * called. | 779 | * called. |
780 | */ | 780 | */ |
781 | static int dn_rt_bug(struct sk_buff *skb) | 781 | static int dn_rt_bug(struct sk_buff *skb) |
782 | { | 782 | { |
783 | if (net_ratelimit()) { | 783 | if (net_ratelimit()) { |
784 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 784 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
785 | 785 | ||
786 | printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n", | 786 | printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n", |
787 | dn_ntohs(cb->src), dn_ntohs(cb->dst)); | 787 | dn_ntohs(cb->src), dn_ntohs(cb->dst)); |
788 | } | 788 | } |
789 | 789 | ||
790 | kfree_skb(skb); | 790 | kfree_skb(skb); |
791 | 791 | ||
792 | return NET_RX_BAD; | 792 | return NET_RX_BAD; |
793 | } | 793 | } |
794 | 794 | ||
795 | static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) | 795 | static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) |
796 | { | 796 | { |
797 | struct dn_fib_info *fi = res->fi; | 797 | struct dn_fib_info *fi = res->fi; |
798 | struct net_device *dev = rt->u.dst.dev; | 798 | struct net_device *dev = rt->u.dst.dev; |
799 | struct neighbour *n; | 799 | struct neighbour *n; |
800 | unsigned mss; | 800 | unsigned mss; |
801 | 801 | ||
802 | if (fi) { | 802 | if (fi) { |
803 | if (DN_FIB_RES_GW(*res) && | 803 | if (DN_FIB_RES_GW(*res) && |
804 | DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | 804 | DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) |
805 | rt->rt_gateway = DN_FIB_RES_GW(*res); | 805 | rt->rt_gateway = DN_FIB_RES_GW(*res); |
806 | memcpy(rt->u.dst.metrics, fi->fib_metrics, | 806 | memcpy(rt->u.dst.metrics, fi->fib_metrics, |
807 | sizeof(rt->u.dst.metrics)); | 807 | sizeof(rt->u.dst.metrics)); |
808 | } | 808 | } |
809 | rt->rt_type = res->type; | 809 | rt->rt_type = res->type; |
810 | 810 | ||
811 | if (dev != NULL && rt->u.dst.neighbour == NULL) { | 811 | if (dev != NULL && rt->u.dst.neighbour == NULL) { |
812 | n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev); | 812 | n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev); |
813 | if (IS_ERR(n)) | 813 | if (IS_ERR(n)) |
814 | return PTR_ERR(n); | 814 | return PTR_ERR(n); |
815 | rt->u.dst.neighbour = n; | 815 | rt->u.dst.neighbour = n; |
816 | } | 816 | } |
817 | 817 | ||
818 | if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || | 818 | if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || |
819 | rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu) | 819 | rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu) |
820 | rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu; | 820 | rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu; |
821 | mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst)); | 821 | mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst)); |
822 | if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 || | 822 | if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 || |
823 | rt->u.dst.metrics[RTAX_ADVMSS-1] > mss) | 823 | rt->u.dst.metrics[RTAX_ADVMSS-1] > mss) |
824 | rt->u.dst.metrics[RTAX_ADVMSS-1] = mss; | 824 | rt->u.dst.metrics[RTAX_ADVMSS-1] = mss; |
825 | return 0; | 825 | return 0; |
826 | } | 826 | } |
827 | 827 | ||
828 | static inline int dn_match_addr(__le16 addr1, __le16 addr2) | 828 | static inline int dn_match_addr(__le16 addr1, __le16 addr2) |
829 | { | 829 | { |
830 | __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); | 830 | __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); |
831 | int match = 16; | 831 | int match = 16; |
832 | while(tmp) { | 832 | while(tmp) { |
833 | tmp >>= 1; | 833 | tmp >>= 1; |
834 | match--; | 834 | match--; |
835 | } | 835 | } |
836 | return match; | 836 | return match; |
837 | } | 837 | } |
838 | 838 | ||
839 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) | 839 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) |
840 | { | 840 | { |
841 | __le16 saddr = 0; | 841 | __le16 saddr = 0; |
842 | struct dn_dev *dn_db = dev->dn_ptr; | 842 | struct dn_dev *dn_db = dev->dn_ptr; |
843 | struct dn_ifaddr *ifa; | 843 | struct dn_ifaddr *ifa; |
844 | int best_match = 0; | 844 | int best_match = 0; |
845 | int ret; | 845 | int ret; |
846 | 846 | ||
847 | read_lock(&dev_base_lock); | 847 | read_lock(&dev_base_lock); |
848 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | 848 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { |
849 | if (ifa->ifa_scope > scope) | 849 | if (ifa->ifa_scope > scope) |
850 | continue; | 850 | continue; |
851 | if (!daddr) { | 851 | if (!daddr) { |
852 | saddr = ifa->ifa_local; | 852 | saddr = ifa->ifa_local; |
853 | break; | 853 | break; |
854 | } | 854 | } |
855 | ret = dn_match_addr(daddr, ifa->ifa_local); | 855 | ret = dn_match_addr(daddr, ifa->ifa_local); |
856 | if (ret > best_match) | 856 | if (ret > best_match) |
857 | saddr = ifa->ifa_local; | 857 | saddr = ifa->ifa_local; |
858 | if (best_match == 0) | 858 | if (best_match == 0) |
859 | saddr = ifa->ifa_local; | 859 | saddr = ifa->ifa_local; |
860 | } | 860 | } |
861 | read_unlock(&dev_base_lock); | 861 | read_unlock(&dev_base_lock); |
862 | 862 | ||
863 | return saddr; | 863 | return saddr; |
864 | } | 864 | } |
865 | 865 | ||
866 | static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res) | 866 | static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res) |
867 | { | 867 | { |
868 | return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope); | 868 | return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope); |
869 | } | 869 | } |
870 | 870 | ||
871 | static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res) | 871 | static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res) |
872 | { | 872 | { |
873 | __le16 mask = dnet_make_mask(res->prefixlen); | 873 | __le16 mask = dnet_make_mask(res->prefixlen); |
874 | return (daddr&~mask)|res->fi->fib_nh->nh_gw; | 874 | return (daddr&~mask)|res->fi->fib_nh->nh_gw; |
875 | } | 875 | } |
876 | 876 | ||
877 | static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard) | 877 | static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard) |
878 | { | 878 | { |
879 | struct flowi fl = { .nl_u = { .dn_u = | 879 | struct flowi fl = { .nl_u = { .dn_u = |
880 | { .daddr = oldflp->fld_dst, | 880 | { .daddr = oldflp->fld_dst, |
881 | .saddr = oldflp->fld_src, | 881 | .saddr = oldflp->fld_src, |
882 | .scope = RT_SCOPE_UNIVERSE, | 882 | .scope = RT_SCOPE_UNIVERSE, |
883 | } }, | 883 | } }, |
884 | .mark = oldflp->mark, | 884 | .mark = oldflp->mark, |
885 | .iif = loopback_dev.ifindex, | 885 | .iif = loopback_dev.ifindex, |
886 | .oif = oldflp->oif }; | 886 | .oif = oldflp->oif }; |
887 | struct dn_route *rt = NULL; | 887 | struct dn_route *rt = NULL; |
888 | struct net_device *dev_out = NULL; | 888 | struct net_device *dev_out = NULL; |
889 | struct neighbour *neigh = NULL; | 889 | struct neighbour *neigh = NULL; |
890 | unsigned hash; | 890 | unsigned hash; |
891 | unsigned flags = 0; | 891 | unsigned flags = 0; |
892 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST }; | 892 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST }; |
893 | int err; | 893 | int err; |
894 | int free_res = 0; | 894 | int free_res = 0; |
895 | __le16 gateway = 0; | 895 | __le16 gateway = 0; |
896 | 896 | ||
897 | if (decnet_debug_level & 16) | 897 | if (decnet_debug_level & 16) |
898 | printk(KERN_DEBUG | 898 | printk(KERN_DEBUG |
899 | "dn_route_output_slow: dst=%04x src=%04x mark=%d" | 899 | "dn_route_output_slow: dst=%04x src=%04x mark=%d" |
900 | " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), | 900 | " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), |
901 | dn_ntohs(oldflp->fld_src), | 901 | dn_ntohs(oldflp->fld_src), |
902 | oldflp->mark, loopback_dev.ifindex, oldflp->oif); | 902 | oldflp->mark, loopback_dev.ifindex, oldflp->oif); |
903 | 903 | ||
904 | /* If we have an output interface, verify its a DECnet device */ | 904 | /* If we have an output interface, verify its a DECnet device */ |
905 | if (oldflp->oif) { | 905 | if (oldflp->oif) { |
906 | dev_out = dev_get_by_index(oldflp->oif); | 906 | dev_out = dev_get_by_index(oldflp->oif); |
907 | err = -ENODEV; | 907 | err = -ENODEV; |
908 | if (dev_out && dev_out->dn_ptr == NULL) { | 908 | if (dev_out && dev_out->dn_ptr == NULL) { |
909 | dev_put(dev_out); | 909 | dev_put(dev_out); |
910 | dev_out = NULL; | 910 | dev_out = NULL; |
911 | } | 911 | } |
912 | if (dev_out == NULL) | 912 | if (dev_out == NULL) |
913 | goto out; | 913 | goto out; |
914 | } | 914 | } |
915 | 915 | ||
916 | /* If we have a source address, verify that its a local address */ | 916 | /* If we have a source address, verify that its a local address */ |
917 | if (oldflp->fld_src) { | 917 | if (oldflp->fld_src) { |
918 | err = -EADDRNOTAVAIL; | 918 | err = -EADDRNOTAVAIL; |
919 | 919 | ||
920 | if (dev_out) { | 920 | if (dev_out) { |
921 | if (dn_dev_islocal(dev_out, oldflp->fld_src)) | 921 | if (dn_dev_islocal(dev_out, oldflp->fld_src)) |
922 | goto source_ok; | 922 | goto source_ok; |
923 | dev_put(dev_out); | 923 | dev_put(dev_out); |
924 | goto out; | 924 | goto out; |
925 | } | 925 | } |
926 | read_lock(&dev_base_lock); | 926 | read_lock(&dev_base_lock); |
927 | for(dev_out = dev_base; dev_out; dev_out = dev_out->next) { | 927 | for(dev_out = dev_base; dev_out; dev_out = dev_out->next) { |
928 | if (!dev_out->dn_ptr) | 928 | if (!dev_out->dn_ptr) |
929 | continue; | 929 | continue; |
930 | if (!dn_dev_islocal(dev_out, oldflp->fld_src)) | 930 | if (!dn_dev_islocal(dev_out, oldflp->fld_src)) |
931 | continue; | 931 | continue; |
932 | if ((dev_out->flags & IFF_LOOPBACK) && | 932 | if ((dev_out->flags & IFF_LOOPBACK) && |
933 | oldflp->fld_dst && | 933 | oldflp->fld_dst && |
934 | !dn_dev_islocal(dev_out, oldflp->fld_dst)) | 934 | !dn_dev_islocal(dev_out, oldflp->fld_dst)) |
935 | continue; | 935 | continue; |
936 | break; | 936 | break; |
937 | } | 937 | } |
938 | read_unlock(&dev_base_lock); | 938 | read_unlock(&dev_base_lock); |
939 | if (dev_out == NULL) | 939 | if (dev_out == NULL) |
940 | goto out; | 940 | goto out; |
941 | dev_hold(dev_out); | 941 | dev_hold(dev_out); |
942 | source_ok: | 942 | source_ok: |
943 | ; | 943 | ; |
944 | } | 944 | } |
945 | 945 | ||
946 | /* No destination? Assume its local */ | 946 | /* No destination? Assume its local */ |
947 | if (!fl.fld_dst) { | 947 | if (!fl.fld_dst) { |
948 | fl.fld_dst = fl.fld_src; | 948 | fl.fld_dst = fl.fld_src; |
949 | 949 | ||
950 | err = -EADDRNOTAVAIL; | 950 | err = -EADDRNOTAVAIL; |
951 | if (dev_out) | 951 | if (dev_out) |
952 | dev_put(dev_out); | 952 | dev_put(dev_out); |
953 | dev_out = &loopback_dev; | 953 | dev_out = &loopback_dev; |
954 | dev_hold(dev_out); | 954 | dev_hold(dev_out); |
955 | if (!fl.fld_dst) { | 955 | if (!fl.fld_dst) { |
956 | fl.fld_dst = | 956 | fl.fld_dst = |
957 | fl.fld_src = dnet_select_source(dev_out, 0, | 957 | fl.fld_src = dnet_select_source(dev_out, 0, |
958 | RT_SCOPE_HOST); | 958 | RT_SCOPE_HOST); |
959 | if (!fl.fld_dst) | 959 | if (!fl.fld_dst) |
960 | goto out; | 960 | goto out; |
961 | } | 961 | } |
962 | fl.oif = loopback_dev.ifindex; | 962 | fl.oif = loopback_dev.ifindex; |
963 | res.type = RTN_LOCAL; | 963 | res.type = RTN_LOCAL; |
964 | goto make_route; | 964 | goto make_route; |
965 | } | 965 | } |
966 | 966 | ||
967 | if (decnet_debug_level & 16) | 967 | if (decnet_debug_level & 16) |
968 | printk(KERN_DEBUG | 968 | printk(KERN_DEBUG |
969 | "dn_route_output_slow: initial checks complete." | 969 | "dn_route_output_slow: initial checks complete." |
970 | " dst=%o4x src=%04x oif=%d try_hard=%d\n", | 970 | " dst=%o4x src=%04x oif=%d try_hard=%d\n", |
971 | dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src), | 971 | dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src), |
972 | fl.oif, try_hard); | 972 | fl.oif, try_hard); |
973 | 973 | ||
974 | /* | 974 | /* |
975 | * N.B. If the kernel is compiled without router support then | 975 | * N.B. If the kernel is compiled without router support then |
976 | * dn_fib_lookup() will evaluate to non-zero so this if () block | 976 | * dn_fib_lookup() will evaluate to non-zero so this if () block |
977 | * will always be executed. | 977 | * will always be executed. |
978 | */ | 978 | */ |
979 | err = -ESRCH; | 979 | err = -ESRCH; |
980 | if (try_hard || (err = dn_fib_lookup(&fl, &res)) != 0) { | 980 | if (try_hard || (err = dn_fib_lookup(&fl, &res)) != 0) { |
981 | struct dn_dev *dn_db; | 981 | struct dn_dev *dn_db; |
982 | if (err != -ESRCH) | 982 | if (err != -ESRCH) |
983 | goto out; | 983 | goto out; |
984 | /* | 984 | /* |
985 | * Here the fallback is basically the standard algorithm for | 985 | * Here the fallback is basically the standard algorithm for |
986 | * routing in endnodes which is described in the DECnet routing | 986 | * routing in endnodes which is described in the DECnet routing |
987 | * docs | 987 | * docs |
988 | * | 988 | * |
989 | * If we are not trying hard, look in neighbour cache. | 989 | * If we are not trying hard, look in neighbour cache. |
990 | * The result is tested to ensure that if a specific output | 990 | * The result is tested to ensure that if a specific output |
991 | * device/source address was requested, then we honour that | 991 | * device/source address was requested, then we honour that |
992 | * here | 992 | * here |
993 | */ | 993 | */ |
994 | if (!try_hard) { | 994 | if (!try_hard) { |
995 | neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst); | 995 | neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst); |
996 | if (neigh) { | 996 | if (neigh) { |
997 | if ((oldflp->oif && | 997 | if ((oldflp->oif && |
998 | (neigh->dev->ifindex != oldflp->oif)) || | 998 | (neigh->dev->ifindex != oldflp->oif)) || |
999 | (oldflp->fld_src && | 999 | (oldflp->fld_src && |
1000 | (!dn_dev_islocal(neigh->dev, | 1000 | (!dn_dev_islocal(neigh->dev, |
1001 | oldflp->fld_src)))) { | 1001 | oldflp->fld_src)))) { |
1002 | neigh_release(neigh); | 1002 | neigh_release(neigh); |
1003 | neigh = NULL; | 1003 | neigh = NULL; |
1004 | } else { | 1004 | } else { |
1005 | if (dev_out) | 1005 | if (dev_out) |
1006 | dev_put(dev_out); | 1006 | dev_put(dev_out); |
1007 | if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { | 1007 | if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { |
1008 | dev_out = &loopback_dev; | 1008 | dev_out = &loopback_dev; |
1009 | res.type = RTN_LOCAL; | 1009 | res.type = RTN_LOCAL; |
1010 | } else { | 1010 | } else { |
1011 | dev_out = neigh->dev; | 1011 | dev_out = neigh->dev; |
1012 | } | 1012 | } |
1013 | dev_hold(dev_out); | 1013 | dev_hold(dev_out); |
1014 | goto select_source; | 1014 | goto select_source; |
1015 | } | 1015 | } |
1016 | } | 1016 | } |
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | /* Not there? Perhaps its a local address */ | 1019 | /* Not there? Perhaps its a local address */ |
1020 | if (dev_out == NULL) | 1020 | if (dev_out == NULL) |
1021 | dev_out = dn_dev_get_default(); | 1021 | dev_out = dn_dev_get_default(); |
1022 | err = -ENODEV; | 1022 | err = -ENODEV; |
1023 | if (dev_out == NULL) | 1023 | if (dev_out == NULL) |
1024 | goto out; | 1024 | goto out; |
1025 | dn_db = dev_out->dn_ptr; | 1025 | dn_db = dev_out->dn_ptr; |
1026 | /* Possible improvement - check all devices for local addr */ | 1026 | /* Possible improvement - check all devices for local addr */ |
1027 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { | 1027 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { |
1028 | dev_put(dev_out); | 1028 | dev_put(dev_out); |
1029 | dev_out = &loopback_dev; | 1029 | dev_out = &loopback_dev; |
1030 | dev_hold(dev_out); | 1030 | dev_hold(dev_out); |
1031 | res.type = RTN_LOCAL; | 1031 | res.type = RTN_LOCAL; |
1032 | goto select_source; | 1032 | goto select_source; |
1033 | } | 1033 | } |
1034 | /* Not local either.... try sending it to the default router */ | 1034 | /* Not local either.... try sending it to the default router */ |
1035 | neigh = neigh_clone(dn_db->router); | 1035 | neigh = neigh_clone(dn_db->router); |
1036 | BUG_ON(neigh && neigh->dev != dev_out); | 1036 | BUG_ON(neigh && neigh->dev != dev_out); |
1037 | 1037 | ||
1038 | /* Ok then, we assume its directly connected and move on */ | 1038 | /* Ok then, we assume its directly connected and move on */ |
1039 | select_source: | 1039 | select_source: |
1040 | if (neigh) | 1040 | if (neigh) |
1041 | gateway = ((struct dn_neigh *)neigh)->addr; | 1041 | gateway = ((struct dn_neigh *)neigh)->addr; |
1042 | if (gateway == 0) | 1042 | if (gateway == 0) |
1043 | gateway = fl.fld_dst; | 1043 | gateway = fl.fld_dst; |
1044 | if (fl.fld_src == 0) { | 1044 | if (fl.fld_src == 0) { |
1045 | fl.fld_src = dnet_select_source(dev_out, gateway, | 1045 | fl.fld_src = dnet_select_source(dev_out, gateway, |
1046 | res.type == RTN_LOCAL ? | 1046 | res.type == RTN_LOCAL ? |
1047 | RT_SCOPE_HOST : | 1047 | RT_SCOPE_HOST : |
1048 | RT_SCOPE_LINK); | 1048 | RT_SCOPE_LINK); |
1049 | if (fl.fld_src == 0 && res.type != RTN_LOCAL) | 1049 | if (fl.fld_src == 0 && res.type != RTN_LOCAL) |
1050 | goto e_addr; | 1050 | goto e_addr; |
1051 | } | 1051 | } |
1052 | fl.oif = dev_out->ifindex; | 1052 | fl.oif = dev_out->ifindex; |
1053 | goto make_route; | 1053 | goto make_route; |
1054 | } | 1054 | } |
1055 | free_res = 1; | 1055 | free_res = 1; |
1056 | 1056 | ||
1057 | if (res.type == RTN_NAT) | 1057 | if (res.type == RTN_NAT) |
1058 | goto e_inval; | 1058 | goto e_inval; |
1059 | 1059 | ||
1060 | if (res.type == RTN_LOCAL) { | 1060 | if (res.type == RTN_LOCAL) { |
1061 | if (!fl.fld_src) | 1061 | if (!fl.fld_src) |
1062 | fl.fld_src = fl.fld_dst; | 1062 | fl.fld_src = fl.fld_dst; |
1063 | if (dev_out) | 1063 | if (dev_out) |
1064 | dev_put(dev_out); | 1064 | dev_put(dev_out); |
1065 | dev_out = &loopback_dev; | 1065 | dev_out = &loopback_dev; |
1066 | dev_hold(dev_out); | 1066 | dev_hold(dev_out); |
1067 | fl.oif = dev_out->ifindex; | 1067 | fl.oif = dev_out->ifindex; |
1068 | if (res.fi) | 1068 | if (res.fi) |
1069 | dn_fib_info_put(res.fi); | 1069 | dn_fib_info_put(res.fi); |
1070 | res.fi = NULL; | 1070 | res.fi = NULL; |
1071 | goto make_route; | 1071 | goto make_route; |
1072 | } | 1072 | } |
1073 | 1073 | ||
1074 | if (res.fi->fib_nhs > 1 && fl.oif == 0) | 1074 | if (res.fi->fib_nhs > 1 && fl.oif == 0) |
1075 | dn_fib_select_multipath(&fl, &res); | 1075 | dn_fib_select_multipath(&fl, &res); |
1076 | 1076 | ||
1077 | /* | 1077 | /* |
1078 | * We could add some logic to deal with default routes here and | 1078 | * We could add some logic to deal with default routes here and |
1079 | * get rid of some of the special casing above. | 1079 | * get rid of some of the special casing above. |
1080 | */ | 1080 | */ |
1081 | 1081 | ||
1082 | if (!fl.fld_src) | 1082 | if (!fl.fld_src) |
1083 | fl.fld_src = DN_FIB_RES_PREFSRC(res); | 1083 | fl.fld_src = DN_FIB_RES_PREFSRC(res); |
1084 | 1084 | ||
1085 | if (dev_out) | 1085 | if (dev_out) |
1086 | dev_put(dev_out); | 1086 | dev_put(dev_out); |
1087 | dev_out = DN_FIB_RES_DEV(res); | 1087 | dev_out = DN_FIB_RES_DEV(res); |
1088 | dev_hold(dev_out); | 1088 | dev_hold(dev_out); |
1089 | fl.oif = dev_out->ifindex; | 1089 | fl.oif = dev_out->ifindex; |
1090 | gateway = DN_FIB_RES_GW(res); | 1090 | gateway = DN_FIB_RES_GW(res); |
1091 | 1091 | ||
1092 | make_route: | 1092 | make_route: |
1093 | if (dev_out->flags & IFF_LOOPBACK) | 1093 | if (dev_out->flags & IFF_LOOPBACK) |
1094 | flags |= RTCF_LOCAL; | 1094 | flags |= RTCF_LOCAL; |
1095 | 1095 | ||
1096 | rt = dst_alloc(&dn_dst_ops); | 1096 | rt = dst_alloc(&dn_dst_ops); |
1097 | if (rt == NULL) | 1097 | if (rt == NULL) |
1098 | goto e_nobufs; | 1098 | goto e_nobufs; |
1099 | 1099 | ||
1100 | atomic_set(&rt->u.dst.__refcnt, 1); | 1100 | atomic_set(&rt->u.dst.__refcnt, 1); |
1101 | rt->u.dst.flags = DST_HOST; | 1101 | rt->u.dst.flags = DST_HOST; |
1102 | 1102 | ||
1103 | rt->fl.fld_src = oldflp->fld_src; | 1103 | rt->fl.fld_src = oldflp->fld_src; |
1104 | rt->fl.fld_dst = oldflp->fld_dst; | 1104 | rt->fl.fld_dst = oldflp->fld_dst; |
1105 | rt->fl.oif = oldflp->oif; | 1105 | rt->fl.oif = oldflp->oif; |
1106 | rt->fl.iif = 0; | 1106 | rt->fl.iif = 0; |
1107 | rt->fl.mark = oldflp->mark; | 1107 | rt->fl.mark = oldflp->mark; |
1108 | 1108 | ||
1109 | rt->rt_saddr = fl.fld_src; | 1109 | rt->rt_saddr = fl.fld_src; |
1110 | rt->rt_daddr = fl.fld_dst; | 1110 | rt->rt_daddr = fl.fld_dst; |
1111 | rt->rt_gateway = gateway ? gateway : fl.fld_dst; | 1111 | rt->rt_gateway = gateway ? gateway : fl.fld_dst; |
1112 | rt->rt_local_src = fl.fld_src; | 1112 | rt->rt_local_src = fl.fld_src; |
1113 | 1113 | ||
1114 | rt->rt_dst_map = fl.fld_dst; | 1114 | rt->rt_dst_map = fl.fld_dst; |
1115 | rt->rt_src_map = fl.fld_src; | 1115 | rt->rt_src_map = fl.fld_src; |
1116 | 1116 | ||
1117 | rt->u.dst.dev = dev_out; | 1117 | rt->u.dst.dev = dev_out; |
1118 | dev_hold(dev_out); | 1118 | dev_hold(dev_out); |
1119 | rt->u.dst.neighbour = neigh; | 1119 | rt->u.dst.neighbour = neigh; |
1120 | neigh = NULL; | 1120 | neigh = NULL; |
1121 | 1121 | ||
1122 | rt->u.dst.lastuse = jiffies; | 1122 | rt->u.dst.lastuse = jiffies; |
1123 | rt->u.dst.output = dn_output; | 1123 | rt->u.dst.output = dn_output; |
1124 | rt->u.dst.input = dn_rt_bug; | 1124 | rt->u.dst.input = dn_rt_bug; |
1125 | rt->rt_flags = flags; | 1125 | rt->rt_flags = flags; |
1126 | if (flags & RTCF_LOCAL) | 1126 | if (flags & RTCF_LOCAL) |
1127 | rt->u.dst.input = dn_nsp_rx; | 1127 | rt->u.dst.input = dn_nsp_rx; |
1128 | 1128 | ||
1129 | err = dn_rt_set_next_hop(rt, &res); | 1129 | err = dn_rt_set_next_hop(rt, &res); |
1130 | if (err) | 1130 | if (err) |
1131 | goto e_neighbour; | 1131 | goto e_neighbour; |
1132 | 1132 | ||
1133 | hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); | 1133 | hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); |
1134 | dn_insert_route(rt, hash, (struct dn_route **)pprt); | 1134 | dn_insert_route(rt, hash, (struct dn_route **)pprt); |
1135 | 1135 | ||
1136 | done: | 1136 | done: |
1137 | if (neigh) | 1137 | if (neigh) |
1138 | neigh_release(neigh); | 1138 | neigh_release(neigh); |
1139 | if (free_res) | 1139 | if (free_res) |
1140 | dn_fib_res_put(&res); | 1140 | dn_fib_res_put(&res); |
1141 | if (dev_out) | 1141 | if (dev_out) |
1142 | dev_put(dev_out); | 1142 | dev_put(dev_out); |
1143 | out: | 1143 | out: |
1144 | return err; | 1144 | return err; |
1145 | 1145 | ||
1146 | e_addr: | 1146 | e_addr: |
1147 | err = -EADDRNOTAVAIL; | 1147 | err = -EADDRNOTAVAIL; |
1148 | goto done; | 1148 | goto done; |
1149 | e_inval: | 1149 | e_inval: |
1150 | err = -EINVAL; | 1150 | err = -EINVAL; |
1151 | goto done; | 1151 | goto done; |
1152 | e_nobufs: | 1152 | e_nobufs: |
1153 | err = -ENOBUFS; | 1153 | err = -ENOBUFS; |
1154 | goto done; | 1154 | goto done; |
1155 | e_neighbour: | 1155 | e_neighbour: |
1156 | dst_free(&rt->u.dst); | 1156 | dst_free(&rt->u.dst); |
1157 | goto e_nobufs; | 1157 | goto e_nobufs; |
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | 1160 | ||
1161 | /* | 1161 | /* |
1162 | * N.B. The flags may be moved into the flowi at some future stage. | 1162 | * N.B. The flags may be moved into the flowi at some future stage. |
1163 | */ | 1163 | */ |
1164 | static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *flp, int flags) | 1164 | static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *flp, int flags) |
1165 | { | 1165 | { |
1166 | unsigned hash = dn_hash(flp->fld_src, flp->fld_dst); | 1166 | unsigned hash = dn_hash(flp->fld_src, flp->fld_dst); |
1167 | struct dn_route *rt = NULL; | 1167 | struct dn_route *rt = NULL; |
1168 | 1168 | ||
1169 | if (!(flags & MSG_TRYHARD)) { | 1169 | if (!(flags & MSG_TRYHARD)) { |
1170 | rcu_read_lock_bh(); | 1170 | rcu_read_lock_bh(); |
1171 | for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt; | 1171 | for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt; |
1172 | rt = rcu_dereference(rt->u.rt_next)) { | 1172 | rt = rcu_dereference(rt->u.rt_next)) { |
1173 | if ((flp->fld_dst == rt->fl.fld_dst) && | 1173 | if ((flp->fld_dst == rt->fl.fld_dst) && |
1174 | (flp->fld_src == rt->fl.fld_src) && | 1174 | (flp->fld_src == rt->fl.fld_src) && |
1175 | (flp->mark == rt->fl.mark) && | 1175 | (flp->mark == rt->fl.mark) && |
1176 | (rt->fl.iif == 0) && | 1176 | (rt->fl.iif == 0) && |
1177 | (rt->fl.oif == flp->oif)) { | 1177 | (rt->fl.oif == flp->oif)) { |
1178 | rt->u.dst.lastuse = jiffies; | 1178 | rt->u.dst.lastuse = jiffies; |
1179 | dst_hold(&rt->u.dst); | 1179 | dst_hold(&rt->u.dst); |
1180 | rt->u.dst.__use++; | 1180 | rt->u.dst.__use++; |
1181 | rcu_read_unlock_bh(); | 1181 | rcu_read_unlock_bh(); |
1182 | *pprt = &rt->u.dst; | 1182 | *pprt = &rt->u.dst; |
1183 | return 0; | 1183 | return 0; |
1184 | } | 1184 | } |
1185 | } | 1185 | } |
1186 | rcu_read_unlock_bh(); | 1186 | rcu_read_unlock_bh(); |
1187 | } | 1187 | } |
1188 | 1188 | ||
1189 | return dn_route_output_slow(pprt, flp, flags); | 1189 | return dn_route_output_slow(pprt, flp, flags); |
1190 | } | 1190 | } |
1191 | 1191 | ||
1192 | static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int flags) | 1192 | static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int flags) |
1193 | { | 1193 | { |
1194 | int err; | 1194 | int err; |
1195 | 1195 | ||
1196 | err = __dn_route_output_key(pprt, flp, flags); | 1196 | err = __dn_route_output_key(pprt, flp, flags); |
1197 | if (err == 0 && flp->proto) { | 1197 | if (err == 0 && flp->proto) { |
1198 | err = xfrm_lookup(pprt, flp, NULL, 0); | 1198 | err = xfrm_lookup(pprt, flp, NULL, 0); |
1199 | } | 1199 | } |
1200 | return err; | 1200 | return err; |
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock *sk, int flags) | 1203 | int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock *sk, int flags) |
1204 | { | 1204 | { |
1205 | int err; | 1205 | int err; |
1206 | 1206 | ||
1207 | err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); | 1207 | err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); |
1208 | if (err == 0 && fl->proto) { | 1208 | if (err == 0 && fl->proto) { |
1209 | err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT)); | 1209 | err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT)); |
1210 | } | 1210 | } |
1211 | return err; | 1211 | return err; |
1212 | } | 1212 | } |
1213 | 1213 | ||
1214 | static int dn_route_input_slow(struct sk_buff *skb) | 1214 | static int dn_route_input_slow(struct sk_buff *skb) |
1215 | { | 1215 | { |
1216 | struct dn_route *rt = NULL; | 1216 | struct dn_route *rt = NULL; |
1217 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 1217 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
1218 | struct net_device *in_dev = skb->dev; | 1218 | struct net_device *in_dev = skb->dev; |
1219 | struct net_device *out_dev = NULL; | 1219 | struct net_device *out_dev = NULL; |
1220 | struct dn_dev *dn_db; | 1220 | struct dn_dev *dn_db; |
1221 | struct neighbour *neigh = NULL; | 1221 | struct neighbour *neigh = NULL; |
1222 | unsigned hash; | 1222 | unsigned hash; |
1223 | int flags = 0; | 1223 | int flags = 0; |
1224 | __le16 gateway = 0; | 1224 | __le16 gateway = 0; |
1225 | __le16 local_src = 0; | 1225 | __le16 local_src = 0; |
1226 | struct flowi fl = { .nl_u = { .dn_u = | 1226 | struct flowi fl = { .nl_u = { .dn_u = |
1227 | { .daddr = cb->dst, | 1227 | { .daddr = cb->dst, |
1228 | .saddr = cb->src, | 1228 | .saddr = cb->src, |
1229 | .scope = RT_SCOPE_UNIVERSE, | 1229 | .scope = RT_SCOPE_UNIVERSE, |
1230 | } }, | 1230 | } }, |
1231 | .mark = skb->mark, | 1231 | .mark = skb->mark, |
1232 | .iif = skb->dev->ifindex }; | 1232 | .iif = skb->dev->ifindex }; |
1233 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE }; | 1233 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE }; |
1234 | int err = -EINVAL; | 1234 | int err = -EINVAL; |
1235 | int free_res = 0; | 1235 | int free_res = 0; |
1236 | 1236 | ||
1237 | dev_hold(in_dev); | 1237 | dev_hold(in_dev); |
1238 | 1238 | ||
1239 | if ((dn_db = in_dev->dn_ptr) == NULL) | 1239 | if ((dn_db = in_dev->dn_ptr) == NULL) |
1240 | goto out; | 1240 | goto out; |
1241 | 1241 | ||
1242 | /* Zero source addresses are not allowed */ | 1242 | /* Zero source addresses are not allowed */ |
1243 | if (fl.fld_src == 0) | 1243 | if (fl.fld_src == 0) |
1244 | goto out; | 1244 | goto out; |
1245 | 1245 | ||
1246 | /* | 1246 | /* |
1247 | * In this case we've just received a packet from a source | 1247 | * In this case we've just received a packet from a source |
1248 | * outside ourselves pretending to come from us. We don't | 1248 | * outside ourselves pretending to come from us. We don't |
1249 | * allow it any further to prevent routing loops, spoofing and | 1249 | * allow it any further to prevent routing loops, spoofing and |
1250 | * other nasties. Loopback packets already have the dst attached | 1250 | * other nasties. Loopback packets already have the dst attached |
1251 | * so this only affects packets which have originated elsewhere. | 1251 | * so this only affects packets which have originated elsewhere. |
1252 | */ | 1252 | */ |
1253 | err = -ENOTUNIQ; | 1253 | err = -ENOTUNIQ; |
1254 | if (dn_dev_islocal(in_dev, cb->src)) | 1254 | if (dn_dev_islocal(in_dev, cb->src)) |
1255 | goto out; | 1255 | goto out; |
1256 | 1256 | ||
1257 | err = dn_fib_lookup(&fl, &res); | 1257 | err = dn_fib_lookup(&fl, &res); |
1258 | if (err) { | 1258 | if (err) { |
1259 | if (err != -ESRCH) | 1259 | if (err != -ESRCH) |
1260 | goto out; | 1260 | goto out; |
1261 | /* | 1261 | /* |
1262 | * Is the destination us ? | 1262 | * Is the destination us ? |
1263 | */ | 1263 | */ |
1264 | if (!dn_dev_islocal(in_dev, cb->dst)) | 1264 | if (!dn_dev_islocal(in_dev, cb->dst)) |
1265 | goto e_inval; | 1265 | goto e_inval; |
1266 | 1266 | ||
1267 | res.type = RTN_LOCAL; | 1267 | res.type = RTN_LOCAL; |
1268 | } else { | 1268 | } else { |
1269 | __le16 src_map = fl.fld_src; | 1269 | __le16 src_map = fl.fld_src; |
1270 | free_res = 1; | 1270 | free_res = 1; |
1271 | 1271 | ||
1272 | out_dev = DN_FIB_RES_DEV(res); | 1272 | out_dev = DN_FIB_RES_DEV(res); |
1273 | if (out_dev == NULL) { | 1273 | if (out_dev == NULL) { |
1274 | if (net_ratelimit()) | 1274 | if (net_ratelimit()) |
1275 | printk(KERN_CRIT "Bug in dn_route_input_slow() " | 1275 | printk(KERN_CRIT "Bug in dn_route_input_slow() " |
1276 | "No output device\n"); | 1276 | "No output device\n"); |
1277 | goto e_inval; | 1277 | goto e_inval; |
1278 | } | 1278 | } |
1279 | dev_hold(out_dev); | 1279 | dev_hold(out_dev); |
1280 | 1280 | ||
1281 | if (res.r) | 1281 | if (res.r) |
1282 | src_map = fl.fld_src; /* no NAT support for now */ | 1282 | src_map = fl.fld_src; /* no NAT support for now */ |
1283 | 1283 | ||
1284 | gateway = DN_FIB_RES_GW(res); | 1284 | gateway = DN_FIB_RES_GW(res); |
1285 | if (res.type == RTN_NAT) { | 1285 | if (res.type == RTN_NAT) { |
1286 | fl.fld_dst = dn_fib_rules_map_destination(fl.fld_dst, &res); | 1286 | fl.fld_dst = dn_fib_rules_map_destination(fl.fld_dst, &res); |
1287 | dn_fib_res_put(&res); | 1287 | dn_fib_res_put(&res); |
1288 | free_res = 0; | 1288 | free_res = 0; |
1289 | if (dn_fib_lookup(&fl, &res)) | 1289 | if (dn_fib_lookup(&fl, &res)) |
1290 | goto e_inval; | 1290 | goto e_inval; |
1291 | free_res = 1; | 1291 | free_res = 1; |
1292 | if (res.type != RTN_UNICAST) | 1292 | if (res.type != RTN_UNICAST) |
1293 | goto e_inval; | 1293 | goto e_inval; |
1294 | flags |= RTCF_DNAT; | 1294 | flags |= RTCF_DNAT; |
1295 | gateway = fl.fld_dst; | 1295 | gateway = fl.fld_dst; |
1296 | } | 1296 | } |
1297 | fl.fld_src = src_map; | 1297 | fl.fld_src = src_map; |
1298 | } | 1298 | } |
1299 | 1299 | ||
1300 | switch(res.type) { | 1300 | switch(res.type) { |
1301 | case RTN_UNICAST: | 1301 | case RTN_UNICAST: |
1302 | /* | 1302 | /* |
1303 | * Forwarding check here, we only check for forwarding | 1303 | * Forwarding check here, we only check for forwarding |
1304 | * being turned off, if you want to only forward intra | 1304 | * being turned off, if you want to only forward intra |
1305 | * area, its up to you to set the routing tables up | 1305 | * area, its up to you to set the routing tables up |
1306 | * correctly. | 1306 | * correctly. |
1307 | */ | 1307 | */ |
1308 | if (dn_db->parms.forwarding == 0) | 1308 | if (dn_db->parms.forwarding == 0) |
1309 | goto e_inval; | 1309 | goto e_inval; |
1310 | 1310 | ||
1311 | if (res.fi->fib_nhs > 1 && fl.oif == 0) | 1311 | if (res.fi->fib_nhs > 1 && fl.oif == 0) |
1312 | dn_fib_select_multipath(&fl, &res); | 1312 | dn_fib_select_multipath(&fl, &res); |
1313 | 1313 | ||
1314 | /* | 1314 | /* |
1315 | * Check for out_dev == in_dev. We use the RTCF_DOREDIRECT | 1315 | * Check for out_dev == in_dev. We use the RTCF_DOREDIRECT |
1316 | * flag as a hint to set the intra-ethernet bit when | 1316 | * flag as a hint to set the intra-ethernet bit when |
1317 | * forwarding. If we've got NAT in operation, we don't do | 1317 | * forwarding. If we've got NAT in operation, we don't do |
1318 | * this optimisation. | 1318 | * this optimisation. |
1319 | */ | 1319 | */ |
1320 | if (out_dev == in_dev && !(flags & RTCF_NAT)) | 1320 | if (out_dev == in_dev && !(flags & RTCF_NAT)) |
1321 | flags |= RTCF_DOREDIRECT; | 1321 | flags |= RTCF_DOREDIRECT; |
1322 | 1322 | ||
1323 | local_src = DN_FIB_RES_PREFSRC(res); | 1323 | local_src = DN_FIB_RES_PREFSRC(res); |
1324 | 1324 | ||
1325 | case RTN_BLACKHOLE: | 1325 | case RTN_BLACKHOLE: |
1326 | case RTN_UNREACHABLE: | 1326 | case RTN_UNREACHABLE: |
1327 | break; | 1327 | break; |
1328 | case RTN_LOCAL: | 1328 | case RTN_LOCAL: |
1329 | flags |= RTCF_LOCAL; | 1329 | flags |= RTCF_LOCAL; |
1330 | fl.fld_src = cb->dst; | 1330 | fl.fld_src = cb->dst; |
1331 | fl.fld_dst = cb->src; | 1331 | fl.fld_dst = cb->src; |
1332 | 1332 | ||
1333 | /* Routing tables gave us a gateway */ | 1333 | /* Routing tables gave us a gateway */ |
1334 | if (gateway) | 1334 | if (gateway) |
1335 | goto make_route; | 1335 | goto make_route; |
1336 | 1336 | ||
1337 | /* Packet was intra-ethernet, so we know its on-link */ | 1337 | /* Packet was intra-ethernet, so we know its on-link */ |
1338 | if (cb->rt_flags & DN_RT_F_IE) { | 1338 | if (cb->rt_flags & DN_RT_F_IE) { |
1339 | gateway = cb->src; | 1339 | gateway = cb->src; |
1340 | flags |= RTCF_DIRECTSRC; | 1340 | flags |= RTCF_DIRECTSRC; |
1341 | goto make_route; | 1341 | goto make_route; |
1342 | } | 1342 | } |
1343 | 1343 | ||
1344 | /* Use the default router if there is one */ | 1344 | /* Use the default router if there is one */ |
1345 | neigh = neigh_clone(dn_db->router); | 1345 | neigh = neigh_clone(dn_db->router); |
1346 | if (neigh) { | 1346 | if (neigh) { |
1347 | gateway = ((struct dn_neigh *)neigh)->addr; | 1347 | gateway = ((struct dn_neigh *)neigh)->addr; |
1348 | goto make_route; | 1348 | goto make_route; |
1349 | } | 1349 | } |
1350 | 1350 | ||
1351 | /* Close eyes and pray */ | 1351 | /* Close eyes and pray */ |
1352 | gateway = cb->src; | 1352 | gateway = cb->src; |
1353 | flags |= RTCF_DIRECTSRC; | 1353 | flags |= RTCF_DIRECTSRC; |
1354 | goto make_route; | 1354 | goto make_route; |
1355 | default: | 1355 | default: |
1356 | goto e_inval; | 1356 | goto e_inval; |
1357 | } | 1357 | } |
1358 | 1358 | ||
1359 | make_route: | 1359 | make_route: |
1360 | rt = dst_alloc(&dn_dst_ops); | 1360 | rt = dst_alloc(&dn_dst_ops); |
1361 | if (rt == NULL) | 1361 | if (rt == NULL) |
1362 | goto e_nobufs; | 1362 | goto e_nobufs; |
1363 | 1363 | ||
1364 | rt->rt_saddr = fl.fld_src; | 1364 | rt->rt_saddr = fl.fld_src; |
1365 | rt->rt_daddr = fl.fld_dst; | 1365 | rt->rt_daddr = fl.fld_dst; |
1366 | rt->rt_gateway = fl.fld_dst; | 1366 | rt->rt_gateway = fl.fld_dst; |
1367 | if (gateway) | 1367 | if (gateway) |
1368 | rt->rt_gateway = gateway; | 1368 | rt->rt_gateway = gateway; |
1369 | rt->rt_local_src = local_src ? local_src : rt->rt_saddr; | 1369 | rt->rt_local_src = local_src ? local_src : rt->rt_saddr; |
1370 | 1370 | ||
1371 | rt->rt_dst_map = fl.fld_dst; | 1371 | rt->rt_dst_map = fl.fld_dst; |
1372 | rt->rt_src_map = fl.fld_src; | 1372 | rt->rt_src_map = fl.fld_src; |
1373 | 1373 | ||
1374 | rt->fl.fld_src = cb->src; | 1374 | rt->fl.fld_src = cb->src; |
1375 | rt->fl.fld_dst = cb->dst; | 1375 | rt->fl.fld_dst = cb->dst; |
1376 | rt->fl.oif = 0; | 1376 | rt->fl.oif = 0; |
1377 | rt->fl.iif = in_dev->ifindex; | 1377 | rt->fl.iif = in_dev->ifindex; |
1378 | rt->fl.mark = fl.mark; | 1378 | rt->fl.mark = fl.mark; |
1379 | 1379 | ||
1380 | rt->u.dst.flags = DST_HOST; | 1380 | rt->u.dst.flags = DST_HOST; |
1381 | rt->u.dst.neighbour = neigh; | 1381 | rt->u.dst.neighbour = neigh; |
1382 | rt->u.dst.dev = out_dev; | 1382 | rt->u.dst.dev = out_dev; |
1383 | rt->u.dst.lastuse = jiffies; | 1383 | rt->u.dst.lastuse = jiffies; |
1384 | rt->u.dst.output = dn_rt_bug; | 1384 | rt->u.dst.output = dn_rt_bug; |
1385 | switch(res.type) { | 1385 | switch(res.type) { |
1386 | case RTN_UNICAST: | 1386 | case RTN_UNICAST: |
1387 | rt->u.dst.input = dn_forward; | 1387 | rt->u.dst.input = dn_forward; |
1388 | break; | 1388 | break; |
1389 | case RTN_LOCAL: | 1389 | case RTN_LOCAL: |
1390 | rt->u.dst.output = dn_output; | 1390 | rt->u.dst.output = dn_output; |
1391 | rt->u.dst.input = dn_nsp_rx; | 1391 | rt->u.dst.input = dn_nsp_rx; |
1392 | rt->u.dst.dev = in_dev; | 1392 | rt->u.dst.dev = in_dev; |
1393 | flags |= RTCF_LOCAL; | 1393 | flags |= RTCF_LOCAL; |
1394 | break; | 1394 | break; |
1395 | default: | 1395 | default: |
1396 | case RTN_UNREACHABLE: | 1396 | case RTN_UNREACHABLE: |
1397 | case RTN_BLACKHOLE: | 1397 | case RTN_BLACKHOLE: |
1398 | rt->u.dst.input = dn_blackhole; | 1398 | rt->u.dst.input = dn_blackhole; |
1399 | } | 1399 | } |
1400 | rt->rt_flags = flags; | 1400 | rt->rt_flags = flags; |
1401 | if (rt->u.dst.dev) | 1401 | if (rt->u.dst.dev) |
1402 | dev_hold(rt->u.dst.dev); | 1402 | dev_hold(rt->u.dst.dev); |
1403 | 1403 | ||
1404 | err = dn_rt_set_next_hop(rt, &res); | 1404 | err = dn_rt_set_next_hop(rt, &res); |
1405 | if (err) | 1405 | if (err) |
1406 | goto e_neighbour; | 1406 | goto e_neighbour; |
1407 | 1407 | ||
1408 | hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); | 1408 | hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); |
1409 | dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); | 1409 | dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); |
1410 | 1410 | ||
1411 | done: | 1411 | done: |
1412 | if (neigh) | 1412 | if (neigh) |
1413 | neigh_release(neigh); | 1413 | neigh_release(neigh); |
1414 | if (free_res) | 1414 | if (free_res) |
1415 | dn_fib_res_put(&res); | 1415 | dn_fib_res_put(&res); |
1416 | dev_put(in_dev); | 1416 | dev_put(in_dev); |
1417 | if (out_dev) | 1417 | if (out_dev) |
1418 | dev_put(out_dev); | 1418 | dev_put(out_dev); |
1419 | out: | 1419 | out: |
1420 | return err; | 1420 | return err; |
1421 | 1421 | ||
1422 | e_inval: | 1422 | e_inval: |
1423 | err = -EINVAL; | 1423 | err = -EINVAL; |
1424 | goto done; | 1424 | goto done; |
1425 | 1425 | ||
1426 | e_nobufs: | 1426 | e_nobufs: |
1427 | err = -ENOBUFS; | 1427 | err = -ENOBUFS; |
1428 | goto done; | 1428 | goto done; |
1429 | 1429 | ||
1430 | e_neighbour: | 1430 | e_neighbour: |
1431 | dst_free(&rt->u.dst); | 1431 | dst_free(&rt->u.dst); |
1432 | goto done; | 1432 | goto done; |
1433 | } | 1433 | } |
1434 | 1434 | ||
1435 | int dn_route_input(struct sk_buff *skb) | 1435 | int dn_route_input(struct sk_buff *skb) |
1436 | { | 1436 | { |
1437 | struct dn_route *rt; | 1437 | struct dn_route *rt; |
1438 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 1438 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
1439 | unsigned hash = dn_hash(cb->src, cb->dst); | 1439 | unsigned hash = dn_hash(cb->src, cb->dst); |
1440 | 1440 | ||
1441 | if (skb->dst) | 1441 | if (skb->dst) |
1442 | return 0; | 1442 | return 0; |
1443 | 1443 | ||
1444 | rcu_read_lock(); | 1444 | rcu_read_lock(); |
1445 | for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL; | 1445 | for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL; |
1446 | rt = rcu_dereference(rt->u.rt_next)) { | 1446 | rt = rcu_dereference(rt->u.rt_next)) { |
1447 | if ((rt->fl.fld_src == cb->src) && | 1447 | if ((rt->fl.fld_src == cb->src) && |
1448 | (rt->fl.fld_dst == cb->dst) && | 1448 | (rt->fl.fld_dst == cb->dst) && |
1449 | (rt->fl.oif == 0) && | 1449 | (rt->fl.oif == 0) && |
1450 | (rt->fl.mark == skb->mark) && | 1450 | (rt->fl.mark == skb->mark) && |
1451 | (rt->fl.iif == cb->iif)) { | 1451 | (rt->fl.iif == cb->iif)) { |
1452 | rt->u.dst.lastuse = jiffies; | 1452 | rt->u.dst.lastuse = jiffies; |
1453 | dst_hold(&rt->u.dst); | 1453 | dst_hold(&rt->u.dst); |
1454 | rt->u.dst.__use++; | 1454 | rt->u.dst.__use++; |
1455 | rcu_read_unlock(); | 1455 | rcu_read_unlock(); |
1456 | skb->dst = (struct dst_entry *)rt; | 1456 | skb->dst = (struct dst_entry *)rt; |
1457 | return 0; | 1457 | return 0; |
1458 | } | 1458 | } |
1459 | } | 1459 | } |
1460 | rcu_read_unlock(); | 1460 | rcu_read_unlock(); |
1461 | 1461 | ||
1462 | return dn_route_input_slow(skb); | 1462 | return dn_route_input_slow(skb); |
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | 1465 | static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, |
1466 | int event, int nowait, unsigned int flags) | 1466 | int event, int nowait, unsigned int flags) |
1467 | { | 1467 | { |
1468 | struct dn_route *rt = (struct dn_route *)skb->dst; | 1468 | struct dn_route *rt = (struct dn_route *)skb->dst; |
1469 | struct rtmsg *r; | 1469 | struct rtmsg *r; |
1470 | struct nlmsghdr *nlh; | 1470 | struct nlmsghdr *nlh; |
1471 | unsigned char *b = skb->tail; | 1471 | unsigned char *b = skb->tail; |
1472 | struct rta_cacheinfo ci; | 1472 | struct rta_cacheinfo ci; |
1473 | 1473 | ||
1474 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 1474 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); |
1475 | r = NLMSG_DATA(nlh); | 1475 | r = NLMSG_DATA(nlh); |
1476 | r->rtm_family = AF_DECnet; | 1476 | r->rtm_family = AF_DECnet; |
1477 | r->rtm_dst_len = 16; | 1477 | r->rtm_dst_len = 16; |
1478 | r->rtm_src_len = 0; | 1478 | r->rtm_src_len = 0; |
1479 | r->rtm_tos = 0; | 1479 | r->rtm_tos = 0; |
1480 | r->rtm_table = RT_TABLE_MAIN; | 1480 | r->rtm_table = RT_TABLE_MAIN; |
1481 | RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); | 1481 | RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); |
1482 | r->rtm_type = rt->rt_type; | 1482 | r->rtm_type = rt->rt_type; |
1483 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; | 1483 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
1484 | r->rtm_scope = RT_SCOPE_UNIVERSE; | 1484 | r->rtm_scope = RT_SCOPE_UNIVERSE; |
1485 | r->rtm_protocol = RTPROT_UNSPEC; | 1485 | r->rtm_protocol = RTPROT_UNSPEC; |
1486 | if (rt->rt_flags & RTCF_NOTIFY) | 1486 | if (rt->rt_flags & RTCF_NOTIFY) |
1487 | r->rtm_flags |= RTM_F_NOTIFY; | 1487 | r->rtm_flags |= RTM_F_NOTIFY; |
1488 | RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr); | 1488 | RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr); |
1489 | if (rt->fl.fld_src) { | 1489 | if (rt->fl.fld_src) { |
1490 | r->rtm_src_len = 16; | 1490 | r->rtm_src_len = 16; |
1491 | RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src); | 1491 | RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src); |
1492 | } | 1492 | } |
1493 | if (rt->u.dst.dev) | 1493 | if (rt->u.dst.dev) |
1494 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); | 1494 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); |
1495 | /* | 1495 | /* |
1496 | * Note to self - change this if input routes reverse direction when | 1496 | * Note to self - change this if input routes reverse direction when |
1497 | * they deal only with inputs and not with replies like they do | 1497 | * they deal only with inputs and not with replies like they do |
1498 | * currently. | 1498 | * currently. |
1499 | */ | 1499 | */ |
1500 | RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src); | 1500 | RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src); |
1501 | if (rt->rt_daddr != rt->rt_gateway) | 1501 | if (rt->rt_daddr != rt->rt_gateway) |
1502 | RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); | 1502 | RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); |
1503 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 1503 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
1504 | goto rtattr_failure; | 1504 | goto rtattr_failure; |
1505 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 1505 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); |
1506 | ci.rta_used = rt->u.dst.__use; | 1506 | ci.rta_used = rt->u.dst.__use; |
1507 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); | 1507 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); |
1508 | if (rt->u.dst.expires) | 1508 | if (rt->u.dst.expires) |
1509 | ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); | 1509 | ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); |
1510 | else | 1510 | else |
1511 | ci.rta_expires = 0; | 1511 | ci.rta_expires = 0; |
1512 | ci.rta_error = rt->u.dst.error; | 1512 | ci.rta_error = rt->u.dst.error; |
1513 | ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; | 1513 | ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; |
1514 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 1514 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
1515 | if (rt->fl.iif) | 1515 | if (rt->fl.iif) |
1516 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); | 1516 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); |
1517 | 1517 | ||
1518 | nlh->nlmsg_len = skb->tail - b; | 1518 | nlh->nlmsg_len = skb->tail - b; |
1519 | return skb->len; | 1519 | return skb->len; |
1520 | 1520 | ||
1521 | nlmsg_failure: | 1521 | nlmsg_failure: |
1522 | rtattr_failure: | 1522 | rtattr_failure: |
1523 | skb_trim(skb, b - skb->data); | 1523 | skb_trim(skb, b - skb->data); |
1524 | return -1; | 1524 | return -1; |
1525 | } | 1525 | } |
1526 | 1526 | ||
1527 | /* | 1527 | /* |
1528 | * This is called by both endnodes and routers now. | 1528 | * This is called by both endnodes and routers now. |
1529 | */ | 1529 | */ |
1530 | int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) | 1530 | int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) |
1531 | { | 1531 | { |
1532 | struct rtattr **rta = arg; | 1532 | struct rtattr **rta = arg; |
1533 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 1533 | struct rtmsg *rtm = NLMSG_DATA(nlh); |
1534 | struct dn_route *rt = NULL; | 1534 | struct dn_route *rt = NULL; |
1535 | struct dn_skb_cb *cb; | 1535 | struct dn_skb_cb *cb; |
1536 | int err; | 1536 | int err; |
1537 | struct sk_buff *skb; | 1537 | struct sk_buff *skb; |
1538 | struct flowi fl; | 1538 | struct flowi fl; |
1539 | 1539 | ||
1540 | memset(&fl, 0, sizeof(fl)); | 1540 | memset(&fl, 0, sizeof(fl)); |
1541 | fl.proto = DNPROTO_NSP; | 1541 | fl.proto = DNPROTO_NSP; |
1542 | 1542 | ||
1543 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 1543 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1544 | if (skb == NULL) | 1544 | if (skb == NULL) |
1545 | return -ENOBUFS; | 1545 | return -ENOBUFS; |
1546 | skb->mac.raw = skb->data; | 1546 | skb->mac.raw = skb->data; |
1547 | cb = DN_SKB_CB(skb); | 1547 | cb = DN_SKB_CB(skb); |
1548 | 1548 | ||
1549 | if (rta[RTA_SRC-1]) | 1549 | if (rta[RTA_SRC-1]) |
1550 | memcpy(&fl.fld_src, RTA_DATA(rta[RTA_SRC-1]), 2); | 1550 | memcpy(&fl.fld_src, RTA_DATA(rta[RTA_SRC-1]), 2); |
1551 | if (rta[RTA_DST-1]) | 1551 | if (rta[RTA_DST-1]) |
1552 | memcpy(&fl.fld_dst, RTA_DATA(rta[RTA_DST-1]), 2); | 1552 | memcpy(&fl.fld_dst, RTA_DATA(rta[RTA_DST-1]), 2); |
1553 | if (rta[RTA_IIF-1]) | 1553 | if (rta[RTA_IIF-1]) |
1554 | memcpy(&fl.iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 1554 | memcpy(&fl.iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); |
1555 | 1555 | ||
1556 | if (fl.iif) { | 1556 | if (fl.iif) { |
1557 | struct net_device *dev; | 1557 | struct net_device *dev; |
1558 | if ((dev = dev_get_by_index(fl.iif)) == NULL) { | 1558 | if ((dev = dev_get_by_index(fl.iif)) == NULL) { |
1559 | kfree_skb(skb); | 1559 | kfree_skb(skb); |
1560 | return -ENODEV; | 1560 | return -ENODEV; |
1561 | } | 1561 | } |
1562 | if (!dev->dn_ptr) { | 1562 | if (!dev->dn_ptr) { |
1563 | dev_put(dev); | 1563 | dev_put(dev); |
1564 | kfree_skb(skb); | 1564 | kfree_skb(skb); |
1565 | return -ENODEV; | 1565 | return -ENODEV; |
1566 | } | 1566 | } |
1567 | skb->protocol = __constant_htons(ETH_P_DNA_RT); | 1567 | skb->protocol = __constant_htons(ETH_P_DNA_RT); |
1568 | skb->dev = dev; | 1568 | skb->dev = dev; |
1569 | cb->src = fl.fld_src; | 1569 | cb->src = fl.fld_src; |
1570 | cb->dst = fl.fld_dst; | 1570 | cb->dst = fl.fld_dst; |
1571 | local_bh_disable(); | 1571 | local_bh_disable(); |
1572 | err = dn_route_input(skb); | 1572 | err = dn_route_input(skb); |
1573 | local_bh_enable(); | 1573 | local_bh_enable(); |
1574 | memset(cb, 0, sizeof(struct dn_skb_cb)); | 1574 | memset(cb, 0, sizeof(struct dn_skb_cb)); |
1575 | rt = (struct dn_route *)skb->dst; | 1575 | rt = (struct dn_route *)skb->dst; |
1576 | if (!err && -rt->u.dst.error) | 1576 | if (!err && -rt->u.dst.error) |
1577 | err = rt->u.dst.error; | 1577 | err = rt->u.dst.error; |
1578 | } else { | 1578 | } else { |
1579 | int oif = 0; | 1579 | int oif = 0; |
1580 | if (rta[RTA_OIF - 1]) | 1580 | if (rta[RTA_OIF - 1]) |
1581 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); | 1581 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); |
1582 | fl.oif = oif; | 1582 | fl.oif = oif; |
1583 | err = dn_route_output_key((struct dst_entry **)&rt, &fl, 0); | 1583 | err = dn_route_output_key((struct dst_entry **)&rt, &fl, 0); |
1584 | } | 1584 | } |
1585 | 1585 | ||
1586 | if (skb->dev) | 1586 | if (skb->dev) |
1587 | dev_put(skb->dev); | 1587 | dev_put(skb->dev); |
1588 | skb->dev = NULL; | 1588 | skb->dev = NULL; |
1589 | if (err) | 1589 | if (err) |
1590 | goto out_free; | 1590 | goto out_free; |
1591 | skb->dst = &rt->u.dst; | 1591 | skb->dst = &rt->u.dst; |
1592 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 1592 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
1593 | rt->rt_flags |= RTCF_NOTIFY; | 1593 | rt->rt_flags |= RTCF_NOTIFY; |
1594 | 1594 | ||
1595 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
1596 | |||
1597 | err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0); | 1595 | err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0); |
1598 | 1596 | ||
1599 | if (err == 0) | 1597 | if (err == 0) |
1600 | goto out_free; | 1598 | goto out_free; |
1601 | if (err < 0) { | 1599 | if (err < 0) { |
1602 | err = -EMSGSIZE; | 1600 | err = -EMSGSIZE; |
1603 | goto out_free; | 1601 | goto out_free; |
1604 | } | 1602 | } |
1605 | 1603 | ||
1606 | return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | 1604 | return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
1607 | 1605 | ||
1608 | out_free: | 1606 | out_free: |
1609 | kfree_skb(skb); | 1607 | kfree_skb(skb); |
1610 | return err; | 1608 | return err; |
1611 | } | 1609 | } |
1612 | 1610 | ||
1613 | /* | 1611 | /* |
1614 | * For routers, this is called from dn_fib_dump, but for endnodes its | 1612 | * For routers, this is called from dn_fib_dump, but for endnodes its |
1615 | * called directly from the rtnetlink dispatch table. | 1613 | * called directly from the rtnetlink dispatch table. |
1616 | */ | 1614 | */ |
1617 | int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) | 1615 | int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) |
1618 | { | 1616 | { |
1619 | struct dn_route *rt; | 1617 | struct dn_route *rt; |
1620 | int h, s_h; | 1618 | int h, s_h; |
1621 | int idx, s_idx; | 1619 | int idx, s_idx; |
1622 | 1620 | ||
1623 | if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) | 1621 | if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) |
1624 | return -EINVAL; | 1622 | return -EINVAL; |
1625 | if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)) | 1623 | if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)) |
1626 | return 0; | 1624 | return 0; |
1627 | 1625 | ||
1628 | s_h = cb->args[0]; | 1626 | s_h = cb->args[0]; |
1629 | s_idx = idx = cb->args[1]; | 1627 | s_idx = idx = cb->args[1]; |
1630 | for(h = 0; h <= dn_rt_hash_mask; h++) { | 1628 | for(h = 0; h <= dn_rt_hash_mask; h++) { |
1631 | if (h < s_h) | 1629 | if (h < s_h) |
1632 | continue; | 1630 | continue; |
1633 | if (h > s_h) | 1631 | if (h > s_h) |
1634 | s_idx = 0; | 1632 | s_idx = 0; |
1635 | rcu_read_lock_bh(); | 1633 | rcu_read_lock_bh(); |
1636 | for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0; | 1634 | for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0; |
1637 | rt; | 1635 | rt; |
1638 | rt = rcu_dereference(rt->u.rt_next), idx++) { | 1636 | rt = rcu_dereference(rt->u.rt_next), idx++) { |
1639 | if (idx < s_idx) | 1637 | if (idx < s_idx) |
1640 | continue; | 1638 | continue; |
1641 | skb->dst = dst_clone(&rt->u.dst); | 1639 | skb->dst = dst_clone(&rt->u.dst); |
1642 | if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, | 1640 | if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, |
1643 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, | 1641 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, |
1644 | 1, NLM_F_MULTI) <= 0) { | 1642 | 1, NLM_F_MULTI) <= 0) { |
1645 | dst_release(xchg(&skb->dst, NULL)); | 1643 | dst_release(xchg(&skb->dst, NULL)); |
1646 | rcu_read_unlock_bh(); | 1644 | rcu_read_unlock_bh(); |
1647 | goto done; | 1645 | goto done; |
1648 | } | 1646 | } |
1649 | dst_release(xchg(&skb->dst, NULL)); | 1647 | dst_release(xchg(&skb->dst, NULL)); |
1650 | } | 1648 | } |
1651 | rcu_read_unlock_bh(); | 1649 | rcu_read_unlock_bh(); |
1652 | } | 1650 | } |
1653 | 1651 | ||
1654 | done: | 1652 | done: |
1655 | cb->args[0] = h; | 1653 | cb->args[0] = h; |
1656 | cb->args[1] = idx; | 1654 | cb->args[1] = idx; |
1657 | return skb->len; | 1655 | return skb->len; |
1658 | } | 1656 | } |
1659 | 1657 | ||
1660 | #ifdef CONFIG_PROC_FS | 1658 | #ifdef CONFIG_PROC_FS |
1661 | struct dn_rt_cache_iter_state { | 1659 | struct dn_rt_cache_iter_state { |
1662 | int bucket; | 1660 | int bucket; |
1663 | }; | 1661 | }; |
1664 | 1662 | ||
1665 | static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq) | 1663 | static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq) |
1666 | { | 1664 | { |
1667 | struct dn_route *rt = NULL; | 1665 | struct dn_route *rt = NULL; |
1668 | struct dn_rt_cache_iter_state *s = seq->private; | 1666 | struct dn_rt_cache_iter_state *s = seq->private; |
1669 | 1667 | ||
1670 | for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) { | 1668 | for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) { |
1671 | rcu_read_lock_bh(); | 1669 | rcu_read_lock_bh(); |
1672 | rt = dn_rt_hash_table[s->bucket].chain; | 1670 | rt = dn_rt_hash_table[s->bucket].chain; |
1673 | if (rt) | 1671 | if (rt) |
1674 | break; | 1672 | break; |
1675 | rcu_read_unlock_bh(); | 1673 | rcu_read_unlock_bh(); |
1676 | } | 1674 | } |
1677 | return rt; | 1675 | return rt; |
1678 | } | 1676 | } |
1679 | 1677 | ||
1680 | static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt) | 1678 | static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt) |
1681 | { | 1679 | { |
1682 | struct dn_rt_cache_iter_state *s = rcu_dereference(seq->private); | 1680 | struct dn_rt_cache_iter_state *s = rcu_dereference(seq->private); |
1683 | 1681 | ||
1684 | rt = rt->u.rt_next; | 1682 | rt = rt->u.rt_next; |
1685 | while(!rt) { | 1683 | while(!rt) { |
1686 | rcu_read_unlock_bh(); | 1684 | rcu_read_unlock_bh(); |
1687 | if (--s->bucket < 0) | 1685 | if (--s->bucket < 0) |
1688 | break; | 1686 | break; |
1689 | rcu_read_lock_bh(); | 1687 | rcu_read_lock_bh(); |
1690 | rt = dn_rt_hash_table[s->bucket].chain; | 1688 | rt = dn_rt_hash_table[s->bucket].chain; |
1691 | } | 1689 | } |
1692 | return rt; | 1690 | return rt; |
1693 | } | 1691 | } |
1694 | 1692 | ||
1695 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) | 1693 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) |
1696 | { | 1694 | { |
1697 | struct dn_route *rt = dn_rt_cache_get_first(seq); | 1695 | struct dn_route *rt = dn_rt_cache_get_first(seq); |
1698 | 1696 | ||
1699 | if (rt) { | 1697 | if (rt) { |
1700 | while(*pos && (rt = dn_rt_cache_get_next(seq, rt))) | 1698 | while(*pos && (rt = dn_rt_cache_get_next(seq, rt))) |
1701 | --*pos; | 1699 | --*pos; |
1702 | } | 1700 | } |
1703 | return *pos ? NULL : rt; | 1701 | return *pos ? NULL : rt; |
1704 | } | 1702 | } |
1705 | 1703 | ||
1706 | static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 1704 | static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
1707 | { | 1705 | { |
1708 | struct dn_route *rt = dn_rt_cache_get_next(seq, v); | 1706 | struct dn_route *rt = dn_rt_cache_get_next(seq, v); |
1709 | ++*pos; | 1707 | ++*pos; |
1710 | return rt; | 1708 | return rt; |
1711 | } | 1709 | } |
1712 | 1710 | ||
1713 | static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v) | 1711 | static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v) |
1714 | { | 1712 | { |
1715 | if (v) | 1713 | if (v) |
1716 | rcu_read_unlock_bh(); | 1714 | rcu_read_unlock_bh(); |
1717 | } | 1715 | } |
1718 | 1716 | ||
1719 | static int dn_rt_cache_seq_show(struct seq_file *seq, void *v) | 1717 | static int dn_rt_cache_seq_show(struct seq_file *seq, void *v) |
1720 | { | 1718 | { |
1721 | struct dn_route *rt = v; | 1719 | struct dn_route *rt = v; |
1722 | char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN]; | 1720 | char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN]; |
1723 | 1721 | ||
1724 | seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n", | 1722 | seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n", |
1725 | rt->u.dst.dev ? rt->u.dst.dev->name : "*", | 1723 | rt->u.dst.dev ? rt->u.dst.dev->name : "*", |
1726 | dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), | 1724 | dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), |
1727 | dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), | 1725 | dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), |
1728 | atomic_read(&rt->u.dst.__refcnt), | 1726 | atomic_read(&rt->u.dst.__refcnt), |
1729 | rt->u.dst.__use, | 1727 | rt->u.dst.__use, |
1730 | (int) dst_metric(&rt->u.dst, RTAX_RTT)); | 1728 | (int) dst_metric(&rt->u.dst, RTAX_RTT)); |
1731 | return 0; | 1729 | return 0; |
1732 | } | 1730 | } |
1733 | 1731 | ||
1734 | static struct seq_operations dn_rt_cache_seq_ops = { | 1732 | static struct seq_operations dn_rt_cache_seq_ops = { |
1735 | .start = dn_rt_cache_seq_start, | 1733 | .start = dn_rt_cache_seq_start, |
1736 | .next = dn_rt_cache_seq_next, | 1734 | .next = dn_rt_cache_seq_next, |
1737 | .stop = dn_rt_cache_seq_stop, | 1735 | .stop = dn_rt_cache_seq_stop, |
1738 | .show = dn_rt_cache_seq_show, | 1736 | .show = dn_rt_cache_seq_show, |
1739 | }; | 1737 | }; |
1740 | 1738 | ||
1741 | static int dn_rt_cache_seq_open(struct inode *inode, struct file *file) | 1739 | static int dn_rt_cache_seq_open(struct inode *inode, struct file *file) |
1742 | { | 1740 | { |
1743 | struct seq_file *seq; | 1741 | struct seq_file *seq; |
1744 | int rc = -ENOMEM; | 1742 | int rc = -ENOMEM; |
1745 | struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 1743 | struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); |
1746 | 1744 | ||
1747 | if (!s) | 1745 | if (!s) |
1748 | goto out; | 1746 | goto out; |
1749 | rc = seq_open(file, &dn_rt_cache_seq_ops); | 1747 | rc = seq_open(file, &dn_rt_cache_seq_ops); |
1750 | if (rc) | 1748 | if (rc) |
1751 | goto out_kfree; | 1749 | goto out_kfree; |
1752 | seq = file->private_data; | 1750 | seq = file->private_data; |
1753 | seq->private = s; | 1751 | seq->private = s; |
1754 | memset(s, 0, sizeof(*s)); | 1752 | memset(s, 0, sizeof(*s)); |
1755 | out: | 1753 | out: |
1756 | return rc; | 1754 | return rc; |
1757 | out_kfree: | 1755 | out_kfree: |
1758 | kfree(s); | 1756 | kfree(s); |
1759 | goto out; | 1757 | goto out; |
1760 | } | 1758 | } |
1761 | 1759 | ||
1762 | static struct file_operations dn_rt_cache_seq_fops = { | 1760 | static struct file_operations dn_rt_cache_seq_fops = { |
1763 | .owner = THIS_MODULE, | 1761 | .owner = THIS_MODULE, |
1764 | .open = dn_rt_cache_seq_open, | 1762 | .open = dn_rt_cache_seq_open, |
1765 | .read = seq_read, | 1763 | .read = seq_read, |
1766 | .llseek = seq_lseek, | 1764 | .llseek = seq_lseek, |
1767 | .release = seq_release_private, | 1765 | .release = seq_release_private, |
1768 | }; | 1766 | }; |
1769 | 1767 | ||
1770 | #endif /* CONFIG_PROC_FS */ | 1768 | #endif /* CONFIG_PROC_FS */ |
1771 | 1769 | ||
1772 | void __init dn_route_init(void) | 1770 | void __init dn_route_init(void) |
1773 | { | 1771 | { |
1774 | int i, goal, order; | 1772 | int i, goal, order; |
1775 | 1773 | ||
1776 | dn_dst_ops.kmem_cachep = | 1774 | dn_dst_ops.kmem_cachep = |
1777 | kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0, | 1775 | kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0, |
1778 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 1776 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
1779 | init_timer(&dn_route_timer); | 1777 | init_timer(&dn_route_timer); |
1780 | dn_route_timer.function = dn_dst_check_expire; | 1778 | dn_route_timer.function = dn_dst_check_expire; |
1781 | dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; | 1779 | dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; |
1782 | add_timer(&dn_route_timer); | 1780 | add_timer(&dn_route_timer); |
1783 | 1781 | ||
1784 | goal = num_physpages >> (26 - PAGE_SHIFT); | 1782 | goal = num_physpages >> (26 - PAGE_SHIFT); |
1785 | 1783 | ||
1786 | for(order = 0; (1UL << order) < goal; order++) | 1784 | for(order = 0; (1UL << order) < goal; order++) |
1787 | /* NOTHING */; | 1785 | /* NOTHING */; |
1788 | 1786 | ||
1789 | /* | 1787 | /* |
1790 | * Only want 1024 entries max, since the table is very, very unlikely | 1788 | * Only want 1024 entries max, since the table is very, very unlikely |
1791 | * to be larger than that. | 1789 | * to be larger than that. |
1792 | */ | 1790 | */ |
1793 | while(order && ((((1UL << order) * PAGE_SIZE) / | 1791 | while(order && ((((1UL << order) * PAGE_SIZE) / |
1794 | sizeof(struct dn_rt_hash_bucket)) >= 2048)) | 1792 | sizeof(struct dn_rt_hash_bucket)) >= 2048)) |
1795 | order--; | 1793 | order--; |
1796 | 1794 | ||
1797 | do { | 1795 | do { |
1798 | dn_rt_hash_mask = (1UL << order) * PAGE_SIZE / | 1796 | dn_rt_hash_mask = (1UL << order) * PAGE_SIZE / |
1799 | sizeof(struct dn_rt_hash_bucket); | 1797 | sizeof(struct dn_rt_hash_bucket); |
1800 | while(dn_rt_hash_mask & (dn_rt_hash_mask - 1)) | 1798 | while(dn_rt_hash_mask & (dn_rt_hash_mask - 1)) |
1801 | dn_rt_hash_mask--; | 1799 | dn_rt_hash_mask--; |
1802 | dn_rt_hash_table = (struct dn_rt_hash_bucket *) | 1800 | dn_rt_hash_table = (struct dn_rt_hash_bucket *) |
1803 | __get_free_pages(GFP_ATOMIC, order); | 1801 | __get_free_pages(GFP_ATOMIC, order); |
1804 | } while (dn_rt_hash_table == NULL && --order > 0); | 1802 | } while (dn_rt_hash_table == NULL && --order > 0); |
1805 | 1803 | ||
1806 | if (!dn_rt_hash_table) | 1804 | if (!dn_rt_hash_table) |
1807 | panic("Failed to allocate DECnet route cache hash table\n"); | 1805 | panic("Failed to allocate DECnet route cache hash table\n"); |
1808 | 1806 | ||
1809 | printk(KERN_INFO | 1807 | printk(KERN_INFO |
1810 | "DECnet: Routing cache hash table of %u buckets, %ldKbytes\n", | 1808 | "DECnet: Routing cache hash table of %u buckets, %ldKbytes\n", |
1811 | dn_rt_hash_mask, | 1809 | dn_rt_hash_mask, |
1812 | (long)(dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024); | 1810 | (long)(dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024); |
1813 | 1811 | ||
1814 | dn_rt_hash_mask--; | 1812 | dn_rt_hash_mask--; |
1815 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 1813 | for(i = 0; i <= dn_rt_hash_mask; i++) { |
1816 | spin_lock_init(&dn_rt_hash_table[i].lock); | 1814 | spin_lock_init(&dn_rt_hash_table[i].lock); |
1817 | dn_rt_hash_table[i].chain = NULL; | 1815 | dn_rt_hash_table[i].chain = NULL; |
1818 | } | 1816 | } |
1819 | 1817 | ||
1820 | dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); | 1818 | dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); |
1821 | 1819 | ||
1822 | proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); | 1820 | proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); |
1823 | } | 1821 | } |
1824 | 1822 | ||
1825 | void __exit dn_route_cleanup(void) | 1823 | void __exit dn_route_cleanup(void) |
1826 | { | 1824 | { |
1827 | del_timer(&dn_route_timer); | 1825 | del_timer(&dn_route_timer); |
1828 | dn_run_flush(0); | 1826 | dn_run_flush(0); |
1829 | 1827 | ||
1830 | proc_net_remove("decnet_cache"); | 1828 | proc_net_remove("decnet_cache"); |
1831 | } | 1829 | } |
1832 | 1830 | ||
1833 | 1831 |
net/ipv4/fib_frontend.c
1 | /* | 1 | /* |
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | 2 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
3 | * operating system. INET is implemented using the BSD Socket | 3 | * operating system. INET is implemented using the BSD Socket |
4 | * interface as the means of communication with the user level. | 4 | * interface as the means of communication with the user level. |
5 | * | 5 | * |
6 | * IPv4 Forwarding Information Base: FIB frontend. | 6 | * IPv4 Forwarding Information Base: FIB frontend. |
7 | * | 7 | * |
8 | * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ | 8 | * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ |
9 | * | 9 | * |
10 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | 10 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
14 | * as published by the Free Software Foundation; either version | 14 | * as published by the Free Software Foundation; either version |
15 | * 2 of the License, or (at your option) any later version. | 15 | * 2 of the License, or (at your option) any later version. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/capability.h> | 22 | #include <linux/capability.h> |
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
26 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/socket.h> | 28 | #include <linux/socket.h> |
29 | #include <linux/sockios.h> | 29 | #include <linux/sockios.h> |
30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
31 | #include <linux/in.h> | 31 | #include <linux/in.h> |
32 | #include <linux/inet.h> | 32 | #include <linux/inet.h> |
33 | #include <linux/inetdevice.h> | 33 | #include <linux/inetdevice.h> |
34 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
35 | #include <linux/if_addr.h> | 35 | #include <linux/if_addr.h> |
36 | #include <linux/if_arp.h> | 36 | #include <linux/if_arp.h> |
37 | #include <linux/skbuff.h> | 37 | #include <linux/skbuff.h> |
38 | #include <linux/netlink.h> | 38 | #include <linux/netlink.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
41 | 41 | ||
42 | #include <net/ip.h> | 42 | #include <net/ip.h> |
43 | #include <net/protocol.h> | 43 | #include <net/protocol.h> |
44 | #include <net/route.h> | 44 | #include <net/route.h> |
45 | #include <net/tcp.h> | 45 | #include <net/tcp.h> |
46 | #include <net/sock.h> | 46 | #include <net/sock.h> |
47 | #include <net/icmp.h> | 47 | #include <net/icmp.h> |
48 | #include <net/arp.h> | 48 | #include <net/arp.h> |
49 | #include <net/ip_fib.h> | 49 | #include <net/ip_fib.h> |
50 | 50 | ||
51 | #define FFprint(a...) printk(KERN_DEBUG a) | 51 | #define FFprint(a...) printk(KERN_DEBUG a) |
52 | 52 | ||
53 | #ifndef CONFIG_IP_MULTIPLE_TABLES | 53 | #ifndef CONFIG_IP_MULTIPLE_TABLES |
54 | 54 | ||
55 | struct fib_table *ip_fib_local_table; | 55 | struct fib_table *ip_fib_local_table; |
56 | struct fib_table *ip_fib_main_table; | 56 | struct fib_table *ip_fib_main_table; |
57 | 57 | ||
58 | #define FIB_TABLE_HASHSZ 1 | 58 | #define FIB_TABLE_HASHSZ 1 |
59 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | 59 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; |
60 | 60 | ||
61 | #else | 61 | #else |
62 | 62 | ||
63 | #define FIB_TABLE_HASHSZ 256 | 63 | #define FIB_TABLE_HASHSZ 256 |
64 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | 64 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; |
65 | 65 | ||
66 | struct fib_table *fib_new_table(u32 id) | 66 | struct fib_table *fib_new_table(u32 id) |
67 | { | 67 | { |
68 | struct fib_table *tb; | 68 | struct fib_table *tb; |
69 | unsigned int h; | 69 | unsigned int h; |
70 | 70 | ||
71 | if (id == 0) | 71 | if (id == 0) |
72 | id = RT_TABLE_MAIN; | 72 | id = RT_TABLE_MAIN; |
73 | tb = fib_get_table(id); | 73 | tb = fib_get_table(id); |
74 | if (tb) | 74 | if (tb) |
75 | return tb; | 75 | return tb; |
76 | tb = fib_hash_init(id); | 76 | tb = fib_hash_init(id); |
77 | if (!tb) | 77 | if (!tb) |
78 | return NULL; | 78 | return NULL; |
79 | h = id & (FIB_TABLE_HASHSZ - 1); | 79 | h = id & (FIB_TABLE_HASHSZ - 1); |
80 | hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]); | 80 | hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]); |
81 | return tb; | 81 | return tb; |
82 | } | 82 | } |
83 | 83 | ||
84 | struct fib_table *fib_get_table(u32 id) | 84 | struct fib_table *fib_get_table(u32 id) |
85 | { | 85 | { |
86 | struct fib_table *tb; | 86 | struct fib_table *tb; |
87 | struct hlist_node *node; | 87 | struct hlist_node *node; |
88 | unsigned int h; | 88 | unsigned int h; |
89 | 89 | ||
90 | if (id == 0) | 90 | if (id == 0) |
91 | id = RT_TABLE_MAIN; | 91 | id = RT_TABLE_MAIN; |
92 | h = id & (FIB_TABLE_HASHSZ - 1); | 92 | h = id & (FIB_TABLE_HASHSZ - 1); |
93 | rcu_read_lock(); | 93 | rcu_read_lock(); |
94 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) { | 94 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) { |
95 | if (tb->tb_id == id) { | 95 | if (tb->tb_id == id) { |
96 | rcu_read_unlock(); | 96 | rcu_read_unlock(); |
97 | return tb; | 97 | return tb; |
98 | } | 98 | } |
99 | } | 99 | } |
100 | rcu_read_unlock(); | 100 | rcu_read_unlock(); |
101 | return NULL; | 101 | return NULL; |
102 | } | 102 | } |
103 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 103 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
104 | 104 | ||
105 | static void fib_flush(void) | 105 | static void fib_flush(void) |
106 | { | 106 | { |
107 | int flushed = 0; | 107 | int flushed = 0; |
108 | struct fib_table *tb; | 108 | struct fib_table *tb; |
109 | struct hlist_node *node; | 109 | struct hlist_node *node; |
110 | unsigned int h; | 110 | unsigned int h; |
111 | 111 | ||
112 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { | 112 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
113 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) | 113 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) |
114 | flushed += tb->tb_flush(tb); | 114 | flushed += tb->tb_flush(tb); |
115 | } | 115 | } |
116 | 116 | ||
117 | if (flushed) | 117 | if (flushed) |
118 | rt_cache_flush(-1); | 118 | rt_cache_flush(-1); |
119 | } | 119 | } |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * Find the first device with a given source address. | 122 | * Find the first device with a given source address. |
123 | */ | 123 | */ |
124 | 124 | ||
125 | struct net_device * ip_dev_find(__be32 addr) | 125 | struct net_device * ip_dev_find(__be32 addr) |
126 | { | 126 | { |
127 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; | 127 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; |
128 | struct fib_result res; | 128 | struct fib_result res; |
129 | struct net_device *dev = NULL; | 129 | struct net_device *dev = NULL; |
130 | 130 | ||
131 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 131 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
132 | res.r = NULL; | 132 | res.r = NULL; |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | if (!ip_fib_local_table || | 135 | if (!ip_fib_local_table || |
136 | ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res)) | 136 | ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res)) |
137 | return NULL; | 137 | return NULL; |
138 | if (res.type != RTN_LOCAL) | 138 | if (res.type != RTN_LOCAL) |
139 | goto out; | 139 | goto out; |
140 | dev = FIB_RES_DEV(res); | 140 | dev = FIB_RES_DEV(res); |
141 | 141 | ||
142 | if (dev) | 142 | if (dev) |
143 | dev_hold(dev); | 143 | dev_hold(dev); |
144 | out: | 144 | out: |
145 | fib_res_put(&res); | 145 | fib_res_put(&res); |
146 | return dev; | 146 | return dev; |
147 | } | 147 | } |
148 | 148 | ||
149 | unsigned inet_addr_type(__be32 addr) | 149 | unsigned inet_addr_type(__be32 addr) |
150 | { | 150 | { |
151 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; | 151 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; |
152 | struct fib_result res; | 152 | struct fib_result res; |
153 | unsigned ret = RTN_BROADCAST; | 153 | unsigned ret = RTN_BROADCAST; |
154 | 154 | ||
155 | if (ZERONET(addr) || BADCLASS(addr)) | 155 | if (ZERONET(addr) || BADCLASS(addr)) |
156 | return RTN_BROADCAST; | 156 | return RTN_BROADCAST; |
157 | if (MULTICAST(addr)) | 157 | if (MULTICAST(addr)) |
158 | return RTN_MULTICAST; | 158 | return RTN_MULTICAST; |
159 | 159 | ||
160 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 160 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
161 | res.r = NULL; | 161 | res.r = NULL; |
162 | #endif | 162 | #endif |
163 | 163 | ||
164 | if (ip_fib_local_table) { | 164 | if (ip_fib_local_table) { |
165 | ret = RTN_UNICAST; | 165 | ret = RTN_UNICAST; |
166 | if (!ip_fib_local_table->tb_lookup(ip_fib_local_table, | 166 | if (!ip_fib_local_table->tb_lookup(ip_fib_local_table, |
167 | &fl, &res)) { | 167 | &fl, &res)) { |
168 | ret = res.type; | 168 | ret = res.type; |
169 | fib_res_put(&res); | 169 | fib_res_put(&res); |
170 | } | 170 | } |
171 | } | 171 | } |
172 | return ret; | 172 | return ret; |
173 | } | 173 | } |
174 | 174 | ||
175 | /* Given (packet source, input interface) and optional (dst, oif, tos): | 175 | /* Given (packet source, input interface) and optional (dst, oif, tos): |
176 | - (main) check, that source is valid i.e. not broadcast or our local | 176 | - (main) check, that source is valid i.e. not broadcast or our local |
177 | address. | 177 | address. |
178 | - figure out what "logical" interface this packet arrived | 178 | - figure out what "logical" interface this packet arrived |
179 | and calculate "specific destination" address. | 179 | and calculate "specific destination" address. |
180 | - check, that packet arrived from expected physical interface. | 180 | - check, that packet arrived from expected physical interface. |
181 | */ | 181 | */ |
182 | 182 | ||
183 | int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | 183 | int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, |
184 | struct net_device *dev, __be32 *spec_dst, u32 *itag) | 184 | struct net_device *dev, __be32 *spec_dst, u32 *itag) |
185 | { | 185 | { |
186 | struct in_device *in_dev; | 186 | struct in_device *in_dev; |
187 | struct flowi fl = { .nl_u = { .ip4_u = | 187 | struct flowi fl = { .nl_u = { .ip4_u = |
188 | { .daddr = src, | 188 | { .daddr = src, |
189 | .saddr = dst, | 189 | .saddr = dst, |
190 | .tos = tos } }, | 190 | .tos = tos } }, |
191 | .iif = oif }; | 191 | .iif = oif }; |
192 | struct fib_result res; | 192 | struct fib_result res; |
193 | int no_addr, rpf; | 193 | int no_addr, rpf; |
194 | int ret; | 194 | int ret; |
195 | 195 | ||
196 | no_addr = rpf = 0; | 196 | no_addr = rpf = 0; |
197 | rcu_read_lock(); | 197 | rcu_read_lock(); |
198 | in_dev = __in_dev_get_rcu(dev); | 198 | in_dev = __in_dev_get_rcu(dev); |
199 | if (in_dev) { | 199 | if (in_dev) { |
200 | no_addr = in_dev->ifa_list == NULL; | 200 | no_addr = in_dev->ifa_list == NULL; |
201 | rpf = IN_DEV_RPFILTER(in_dev); | 201 | rpf = IN_DEV_RPFILTER(in_dev); |
202 | } | 202 | } |
203 | rcu_read_unlock(); | 203 | rcu_read_unlock(); |
204 | 204 | ||
205 | if (in_dev == NULL) | 205 | if (in_dev == NULL) |
206 | goto e_inval; | 206 | goto e_inval; |
207 | 207 | ||
208 | if (fib_lookup(&fl, &res)) | 208 | if (fib_lookup(&fl, &res)) |
209 | goto last_resort; | 209 | goto last_resort; |
210 | if (res.type != RTN_UNICAST) | 210 | if (res.type != RTN_UNICAST) |
211 | goto e_inval_res; | 211 | goto e_inval_res; |
212 | *spec_dst = FIB_RES_PREFSRC(res); | 212 | *spec_dst = FIB_RES_PREFSRC(res); |
213 | fib_combine_itag(itag, &res); | 213 | fib_combine_itag(itag, &res); |
214 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 214 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
215 | if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1) | 215 | if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1) |
216 | #else | 216 | #else |
217 | if (FIB_RES_DEV(res) == dev) | 217 | if (FIB_RES_DEV(res) == dev) |
218 | #endif | 218 | #endif |
219 | { | 219 | { |
220 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 220 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
221 | fib_res_put(&res); | 221 | fib_res_put(&res); |
222 | return ret; | 222 | return ret; |
223 | } | 223 | } |
224 | fib_res_put(&res); | 224 | fib_res_put(&res); |
225 | if (no_addr) | 225 | if (no_addr) |
226 | goto last_resort; | 226 | goto last_resort; |
227 | if (rpf) | 227 | if (rpf) |
228 | goto e_inval; | 228 | goto e_inval; |
229 | fl.oif = dev->ifindex; | 229 | fl.oif = dev->ifindex; |
230 | 230 | ||
231 | ret = 0; | 231 | ret = 0; |
232 | if (fib_lookup(&fl, &res) == 0) { | 232 | if (fib_lookup(&fl, &res) == 0) { |
233 | if (res.type == RTN_UNICAST) { | 233 | if (res.type == RTN_UNICAST) { |
234 | *spec_dst = FIB_RES_PREFSRC(res); | 234 | *spec_dst = FIB_RES_PREFSRC(res); |
235 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 235 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
236 | } | 236 | } |
237 | fib_res_put(&res); | 237 | fib_res_put(&res); |
238 | } | 238 | } |
239 | return ret; | 239 | return ret; |
240 | 240 | ||
241 | last_resort: | 241 | last_resort: |
242 | if (rpf) | 242 | if (rpf) |
243 | goto e_inval; | 243 | goto e_inval; |
244 | *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); | 244 | *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); |
245 | *itag = 0; | 245 | *itag = 0; |
246 | return 0; | 246 | return 0; |
247 | 247 | ||
248 | e_inval_res: | 248 | e_inval_res: |
249 | fib_res_put(&res); | 249 | fib_res_put(&res); |
250 | e_inval: | 250 | e_inval: |
251 | return -EINVAL; | 251 | return -EINVAL; |
252 | } | 252 | } |
253 | 253 | ||
254 | #ifndef CONFIG_IP_NOSIOCRT | 254 | #ifndef CONFIG_IP_NOSIOCRT |
255 | 255 | ||
256 | static inline __be32 sk_extract_addr(struct sockaddr *addr) | 256 | static inline __be32 sk_extract_addr(struct sockaddr *addr) |
257 | { | 257 | { |
258 | return ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 258 | return ((struct sockaddr_in *) addr)->sin_addr.s_addr; |
259 | } | 259 | } |
260 | 260 | ||
261 | static int put_rtax(struct nlattr *mx, int len, int type, u32 value) | 261 | static int put_rtax(struct nlattr *mx, int len, int type, u32 value) |
262 | { | 262 | { |
263 | struct nlattr *nla; | 263 | struct nlattr *nla; |
264 | 264 | ||
265 | nla = (struct nlattr *) ((char *) mx + len); | 265 | nla = (struct nlattr *) ((char *) mx + len); |
266 | nla->nla_type = type; | 266 | nla->nla_type = type; |
267 | nla->nla_len = nla_attr_size(4); | 267 | nla->nla_len = nla_attr_size(4); |
268 | *(u32 *) nla_data(nla) = value; | 268 | *(u32 *) nla_data(nla) = value; |
269 | 269 | ||
270 | return len + nla_total_size(4); | 270 | return len + nla_total_size(4); |
271 | } | 271 | } |
272 | 272 | ||
273 | static int rtentry_to_fib_config(int cmd, struct rtentry *rt, | 273 | static int rtentry_to_fib_config(int cmd, struct rtentry *rt, |
274 | struct fib_config *cfg) | 274 | struct fib_config *cfg) |
275 | { | 275 | { |
276 | __be32 addr; | 276 | __be32 addr; |
277 | int plen; | 277 | int plen; |
278 | 278 | ||
279 | memset(cfg, 0, sizeof(*cfg)); | 279 | memset(cfg, 0, sizeof(*cfg)); |
280 | 280 | ||
281 | if (rt->rt_dst.sa_family != AF_INET) | 281 | if (rt->rt_dst.sa_family != AF_INET) |
282 | return -EAFNOSUPPORT; | 282 | return -EAFNOSUPPORT; |
283 | 283 | ||
284 | /* | 284 | /* |
285 | * Check mask for validity: | 285 | * Check mask for validity: |
286 | * a) it must be contiguous. | 286 | * a) it must be contiguous. |
287 | * b) destination must have all host bits clear. | 287 | * b) destination must have all host bits clear. |
288 | * c) if application forgot to set correct family (AF_INET), | 288 | * c) if application forgot to set correct family (AF_INET), |
289 | * reject request unless it is absolutely clear i.e. | 289 | * reject request unless it is absolutely clear i.e. |
290 | * both family and mask are zero. | 290 | * both family and mask are zero. |
291 | */ | 291 | */ |
292 | plen = 32; | 292 | plen = 32; |
293 | addr = sk_extract_addr(&rt->rt_dst); | 293 | addr = sk_extract_addr(&rt->rt_dst); |
294 | if (!(rt->rt_flags & RTF_HOST)) { | 294 | if (!(rt->rt_flags & RTF_HOST)) { |
295 | __be32 mask = sk_extract_addr(&rt->rt_genmask); | 295 | __be32 mask = sk_extract_addr(&rt->rt_genmask); |
296 | 296 | ||
297 | if (rt->rt_genmask.sa_family != AF_INET) { | 297 | if (rt->rt_genmask.sa_family != AF_INET) { |
298 | if (mask || rt->rt_genmask.sa_family) | 298 | if (mask || rt->rt_genmask.sa_family) |
299 | return -EAFNOSUPPORT; | 299 | return -EAFNOSUPPORT; |
300 | } | 300 | } |
301 | 301 | ||
302 | if (bad_mask(mask, addr)) | 302 | if (bad_mask(mask, addr)) |
303 | return -EINVAL; | 303 | return -EINVAL; |
304 | 304 | ||
305 | plen = inet_mask_len(mask); | 305 | plen = inet_mask_len(mask); |
306 | } | 306 | } |
307 | 307 | ||
308 | cfg->fc_dst_len = plen; | 308 | cfg->fc_dst_len = plen; |
309 | cfg->fc_dst = addr; | 309 | cfg->fc_dst = addr; |
310 | 310 | ||
311 | if (cmd != SIOCDELRT) { | 311 | if (cmd != SIOCDELRT) { |
312 | cfg->fc_nlflags = NLM_F_CREATE; | 312 | cfg->fc_nlflags = NLM_F_CREATE; |
313 | cfg->fc_protocol = RTPROT_BOOT; | 313 | cfg->fc_protocol = RTPROT_BOOT; |
314 | } | 314 | } |
315 | 315 | ||
316 | if (rt->rt_metric) | 316 | if (rt->rt_metric) |
317 | cfg->fc_priority = rt->rt_metric - 1; | 317 | cfg->fc_priority = rt->rt_metric - 1; |
318 | 318 | ||
319 | if (rt->rt_flags & RTF_REJECT) { | 319 | if (rt->rt_flags & RTF_REJECT) { |
320 | cfg->fc_scope = RT_SCOPE_HOST; | 320 | cfg->fc_scope = RT_SCOPE_HOST; |
321 | cfg->fc_type = RTN_UNREACHABLE; | 321 | cfg->fc_type = RTN_UNREACHABLE; |
322 | return 0; | 322 | return 0; |
323 | } | 323 | } |
324 | 324 | ||
325 | cfg->fc_scope = RT_SCOPE_NOWHERE; | 325 | cfg->fc_scope = RT_SCOPE_NOWHERE; |
326 | cfg->fc_type = RTN_UNICAST; | 326 | cfg->fc_type = RTN_UNICAST; |
327 | 327 | ||
328 | if (rt->rt_dev) { | 328 | if (rt->rt_dev) { |
329 | char *colon; | 329 | char *colon; |
330 | struct net_device *dev; | 330 | struct net_device *dev; |
331 | char devname[IFNAMSIZ]; | 331 | char devname[IFNAMSIZ]; |
332 | 332 | ||
333 | if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1)) | 333 | if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1)) |
334 | return -EFAULT; | 334 | return -EFAULT; |
335 | 335 | ||
336 | devname[IFNAMSIZ-1] = 0; | 336 | devname[IFNAMSIZ-1] = 0; |
337 | colon = strchr(devname, ':'); | 337 | colon = strchr(devname, ':'); |
338 | if (colon) | 338 | if (colon) |
339 | *colon = 0; | 339 | *colon = 0; |
340 | dev = __dev_get_by_name(devname); | 340 | dev = __dev_get_by_name(devname); |
341 | if (!dev) | 341 | if (!dev) |
342 | return -ENODEV; | 342 | return -ENODEV; |
343 | cfg->fc_oif = dev->ifindex; | 343 | cfg->fc_oif = dev->ifindex; |
344 | if (colon) { | 344 | if (colon) { |
345 | struct in_ifaddr *ifa; | 345 | struct in_ifaddr *ifa; |
346 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 346 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
347 | if (!in_dev) | 347 | if (!in_dev) |
348 | return -ENODEV; | 348 | return -ENODEV; |
349 | *colon = ':'; | 349 | *colon = ':'; |
350 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) | 350 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) |
351 | if (strcmp(ifa->ifa_label, devname) == 0) | 351 | if (strcmp(ifa->ifa_label, devname) == 0) |
352 | break; | 352 | break; |
353 | if (ifa == NULL) | 353 | if (ifa == NULL) |
354 | return -ENODEV; | 354 | return -ENODEV; |
355 | cfg->fc_prefsrc = ifa->ifa_local; | 355 | cfg->fc_prefsrc = ifa->ifa_local; |
356 | } | 356 | } |
357 | } | 357 | } |
358 | 358 | ||
359 | addr = sk_extract_addr(&rt->rt_gateway); | 359 | addr = sk_extract_addr(&rt->rt_gateway); |
360 | if (rt->rt_gateway.sa_family == AF_INET && addr) { | 360 | if (rt->rt_gateway.sa_family == AF_INET && addr) { |
361 | cfg->fc_gw = addr; | 361 | cfg->fc_gw = addr; |
362 | if (rt->rt_flags & RTF_GATEWAY && | 362 | if (rt->rt_flags & RTF_GATEWAY && |
363 | inet_addr_type(addr) == RTN_UNICAST) | 363 | inet_addr_type(addr) == RTN_UNICAST) |
364 | cfg->fc_scope = RT_SCOPE_UNIVERSE; | 364 | cfg->fc_scope = RT_SCOPE_UNIVERSE; |
365 | } | 365 | } |
366 | 366 | ||
367 | if (cmd == SIOCDELRT) | 367 | if (cmd == SIOCDELRT) |
368 | return 0; | 368 | return 0; |
369 | 369 | ||
370 | if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw) | 370 | if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw) |
371 | return -EINVAL; | 371 | return -EINVAL; |
372 | 372 | ||
373 | if (cfg->fc_scope == RT_SCOPE_NOWHERE) | 373 | if (cfg->fc_scope == RT_SCOPE_NOWHERE) |
374 | cfg->fc_scope = RT_SCOPE_LINK; | 374 | cfg->fc_scope = RT_SCOPE_LINK; |
375 | 375 | ||
376 | if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) { | 376 | if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) { |
377 | struct nlattr *mx; | 377 | struct nlattr *mx; |
378 | int len = 0; | 378 | int len = 0; |
379 | 379 | ||
380 | mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); | 380 | mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); |
381 | if (mx == NULL) | 381 | if (mx == NULL) |
382 | return -ENOMEM; | 382 | return -ENOMEM; |
383 | 383 | ||
384 | if (rt->rt_flags & RTF_MTU) | 384 | if (rt->rt_flags & RTF_MTU) |
385 | len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40); | 385 | len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40); |
386 | 386 | ||
387 | if (rt->rt_flags & RTF_WINDOW) | 387 | if (rt->rt_flags & RTF_WINDOW) |
388 | len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window); | 388 | len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window); |
389 | 389 | ||
390 | if (rt->rt_flags & RTF_IRTT) | 390 | if (rt->rt_flags & RTF_IRTT) |
391 | len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3); | 391 | len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3); |
392 | 392 | ||
393 | cfg->fc_mx = mx; | 393 | cfg->fc_mx = mx; |
394 | cfg->fc_mx_len = len; | 394 | cfg->fc_mx_len = len; |
395 | } | 395 | } |
396 | 396 | ||
397 | return 0; | 397 | return 0; |
398 | } | 398 | } |
399 | 399 | ||
400 | /* | 400 | /* |
401 | * Handle IP routing ioctl calls. These are used to manipulate the routing tables | 401 | * Handle IP routing ioctl calls. These are used to manipulate the routing tables |
402 | */ | 402 | */ |
403 | 403 | ||
404 | int ip_rt_ioctl(unsigned int cmd, void __user *arg) | 404 | int ip_rt_ioctl(unsigned int cmd, void __user *arg) |
405 | { | 405 | { |
406 | struct fib_config cfg; | 406 | struct fib_config cfg; |
407 | struct rtentry rt; | 407 | struct rtentry rt; |
408 | int err; | 408 | int err; |
409 | 409 | ||
410 | switch (cmd) { | 410 | switch (cmd) { |
411 | case SIOCADDRT: /* Add a route */ | 411 | case SIOCADDRT: /* Add a route */ |
412 | case SIOCDELRT: /* Delete a route */ | 412 | case SIOCDELRT: /* Delete a route */ |
413 | if (!capable(CAP_NET_ADMIN)) | 413 | if (!capable(CAP_NET_ADMIN)) |
414 | return -EPERM; | 414 | return -EPERM; |
415 | 415 | ||
416 | if (copy_from_user(&rt, arg, sizeof(rt))) | 416 | if (copy_from_user(&rt, arg, sizeof(rt))) |
417 | return -EFAULT; | 417 | return -EFAULT; |
418 | 418 | ||
419 | rtnl_lock(); | 419 | rtnl_lock(); |
420 | err = rtentry_to_fib_config(cmd, &rt, &cfg); | 420 | err = rtentry_to_fib_config(cmd, &rt, &cfg); |
421 | if (err == 0) { | 421 | if (err == 0) { |
422 | struct fib_table *tb; | 422 | struct fib_table *tb; |
423 | 423 | ||
424 | if (cmd == SIOCDELRT) { | 424 | if (cmd == SIOCDELRT) { |
425 | tb = fib_get_table(cfg.fc_table); | 425 | tb = fib_get_table(cfg.fc_table); |
426 | if (tb) | 426 | if (tb) |
427 | err = tb->tb_delete(tb, &cfg); | 427 | err = tb->tb_delete(tb, &cfg); |
428 | else | 428 | else |
429 | err = -ESRCH; | 429 | err = -ESRCH; |
430 | } else { | 430 | } else { |
431 | tb = fib_new_table(cfg.fc_table); | 431 | tb = fib_new_table(cfg.fc_table); |
432 | if (tb) | 432 | if (tb) |
433 | err = tb->tb_insert(tb, &cfg); | 433 | err = tb->tb_insert(tb, &cfg); |
434 | else | 434 | else |
435 | err = -ENOBUFS; | 435 | err = -ENOBUFS; |
436 | } | 436 | } |
437 | 437 | ||
438 | /* allocated by rtentry_to_fib_config() */ | 438 | /* allocated by rtentry_to_fib_config() */ |
439 | kfree(cfg.fc_mx); | 439 | kfree(cfg.fc_mx); |
440 | } | 440 | } |
441 | rtnl_unlock(); | 441 | rtnl_unlock(); |
442 | return err; | 442 | return err; |
443 | } | 443 | } |
444 | return -EINVAL; | 444 | return -EINVAL; |
445 | } | 445 | } |
446 | 446 | ||
447 | #else | 447 | #else |
448 | 448 | ||
449 | int ip_rt_ioctl(unsigned int cmd, void *arg) | 449 | int ip_rt_ioctl(unsigned int cmd, void *arg) |
450 | { | 450 | { |
451 | return -EINVAL; | 451 | return -EINVAL; |
452 | } | 452 | } |
453 | 453 | ||
454 | #endif | 454 | #endif |
455 | 455 | ||
456 | struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { | 456 | struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { |
457 | [RTA_DST] = { .type = NLA_U32 }, | 457 | [RTA_DST] = { .type = NLA_U32 }, |
458 | [RTA_SRC] = { .type = NLA_U32 }, | 458 | [RTA_SRC] = { .type = NLA_U32 }, |
459 | [RTA_IIF] = { .type = NLA_U32 }, | 459 | [RTA_IIF] = { .type = NLA_U32 }, |
460 | [RTA_OIF] = { .type = NLA_U32 }, | 460 | [RTA_OIF] = { .type = NLA_U32 }, |
461 | [RTA_GATEWAY] = { .type = NLA_U32 }, | 461 | [RTA_GATEWAY] = { .type = NLA_U32 }, |
462 | [RTA_PRIORITY] = { .type = NLA_U32 }, | 462 | [RTA_PRIORITY] = { .type = NLA_U32 }, |
463 | [RTA_PREFSRC] = { .type = NLA_U32 }, | 463 | [RTA_PREFSRC] = { .type = NLA_U32 }, |
464 | [RTA_METRICS] = { .type = NLA_NESTED }, | 464 | [RTA_METRICS] = { .type = NLA_NESTED }, |
465 | [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, | 465 | [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, |
466 | [RTA_PROTOINFO] = { .type = NLA_U32 }, | 466 | [RTA_PROTOINFO] = { .type = NLA_U32 }, |
467 | [RTA_FLOW] = { .type = NLA_U32 }, | 467 | [RTA_FLOW] = { .type = NLA_U32 }, |
468 | [RTA_MP_ALGO] = { .type = NLA_U32 }, | 468 | [RTA_MP_ALGO] = { .type = NLA_U32 }, |
469 | }; | 469 | }; |
470 | 470 | ||
471 | static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, | 471 | static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, |
472 | struct fib_config *cfg) | 472 | struct fib_config *cfg) |
473 | { | 473 | { |
474 | struct nlattr *attr; | 474 | struct nlattr *attr; |
475 | int err, remaining; | 475 | int err, remaining; |
476 | struct rtmsg *rtm; | 476 | struct rtmsg *rtm; |
477 | 477 | ||
478 | err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy); | 478 | err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy); |
479 | if (err < 0) | 479 | if (err < 0) |
480 | goto errout; | 480 | goto errout; |
481 | 481 | ||
482 | memset(cfg, 0, sizeof(*cfg)); | 482 | memset(cfg, 0, sizeof(*cfg)); |
483 | 483 | ||
484 | rtm = nlmsg_data(nlh); | 484 | rtm = nlmsg_data(nlh); |
485 | cfg->fc_dst_len = rtm->rtm_dst_len; | 485 | cfg->fc_dst_len = rtm->rtm_dst_len; |
486 | cfg->fc_tos = rtm->rtm_tos; | 486 | cfg->fc_tos = rtm->rtm_tos; |
487 | cfg->fc_table = rtm->rtm_table; | 487 | cfg->fc_table = rtm->rtm_table; |
488 | cfg->fc_protocol = rtm->rtm_protocol; | 488 | cfg->fc_protocol = rtm->rtm_protocol; |
489 | cfg->fc_scope = rtm->rtm_scope; | 489 | cfg->fc_scope = rtm->rtm_scope; |
490 | cfg->fc_type = rtm->rtm_type; | 490 | cfg->fc_type = rtm->rtm_type; |
491 | cfg->fc_flags = rtm->rtm_flags; | 491 | cfg->fc_flags = rtm->rtm_flags; |
492 | cfg->fc_nlflags = nlh->nlmsg_flags; | 492 | cfg->fc_nlflags = nlh->nlmsg_flags; |
493 | 493 | ||
494 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | 494 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; |
495 | cfg->fc_nlinfo.nlh = nlh; | 495 | cfg->fc_nlinfo.nlh = nlh; |
496 | 496 | ||
497 | nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { | 497 | nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { |
498 | switch (attr->nla_type) { | 498 | switch (attr->nla_type) { |
499 | case RTA_DST: | 499 | case RTA_DST: |
500 | cfg->fc_dst = nla_get_be32(attr); | 500 | cfg->fc_dst = nla_get_be32(attr); |
501 | break; | 501 | break; |
502 | case RTA_OIF: | 502 | case RTA_OIF: |
503 | cfg->fc_oif = nla_get_u32(attr); | 503 | cfg->fc_oif = nla_get_u32(attr); |
504 | break; | 504 | break; |
505 | case RTA_GATEWAY: | 505 | case RTA_GATEWAY: |
506 | cfg->fc_gw = nla_get_be32(attr); | 506 | cfg->fc_gw = nla_get_be32(attr); |
507 | break; | 507 | break; |
508 | case RTA_PRIORITY: | 508 | case RTA_PRIORITY: |
509 | cfg->fc_priority = nla_get_u32(attr); | 509 | cfg->fc_priority = nla_get_u32(attr); |
510 | break; | 510 | break; |
511 | case RTA_PREFSRC: | 511 | case RTA_PREFSRC: |
512 | cfg->fc_prefsrc = nla_get_be32(attr); | 512 | cfg->fc_prefsrc = nla_get_be32(attr); |
513 | break; | 513 | break; |
514 | case RTA_METRICS: | 514 | case RTA_METRICS: |
515 | cfg->fc_mx = nla_data(attr); | 515 | cfg->fc_mx = nla_data(attr); |
516 | cfg->fc_mx_len = nla_len(attr); | 516 | cfg->fc_mx_len = nla_len(attr); |
517 | break; | 517 | break; |
518 | case RTA_MULTIPATH: | 518 | case RTA_MULTIPATH: |
519 | cfg->fc_mp = nla_data(attr); | 519 | cfg->fc_mp = nla_data(attr); |
520 | cfg->fc_mp_len = nla_len(attr); | 520 | cfg->fc_mp_len = nla_len(attr); |
521 | break; | 521 | break; |
522 | case RTA_FLOW: | 522 | case RTA_FLOW: |
523 | cfg->fc_flow = nla_get_u32(attr); | 523 | cfg->fc_flow = nla_get_u32(attr); |
524 | break; | 524 | break; |
525 | case RTA_MP_ALGO: | 525 | case RTA_MP_ALGO: |
526 | cfg->fc_mp_alg = nla_get_u32(attr); | 526 | cfg->fc_mp_alg = nla_get_u32(attr); |
527 | break; | 527 | break; |
528 | case RTA_TABLE: | 528 | case RTA_TABLE: |
529 | cfg->fc_table = nla_get_u32(attr); | 529 | cfg->fc_table = nla_get_u32(attr); |
530 | break; | 530 | break; |
531 | } | 531 | } |
532 | } | 532 | } |
533 | 533 | ||
534 | return 0; | 534 | return 0; |
535 | errout: | 535 | errout: |
536 | return err; | 536 | return err; |
537 | } | 537 | } |
538 | 538 | ||
539 | int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 539 | int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
540 | { | 540 | { |
541 | struct fib_config cfg; | 541 | struct fib_config cfg; |
542 | struct fib_table *tb; | 542 | struct fib_table *tb; |
543 | int err; | 543 | int err; |
544 | 544 | ||
545 | err = rtm_to_fib_config(skb, nlh, &cfg); | 545 | err = rtm_to_fib_config(skb, nlh, &cfg); |
546 | if (err < 0) | 546 | if (err < 0) |
547 | goto errout; | 547 | goto errout; |
548 | 548 | ||
549 | tb = fib_get_table(cfg.fc_table); | 549 | tb = fib_get_table(cfg.fc_table); |
550 | if (tb == NULL) { | 550 | if (tb == NULL) { |
551 | err = -ESRCH; | 551 | err = -ESRCH; |
552 | goto errout; | 552 | goto errout; |
553 | } | 553 | } |
554 | 554 | ||
555 | err = tb->tb_delete(tb, &cfg); | 555 | err = tb->tb_delete(tb, &cfg); |
556 | errout: | 556 | errout: |
557 | return err; | 557 | return err; |
558 | } | 558 | } |
559 | 559 | ||
560 | int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 560 | int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
561 | { | 561 | { |
562 | struct fib_config cfg; | 562 | struct fib_config cfg; |
563 | struct fib_table *tb; | 563 | struct fib_table *tb; |
564 | int err; | 564 | int err; |
565 | 565 | ||
566 | err = rtm_to_fib_config(skb, nlh, &cfg); | 566 | err = rtm_to_fib_config(skb, nlh, &cfg); |
567 | if (err < 0) | 567 | if (err < 0) |
568 | goto errout; | 568 | goto errout; |
569 | 569 | ||
570 | tb = fib_new_table(cfg.fc_table); | 570 | tb = fib_new_table(cfg.fc_table); |
571 | if (tb == NULL) { | 571 | if (tb == NULL) { |
572 | err = -ENOBUFS; | 572 | err = -ENOBUFS; |
573 | goto errout; | 573 | goto errout; |
574 | } | 574 | } |
575 | 575 | ||
576 | err = tb->tb_insert(tb, &cfg); | 576 | err = tb->tb_insert(tb, &cfg); |
577 | errout: | 577 | errout: |
578 | return err; | 578 | return err; |
579 | } | 579 | } |
580 | 580 | ||
581 | int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | 581 | int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) |
582 | { | 582 | { |
583 | unsigned int h, s_h; | 583 | unsigned int h, s_h; |
584 | unsigned int e = 0, s_e; | 584 | unsigned int e = 0, s_e; |
585 | struct fib_table *tb; | 585 | struct fib_table *tb; |
586 | struct hlist_node *node; | 586 | struct hlist_node *node; |
587 | int dumped = 0; | 587 | int dumped = 0; |
588 | 588 | ||
589 | if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && | 589 | if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && |
590 | ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) | 590 | ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) |
591 | return ip_rt_dump(skb, cb); | 591 | return ip_rt_dump(skb, cb); |
592 | 592 | ||
593 | s_h = cb->args[0]; | 593 | s_h = cb->args[0]; |
594 | s_e = cb->args[1]; | 594 | s_e = cb->args[1]; |
595 | 595 | ||
596 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { | 596 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { |
597 | e = 0; | 597 | e = 0; |
598 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) { | 598 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) { |
599 | if (e < s_e) | 599 | if (e < s_e) |
600 | goto next; | 600 | goto next; |
601 | if (dumped) | 601 | if (dumped) |
602 | memset(&cb->args[2], 0, sizeof(cb->args) - | 602 | memset(&cb->args[2], 0, sizeof(cb->args) - |
603 | 2 * sizeof(cb->args[0])); | 603 | 2 * sizeof(cb->args[0])); |
604 | if (tb->tb_dump(tb, skb, cb) < 0) | 604 | if (tb->tb_dump(tb, skb, cb) < 0) |
605 | goto out; | 605 | goto out; |
606 | dumped = 1; | 606 | dumped = 1; |
607 | next: | 607 | next: |
608 | e++; | 608 | e++; |
609 | } | 609 | } |
610 | } | 610 | } |
611 | out: | 611 | out: |
612 | cb->args[1] = e; | 612 | cb->args[1] = e; |
613 | cb->args[0] = h; | 613 | cb->args[0] = h; |
614 | 614 | ||
615 | return skb->len; | 615 | return skb->len; |
616 | } | 616 | } |
617 | 617 | ||
618 | /* Prepare and feed intra-kernel routing request. | 618 | /* Prepare and feed intra-kernel routing request. |
619 | Really, it should be netlink message, but :-( netlink | 619 | Really, it should be netlink message, but :-( netlink |
620 | can be not configured, so that we feed it directly | 620 | can be not configured, so that we feed it directly |
621 | to fib engine. It is legal, because all events occur | 621 | to fib engine. It is legal, because all events occur |
622 | only when netlink is already locked. | 622 | only when netlink is already locked. |
623 | */ | 623 | */ |
624 | 624 | ||
625 | static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) | 625 | static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) |
626 | { | 626 | { |
627 | struct fib_table *tb; | 627 | struct fib_table *tb; |
628 | struct fib_config cfg = { | 628 | struct fib_config cfg = { |
629 | .fc_protocol = RTPROT_KERNEL, | 629 | .fc_protocol = RTPROT_KERNEL, |
630 | .fc_type = type, | 630 | .fc_type = type, |
631 | .fc_dst = dst, | 631 | .fc_dst = dst, |
632 | .fc_dst_len = dst_len, | 632 | .fc_dst_len = dst_len, |
633 | .fc_prefsrc = ifa->ifa_local, | 633 | .fc_prefsrc = ifa->ifa_local, |
634 | .fc_oif = ifa->ifa_dev->dev->ifindex, | 634 | .fc_oif = ifa->ifa_dev->dev->ifindex, |
635 | .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, | 635 | .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, |
636 | }; | 636 | }; |
637 | 637 | ||
638 | if (type == RTN_UNICAST) | 638 | if (type == RTN_UNICAST) |
639 | tb = fib_new_table(RT_TABLE_MAIN); | 639 | tb = fib_new_table(RT_TABLE_MAIN); |
640 | else | 640 | else |
641 | tb = fib_new_table(RT_TABLE_LOCAL); | 641 | tb = fib_new_table(RT_TABLE_LOCAL); |
642 | 642 | ||
643 | if (tb == NULL) | 643 | if (tb == NULL) |
644 | return; | 644 | return; |
645 | 645 | ||
646 | cfg.fc_table = tb->tb_id; | 646 | cfg.fc_table = tb->tb_id; |
647 | 647 | ||
648 | if (type != RTN_LOCAL) | 648 | if (type != RTN_LOCAL) |
649 | cfg.fc_scope = RT_SCOPE_LINK; | 649 | cfg.fc_scope = RT_SCOPE_LINK; |
650 | else | 650 | else |
651 | cfg.fc_scope = RT_SCOPE_HOST; | 651 | cfg.fc_scope = RT_SCOPE_HOST; |
652 | 652 | ||
653 | if (cmd == RTM_NEWROUTE) | 653 | if (cmd == RTM_NEWROUTE) |
654 | tb->tb_insert(tb, &cfg); | 654 | tb->tb_insert(tb, &cfg); |
655 | else | 655 | else |
656 | tb->tb_delete(tb, &cfg); | 656 | tb->tb_delete(tb, &cfg); |
657 | } | 657 | } |
658 | 658 | ||
659 | void fib_add_ifaddr(struct in_ifaddr *ifa) | 659 | void fib_add_ifaddr(struct in_ifaddr *ifa) |
660 | { | 660 | { |
661 | struct in_device *in_dev = ifa->ifa_dev; | 661 | struct in_device *in_dev = ifa->ifa_dev; |
662 | struct net_device *dev = in_dev->dev; | 662 | struct net_device *dev = in_dev->dev; |
663 | struct in_ifaddr *prim = ifa; | 663 | struct in_ifaddr *prim = ifa; |
664 | __be32 mask = ifa->ifa_mask; | 664 | __be32 mask = ifa->ifa_mask; |
665 | __be32 addr = ifa->ifa_local; | 665 | __be32 addr = ifa->ifa_local; |
666 | __be32 prefix = ifa->ifa_address&mask; | 666 | __be32 prefix = ifa->ifa_address&mask; |
667 | 667 | ||
668 | if (ifa->ifa_flags&IFA_F_SECONDARY) { | 668 | if (ifa->ifa_flags&IFA_F_SECONDARY) { |
669 | prim = inet_ifa_byprefix(in_dev, prefix, mask); | 669 | prim = inet_ifa_byprefix(in_dev, prefix, mask); |
670 | if (prim == NULL) { | 670 | if (prim == NULL) { |
671 | printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n"); | 671 | printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n"); |
672 | return; | 672 | return; |
673 | } | 673 | } |
674 | } | 674 | } |
675 | 675 | ||
676 | fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); | 676 | fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); |
677 | 677 | ||
678 | if (!(dev->flags&IFF_UP)) | 678 | if (!(dev->flags&IFF_UP)) |
679 | return; | 679 | return; |
680 | 680 | ||
681 | /* Add broadcast address, if it is explicitly assigned. */ | 681 | /* Add broadcast address, if it is explicitly assigned. */ |
682 | if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) | 682 | if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) |
683 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); | 683 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
684 | 684 | ||
685 | if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) && | 685 | if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) && |
686 | (prefix != addr || ifa->ifa_prefixlen < 32)) { | 686 | (prefix != addr || ifa->ifa_prefixlen < 32)) { |
687 | fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL : | 687 | fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL : |
688 | RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim); | 688 | RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim); |
689 | 689 | ||
690 | /* Add network specific broadcasts, when it takes a sense */ | 690 | /* Add network specific broadcasts, when it takes a sense */ |
691 | if (ifa->ifa_prefixlen < 31) { | 691 | if (ifa->ifa_prefixlen < 31) { |
692 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); | 692 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); |
693 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim); | 693 | fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim); |
694 | } | 694 | } |
695 | } | 695 | } |
696 | } | 696 | } |
697 | 697 | ||
698 | static void fib_del_ifaddr(struct in_ifaddr *ifa) | 698 | static void fib_del_ifaddr(struct in_ifaddr *ifa) |
699 | { | 699 | { |
700 | struct in_device *in_dev = ifa->ifa_dev; | 700 | struct in_device *in_dev = ifa->ifa_dev; |
701 | struct net_device *dev = in_dev->dev; | 701 | struct net_device *dev = in_dev->dev; |
702 | struct in_ifaddr *ifa1; | 702 | struct in_ifaddr *ifa1; |
703 | struct in_ifaddr *prim = ifa; | 703 | struct in_ifaddr *prim = ifa; |
704 | __be32 brd = ifa->ifa_address|~ifa->ifa_mask; | 704 | __be32 brd = ifa->ifa_address|~ifa->ifa_mask; |
705 | __be32 any = ifa->ifa_address&ifa->ifa_mask; | 705 | __be32 any = ifa->ifa_address&ifa->ifa_mask; |
706 | #define LOCAL_OK 1 | 706 | #define LOCAL_OK 1 |
707 | #define BRD_OK 2 | 707 | #define BRD_OK 2 |
708 | #define BRD0_OK 4 | 708 | #define BRD0_OK 4 |
709 | #define BRD1_OK 8 | 709 | #define BRD1_OK 8 |
710 | unsigned ok = 0; | 710 | unsigned ok = 0; |
711 | 711 | ||
712 | if (!(ifa->ifa_flags&IFA_F_SECONDARY)) | 712 | if (!(ifa->ifa_flags&IFA_F_SECONDARY)) |
713 | fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL : | 713 | fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL : |
714 | RTN_UNICAST, any, ifa->ifa_prefixlen, prim); | 714 | RTN_UNICAST, any, ifa->ifa_prefixlen, prim); |
715 | else { | 715 | else { |
716 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); | 716 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); |
717 | if (prim == NULL) { | 717 | if (prim == NULL) { |
718 | printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n"); | 718 | printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n"); |
719 | return; | 719 | return; |
720 | } | 720 | } |
721 | } | 721 | } |
722 | 722 | ||
723 | /* Deletion is more complicated than add. | 723 | /* Deletion is more complicated than add. |
724 | We should take care of not to delete too much :-) | 724 | We should take care of not to delete too much :-) |
725 | 725 | ||
726 | Scan address list to be sure that addresses are really gone. | 726 | Scan address list to be sure that addresses are really gone. |
727 | */ | 727 | */ |
728 | 728 | ||
729 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { | 729 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { |
730 | if (ifa->ifa_local == ifa1->ifa_local) | 730 | if (ifa->ifa_local == ifa1->ifa_local) |
731 | ok |= LOCAL_OK; | 731 | ok |= LOCAL_OK; |
732 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) | 732 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) |
733 | ok |= BRD_OK; | 733 | ok |= BRD_OK; |
734 | if (brd == ifa1->ifa_broadcast) | 734 | if (brd == ifa1->ifa_broadcast) |
735 | ok |= BRD1_OK; | 735 | ok |= BRD1_OK; |
736 | if (any == ifa1->ifa_broadcast) | 736 | if (any == ifa1->ifa_broadcast) |
737 | ok |= BRD0_OK; | 737 | ok |= BRD0_OK; |
738 | } | 738 | } |
739 | 739 | ||
740 | if (!(ok&BRD_OK)) | 740 | if (!(ok&BRD_OK)) |
741 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); | 741 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
742 | if (!(ok&BRD1_OK)) | 742 | if (!(ok&BRD1_OK)) |
743 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); | 743 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); |
744 | if (!(ok&BRD0_OK)) | 744 | if (!(ok&BRD0_OK)) |
745 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); | 745 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); |
746 | if (!(ok&LOCAL_OK)) { | 746 | if (!(ok&LOCAL_OK)) { |
747 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); | 747 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); |
748 | 748 | ||
749 | /* Check, that this local address finally disappeared. */ | 749 | /* Check, that this local address finally disappeared. */ |
750 | if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) { | 750 | if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) { |
751 | /* And the last, but not the least thing. | 751 | /* And the last, but not the least thing. |
752 | We must flush stray FIB entries. | 752 | We must flush stray FIB entries. |
753 | 753 | ||
754 | First of all, we scan fib_info list searching | 754 | First of all, we scan fib_info list searching |
755 | for stray nexthop entries, then ignite fib_flush. | 755 | for stray nexthop entries, then ignite fib_flush. |
756 | */ | 756 | */ |
757 | if (fib_sync_down(ifa->ifa_local, NULL, 0)) | 757 | if (fib_sync_down(ifa->ifa_local, NULL, 0)) |
758 | fib_flush(); | 758 | fib_flush(); |
759 | } | 759 | } |
760 | } | 760 | } |
761 | #undef LOCAL_OK | 761 | #undef LOCAL_OK |
762 | #undef BRD_OK | 762 | #undef BRD_OK |
763 | #undef BRD0_OK | 763 | #undef BRD0_OK |
764 | #undef BRD1_OK | 764 | #undef BRD1_OK |
765 | } | 765 | } |
766 | 766 | ||
767 | static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) | 767 | static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) |
768 | { | 768 | { |
769 | 769 | ||
770 | struct fib_result res; | 770 | struct fib_result res; |
771 | struct flowi fl = { .mark = frn->fl_mark, | 771 | struct flowi fl = { .mark = frn->fl_mark, |
772 | .nl_u = { .ip4_u = { .daddr = frn->fl_addr, | 772 | .nl_u = { .ip4_u = { .daddr = frn->fl_addr, |
773 | .tos = frn->fl_tos, | 773 | .tos = frn->fl_tos, |
774 | .scope = frn->fl_scope } } }; | 774 | .scope = frn->fl_scope } } }; |
775 | if (tb) { | 775 | if (tb) { |
776 | local_bh_disable(); | 776 | local_bh_disable(); |
777 | 777 | ||
778 | frn->tb_id = tb->tb_id; | 778 | frn->tb_id = tb->tb_id; |
779 | frn->err = tb->tb_lookup(tb, &fl, &res); | 779 | frn->err = tb->tb_lookup(tb, &fl, &res); |
780 | 780 | ||
781 | if (!frn->err) { | 781 | if (!frn->err) { |
782 | frn->prefixlen = res.prefixlen; | 782 | frn->prefixlen = res.prefixlen; |
783 | frn->nh_sel = res.nh_sel; | 783 | frn->nh_sel = res.nh_sel; |
784 | frn->type = res.type; | 784 | frn->type = res.type; |
785 | frn->scope = res.scope; | 785 | frn->scope = res.scope; |
786 | } | 786 | } |
787 | local_bh_enable(); | 787 | local_bh_enable(); |
788 | } | 788 | } |
789 | } | 789 | } |
790 | 790 | ||
791 | static void nl_fib_input(struct sock *sk, int len) | 791 | static void nl_fib_input(struct sock *sk, int len) |
792 | { | 792 | { |
793 | struct sk_buff *skb = NULL; | 793 | struct sk_buff *skb = NULL; |
794 | struct nlmsghdr *nlh = NULL; | 794 | struct nlmsghdr *nlh = NULL; |
795 | struct fib_result_nl *frn; | 795 | struct fib_result_nl *frn; |
796 | u32 pid; | 796 | u32 pid; |
797 | struct fib_table *tb; | 797 | struct fib_table *tb; |
798 | 798 | ||
799 | skb = skb_dequeue(&sk->sk_receive_queue); | 799 | skb = skb_dequeue(&sk->sk_receive_queue); |
800 | nlh = (struct nlmsghdr *)skb->data; | 800 | nlh = (struct nlmsghdr *)skb->data; |
801 | if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || | 801 | if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || |
802 | nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) { | 802 | nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) { |
803 | kfree_skb(skb); | 803 | kfree_skb(skb); |
804 | return; | 804 | return; |
805 | } | 805 | } |
806 | 806 | ||
807 | frn = (struct fib_result_nl *) NLMSG_DATA(nlh); | 807 | frn = (struct fib_result_nl *) NLMSG_DATA(nlh); |
808 | tb = fib_get_table(frn->tb_id_in); | 808 | tb = fib_get_table(frn->tb_id_in); |
809 | 809 | ||
810 | nl_fib_lookup(frn, tb); | 810 | nl_fib_lookup(frn, tb); |
811 | 811 | ||
812 | pid = nlh->nlmsg_pid; /*pid of sending process */ | 812 | pid = nlh->nlmsg_pid; /*pid of sending process */ |
813 | NETLINK_CB(skb).pid = 0; /* from kernel */ | 813 | NETLINK_CB(skb).pid = 0; /* from kernel */ |
814 | NETLINK_CB(skb).dst_pid = pid; | ||
815 | NETLINK_CB(skb).dst_group = 0; /* unicast */ | 814 | NETLINK_CB(skb).dst_group = 0; /* unicast */ |
816 | netlink_unicast(sk, skb, pid, MSG_DONTWAIT); | 815 | netlink_unicast(sk, skb, pid, MSG_DONTWAIT); |
817 | } | 816 | } |
818 | 817 | ||
819 | static void nl_fib_lookup_init(void) | 818 | static void nl_fib_lookup_init(void) |
820 | { | 819 | { |
821 | netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE); | 820 | netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE); |
822 | } | 821 | } |
823 | 822 | ||
824 | static void fib_disable_ip(struct net_device *dev, int force) | 823 | static void fib_disable_ip(struct net_device *dev, int force) |
825 | { | 824 | { |
826 | if (fib_sync_down(0, dev, force)) | 825 | if (fib_sync_down(0, dev, force)) |
827 | fib_flush(); | 826 | fib_flush(); |
828 | rt_cache_flush(0); | 827 | rt_cache_flush(0); |
829 | arp_ifdown(dev); | 828 | arp_ifdown(dev); |
830 | } | 829 | } |
831 | 830 | ||
832 | static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) | 831 | static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) |
833 | { | 832 | { |
834 | struct in_ifaddr *ifa = (struct in_ifaddr*)ptr; | 833 | struct in_ifaddr *ifa = (struct in_ifaddr*)ptr; |
835 | 834 | ||
836 | switch (event) { | 835 | switch (event) { |
837 | case NETDEV_UP: | 836 | case NETDEV_UP: |
838 | fib_add_ifaddr(ifa); | 837 | fib_add_ifaddr(ifa); |
839 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 838 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
840 | fib_sync_up(ifa->ifa_dev->dev); | 839 | fib_sync_up(ifa->ifa_dev->dev); |
841 | #endif | 840 | #endif |
842 | rt_cache_flush(-1); | 841 | rt_cache_flush(-1); |
843 | break; | 842 | break; |
844 | case NETDEV_DOWN: | 843 | case NETDEV_DOWN: |
845 | fib_del_ifaddr(ifa); | 844 | fib_del_ifaddr(ifa); |
846 | if (ifa->ifa_dev->ifa_list == NULL) { | 845 | if (ifa->ifa_dev->ifa_list == NULL) { |
847 | /* Last address was deleted from this interface. | 846 | /* Last address was deleted from this interface. |
848 | Disable IP. | 847 | Disable IP. |
849 | */ | 848 | */ |
850 | fib_disable_ip(ifa->ifa_dev->dev, 1); | 849 | fib_disable_ip(ifa->ifa_dev->dev, 1); |
851 | } else { | 850 | } else { |
852 | rt_cache_flush(-1); | 851 | rt_cache_flush(-1); |
853 | } | 852 | } |
854 | break; | 853 | break; |
855 | } | 854 | } |
856 | return NOTIFY_DONE; | 855 | return NOTIFY_DONE; |
857 | } | 856 | } |
858 | 857 | ||
859 | static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) | 858 | static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) |
860 | { | 859 | { |
861 | struct net_device *dev = ptr; | 860 | struct net_device *dev = ptr; |
862 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 861 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
863 | 862 | ||
864 | if (event == NETDEV_UNREGISTER) { | 863 | if (event == NETDEV_UNREGISTER) { |
865 | fib_disable_ip(dev, 2); | 864 | fib_disable_ip(dev, 2); |
866 | return NOTIFY_DONE; | 865 | return NOTIFY_DONE; |
867 | } | 866 | } |
868 | 867 | ||
869 | if (!in_dev) | 868 | if (!in_dev) |
870 | return NOTIFY_DONE; | 869 | return NOTIFY_DONE; |
871 | 870 | ||
872 | switch (event) { | 871 | switch (event) { |
873 | case NETDEV_UP: | 872 | case NETDEV_UP: |
874 | for_ifa(in_dev) { | 873 | for_ifa(in_dev) { |
875 | fib_add_ifaddr(ifa); | 874 | fib_add_ifaddr(ifa); |
876 | } endfor_ifa(in_dev); | 875 | } endfor_ifa(in_dev); |
877 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 876 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
878 | fib_sync_up(dev); | 877 | fib_sync_up(dev); |
879 | #endif | 878 | #endif |
880 | rt_cache_flush(-1); | 879 | rt_cache_flush(-1); |
881 | break; | 880 | break; |
882 | case NETDEV_DOWN: | 881 | case NETDEV_DOWN: |
883 | fib_disable_ip(dev, 0); | 882 | fib_disable_ip(dev, 0); |
884 | break; | 883 | break; |
885 | case NETDEV_CHANGEMTU: | 884 | case NETDEV_CHANGEMTU: |
886 | case NETDEV_CHANGE: | 885 | case NETDEV_CHANGE: |
887 | rt_cache_flush(0); | 886 | rt_cache_flush(0); |
888 | break; | 887 | break; |
889 | } | 888 | } |
890 | return NOTIFY_DONE; | 889 | return NOTIFY_DONE; |
891 | } | 890 | } |
892 | 891 | ||
893 | static struct notifier_block fib_inetaddr_notifier = { | 892 | static struct notifier_block fib_inetaddr_notifier = { |
894 | .notifier_call =fib_inetaddr_event, | 893 | .notifier_call =fib_inetaddr_event, |
895 | }; | 894 | }; |
896 | 895 | ||
897 | static struct notifier_block fib_netdev_notifier = { | 896 | static struct notifier_block fib_netdev_notifier = { |
898 | .notifier_call =fib_netdev_event, | 897 | .notifier_call =fib_netdev_event, |
899 | }; | 898 | }; |
900 | 899 | ||
901 | void __init ip_fib_init(void) | 900 | void __init ip_fib_init(void) |
902 | { | 901 | { |
903 | unsigned int i; | 902 | unsigned int i; |
904 | 903 | ||
905 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) | 904 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) |
906 | INIT_HLIST_HEAD(&fib_table_hash[i]); | 905 | INIT_HLIST_HEAD(&fib_table_hash[i]); |
907 | #ifndef CONFIG_IP_MULTIPLE_TABLES | 906 | #ifndef CONFIG_IP_MULTIPLE_TABLES |
908 | ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL); | 907 | ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL); |
909 | hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]); | 908 | hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]); |
910 | ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN); | 909 | ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN); |
911 | hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]); | 910 | hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]); |
912 | #else | 911 | #else |
913 | fib4_rules_init(); | 912 | fib4_rules_init(); |
914 | #endif | 913 | #endif |
915 | 914 | ||
916 | register_netdevice_notifier(&fib_netdev_notifier); | 915 | register_netdevice_notifier(&fib_netdev_notifier); |
917 | register_inetaddr_notifier(&fib_inetaddr_notifier); | 916 | register_inetaddr_notifier(&fib_inetaddr_notifier); |
918 | nl_fib_lookup_init(); | 917 | nl_fib_lookup_init(); |
919 | } | 918 | } |
920 | 919 | ||
921 | EXPORT_SYMBOL(inet_addr_type); | 920 | EXPORT_SYMBOL(inet_addr_type); |
922 | EXPORT_SYMBOL(ip_dev_find); | 921 | EXPORT_SYMBOL(ip_dev_find); |
923 | 922 |
net/ipv4/netfilter/ip_conntrack_netlink.c
1 | /* Connection tracking via netlink socket. Allows for user space | 1 | /* Connection tracking via netlink socket. Allows for user space |
2 | * protocol helpers and general trouble making from userspace. | 2 | * protocol helpers and general trouble making from userspace. |
3 | * | 3 | * |
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> | 7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> |
8 | * | 8 | * |
9 | * I've reworked this stuff to use attributes instead of conntrack | 9 | * I've reworked this stuff to use attributes instead of conntrack |
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | 10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. |
11 | * | 11 | * |
12 | * Initial connection tracking via netlink development funded and | 12 | * Initial connection tracking via netlink development funded and |
13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) | 13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) |
14 | * | 14 | * |
15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) | 15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) |
16 | * | 16 | * |
17 | * This software may be used and distributed according to the terms | 17 | * This software may be used and distributed according to the terms |
18 | * of the GNU General Public License, incorporated herein by reference. | 18 | * of the GNU General Public License, incorporated herein by reference. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/timer.h> | 25 | #include <linux/timer.h> |
26 | #include <linux/skbuff.h> | 26 | #include <linux/skbuff.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/netlink.h> | 28 | #include <linux/netlink.h> |
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/notifier.h> | 31 | #include <linux/notifier.h> |
32 | 32 | ||
33 | #include <linux/netfilter.h> | 33 | #include <linux/netfilter.h> |
34 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 34 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
35 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 35 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
36 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 36 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
37 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 37 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
38 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | 38 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> |
39 | 39 | ||
40 | #include <linux/netfilter/nfnetlink.h> | 40 | #include <linux/netfilter/nfnetlink.h> |
41 | #include <linux/netfilter/nfnetlink_conntrack.h> | 41 | #include <linux/netfilter/nfnetlink_conntrack.h> |
42 | 42 | ||
43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
44 | 44 | ||
45 | static char __initdata version[] = "0.90"; | 45 | static char __initdata version[] = "0.90"; |
46 | 46 | ||
47 | static inline int | 47 | static inline int |
48 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | 48 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, |
49 | const struct ip_conntrack_tuple *tuple, | 49 | const struct ip_conntrack_tuple *tuple, |
50 | struct ip_conntrack_protocol *proto) | 50 | struct ip_conntrack_protocol *proto) |
51 | { | 51 | { |
52 | int ret = 0; | 52 | int ret = 0; |
53 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | 53 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); |
54 | 54 | ||
55 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | 55 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); |
56 | 56 | ||
57 | if (likely(proto->tuple_to_nfattr)) | 57 | if (likely(proto->tuple_to_nfattr)) |
58 | ret = proto->tuple_to_nfattr(skb, tuple); | 58 | ret = proto->tuple_to_nfattr(skb, tuple); |
59 | 59 | ||
60 | NFA_NEST_END(skb, nest_parms); | 60 | NFA_NEST_END(skb, nest_parms); |
61 | 61 | ||
62 | return ret; | 62 | return ret; |
63 | 63 | ||
64 | nfattr_failure: | 64 | nfattr_failure: |
65 | return -1; | 65 | return -1; |
66 | } | 66 | } |
67 | 67 | ||
68 | static inline int | 68 | static inline int |
69 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, | 69 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, |
70 | const struct ip_conntrack_tuple *tuple) | 70 | const struct ip_conntrack_tuple *tuple) |
71 | { | 71 | { |
72 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | 72 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); |
73 | 73 | ||
74 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip); | 74 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip); |
75 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip); | 75 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip); |
76 | 76 | ||
77 | NFA_NEST_END(skb, nest_parms); | 77 | NFA_NEST_END(skb, nest_parms); |
78 | 78 | ||
79 | return 0; | 79 | return 0; |
80 | 80 | ||
81 | nfattr_failure: | 81 | nfattr_failure: |
82 | return -1; | 82 | return -1; |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline int | 85 | static inline int |
86 | ctnetlink_dump_tuples(struct sk_buff *skb, | 86 | ctnetlink_dump_tuples(struct sk_buff *skb, |
87 | const struct ip_conntrack_tuple *tuple) | 87 | const struct ip_conntrack_tuple *tuple) |
88 | { | 88 | { |
89 | int ret; | 89 | int ret; |
90 | struct ip_conntrack_protocol *proto; | 90 | struct ip_conntrack_protocol *proto; |
91 | 91 | ||
92 | ret = ctnetlink_dump_tuples_ip(skb, tuple); | 92 | ret = ctnetlink_dump_tuples_ip(skb, tuple); |
93 | if (unlikely(ret < 0)) | 93 | if (unlikely(ret < 0)) |
94 | return ret; | 94 | return ret; |
95 | 95 | ||
96 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | 96 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); |
97 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); | 97 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); |
98 | ip_conntrack_proto_put(proto); | 98 | ip_conntrack_proto_put(proto); |
99 | 99 | ||
100 | return ret; | 100 | return ret; |
101 | } | 101 | } |
102 | 102 | ||
103 | static inline int | 103 | static inline int |
104 | ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) | 104 | ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) |
105 | { | 105 | { |
106 | __be32 status = htonl((u_int32_t) ct->status); | 106 | __be32 status = htonl((u_int32_t) ct->status); |
107 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); | 107 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); |
108 | return 0; | 108 | return 0; |
109 | 109 | ||
110 | nfattr_failure: | 110 | nfattr_failure: |
111 | return -1; | 111 | return -1; |
112 | } | 112 | } |
113 | 113 | ||
114 | static inline int | 114 | static inline int |
115 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct) | 115 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct) |
116 | { | 116 | { |
117 | long timeout_l = ct->timeout.expires - jiffies; | 117 | long timeout_l = ct->timeout.expires - jiffies; |
118 | __be32 timeout; | 118 | __be32 timeout; |
119 | 119 | ||
120 | if (timeout_l < 0) | 120 | if (timeout_l < 0) |
121 | timeout = 0; | 121 | timeout = 0; |
122 | else | 122 | else |
123 | timeout = htonl(timeout_l / HZ); | 123 | timeout = htonl(timeout_l / HZ); |
124 | 124 | ||
125 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); | 125 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); |
126 | return 0; | 126 | return 0; |
127 | 127 | ||
128 | nfattr_failure: | 128 | nfattr_failure: |
129 | return -1; | 129 | return -1; |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline int | 132 | static inline int |
133 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | 133 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) |
134 | { | 134 | { |
135 | struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | 135 | struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); |
136 | 136 | ||
137 | struct nfattr *nest_proto; | 137 | struct nfattr *nest_proto; |
138 | int ret; | 138 | int ret; |
139 | 139 | ||
140 | if (!proto->to_nfattr) { | 140 | if (!proto->to_nfattr) { |
141 | ip_conntrack_proto_put(proto); | 141 | ip_conntrack_proto_put(proto); |
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
144 | 144 | ||
145 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); | 145 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); |
146 | 146 | ||
147 | ret = proto->to_nfattr(skb, nest_proto, ct); | 147 | ret = proto->to_nfattr(skb, nest_proto, ct); |
148 | 148 | ||
149 | ip_conntrack_proto_put(proto); | 149 | ip_conntrack_proto_put(proto); |
150 | 150 | ||
151 | NFA_NEST_END(skb, nest_proto); | 151 | NFA_NEST_END(skb, nest_proto); |
152 | 152 | ||
153 | return ret; | 153 | return ret; |
154 | 154 | ||
155 | nfattr_failure: | 155 | nfattr_failure: |
156 | ip_conntrack_proto_put(proto); | 156 | ip_conntrack_proto_put(proto); |
157 | return -1; | 157 | return -1; |
158 | } | 158 | } |
159 | 159 | ||
160 | static inline int | 160 | static inline int |
161 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | 161 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct) |
162 | { | 162 | { |
163 | struct nfattr *nest_helper; | 163 | struct nfattr *nest_helper; |
164 | 164 | ||
165 | if (!ct->helper) | 165 | if (!ct->helper) |
166 | return 0; | 166 | return 0; |
167 | 167 | ||
168 | nest_helper = NFA_NEST(skb, CTA_HELP); | 168 | nest_helper = NFA_NEST(skb, CTA_HELP); |
169 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); | 169 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); |
170 | 170 | ||
171 | if (ct->helper->to_nfattr) | 171 | if (ct->helper->to_nfattr) |
172 | ct->helper->to_nfattr(skb, ct); | 172 | ct->helper->to_nfattr(skb, ct); |
173 | 173 | ||
174 | NFA_NEST_END(skb, nest_helper); | 174 | NFA_NEST_END(skb, nest_helper); |
175 | 175 | ||
176 | return 0; | 176 | return 0; |
177 | 177 | ||
178 | nfattr_failure: | 178 | nfattr_failure: |
179 | return -1; | 179 | return -1; |
180 | } | 180 | } |
181 | 181 | ||
182 | #ifdef CONFIG_IP_NF_CT_ACCT | 182 | #ifdef CONFIG_IP_NF_CT_ACCT |
183 | static inline int | 183 | static inline int |
184 | ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct, | 184 | ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct, |
185 | enum ip_conntrack_dir dir) | 185 | enum ip_conntrack_dir dir) |
186 | { | 186 | { |
187 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; | 187 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; |
188 | struct nfattr *nest_count = NFA_NEST(skb, type); | 188 | struct nfattr *nest_count = NFA_NEST(skb, type); |
189 | __be32 tmp; | 189 | __be32 tmp; |
190 | 190 | ||
191 | tmp = htonl(ct->counters[dir].packets); | 191 | tmp = htonl(ct->counters[dir].packets); |
192 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp); | 192 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp); |
193 | 193 | ||
194 | tmp = htonl(ct->counters[dir].bytes); | 194 | tmp = htonl(ct->counters[dir].bytes); |
195 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp); | 195 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp); |
196 | 196 | ||
197 | NFA_NEST_END(skb, nest_count); | 197 | NFA_NEST_END(skb, nest_count); |
198 | 198 | ||
199 | return 0; | 199 | return 0; |
200 | 200 | ||
201 | nfattr_failure: | 201 | nfattr_failure: |
202 | return -1; | 202 | return -1; |
203 | } | 203 | } |
204 | #else | 204 | #else |
205 | #define ctnetlink_dump_counters(a, b, c) (0) | 205 | #define ctnetlink_dump_counters(a, b, c) (0) |
206 | #endif | 206 | #endif |
207 | 207 | ||
208 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | 208 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK |
209 | static inline int | 209 | static inline int |
210 | ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct) | 210 | ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct) |
211 | { | 211 | { |
212 | __be32 mark = htonl(ct->mark); | 212 | __be32 mark = htonl(ct->mark); |
213 | 213 | ||
214 | NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark); | 214 | NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark); |
215 | return 0; | 215 | return 0; |
216 | 216 | ||
217 | nfattr_failure: | 217 | nfattr_failure: |
218 | return -1; | 218 | return -1; |
219 | } | 219 | } |
220 | #else | 220 | #else |
221 | #define ctnetlink_dump_mark(a, b) (0) | 221 | #define ctnetlink_dump_mark(a, b) (0) |
222 | #endif | 222 | #endif |
223 | 223 | ||
224 | static inline int | 224 | static inline int |
225 | ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct) | 225 | ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct) |
226 | { | 226 | { |
227 | __be32 id = htonl(ct->id); | 227 | __be32 id = htonl(ct->id); |
228 | NFA_PUT(skb, CTA_ID, sizeof(__be32), &id); | 228 | NFA_PUT(skb, CTA_ID, sizeof(__be32), &id); |
229 | return 0; | 229 | return 0; |
230 | 230 | ||
231 | nfattr_failure: | 231 | nfattr_failure: |
232 | return -1; | 232 | return -1; |
233 | } | 233 | } |
234 | 234 | ||
235 | static inline int | 235 | static inline int |
236 | ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) | 236 | ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) |
237 | { | 237 | { |
238 | __be32 use = htonl(atomic_read(&ct->ct_general.use)); | 238 | __be32 use = htonl(atomic_read(&ct->ct_general.use)); |
239 | 239 | ||
240 | NFA_PUT(skb, CTA_USE, sizeof(__be32), &use); | 240 | NFA_PUT(skb, CTA_USE, sizeof(__be32), &use); |
241 | return 0; | 241 | return 0; |
242 | 242 | ||
243 | nfattr_failure: | 243 | nfattr_failure: |
244 | return -1; | 244 | return -1; |
245 | } | 245 | } |
246 | 246 | ||
247 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) | 247 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) |
248 | 248 | ||
249 | static int | 249 | static int |
250 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | 250 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, |
251 | int event, int nowait, | 251 | int event, int nowait, |
252 | const struct ip_conntrack *ct) | 252 | const struct ip_conntrack *ct) |
253 | { | 253 | { |
254 | struct nlmsghdr *nlh; | 254 | struct nlmsghdr *nlh; |
255 | struct nfgenmsg *nfmsg; | 255 | struct nfgenmsg *nfmsg; |
256 | struct nfattr *nest_parms; | 256 | struct nfattr *nest_parms; |
257 | unsigned char *b; | 257 | unsigned char *b; |
258 | 258 | ||
259 | b = skb->tail; | 259 | b = skb->tail; |
260 | 260 | ||
261 | event |= NFNL_SUBSYS_CTNETLINK << 8; | 261 | event |= NFNL_SUBSYS_CTNETLINK << 8; |
262 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | 262 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); |
263 | nfmsg = NLMSG_DATA(nlh); | 263 | nfmsg = NLMSG_DATA(nlh); |
264 | 264 | ||
265 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | 265 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; |
266 | nfmsg->nfgen_family = AF_INET; | 266 | nfmsg->nfgen_family = AF_INET; |
267 | nfmsg->version = NFNETLINK_V0; | 267 | nfmsg->version = NFNETLINK_V0; |
268 | nfmsg->res_id = 0; | 268 | nfmsg->res_id = 0; |
269 | 269 | ||
270 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | 270 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); |
271 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | 271 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) |
272 | goto nfattr_failure; | 272 | goto nfattr_failure; |
273 | NFA_NEST_END(skb, nest_parms); | 273 | NFA_NEST_END(skb, nest_parms); |
274 | 274 | ||
275 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | 275 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); |
276 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | 276 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) |
277 | goto nfattr_failure; | 277 | goto nfattr_failure; |
278 | NFA_NEST_END(skb, nest_parms); | 278 | NFA_NEST_END(skb, nest_parms); |
279 | 279 | ||
280 | if (ctnetlink_dump_status(skb, ct) < 0 || | 280 | if (ctnetlink_dump_status(skb, ct) < 0 || |
281 | ctnetlink_dump_timeout(skb, ct) < 0 || | 281 | ctnetlink_dump_timeout(skb, ct) < 0 || |
282 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 282 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
283 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || | 283 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || |
284 | ctnetlink_dump_protoinfo(skb, ct) < 0 || | 284 | ctnetlink_dump_protoinfo(skb, ct) < 0 || |
285 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | 285 | ctnetlink_dump_helpinfo(skb, ct) < 0 || |
286 | ctnetlink_dump_mark(skb, ct) < 0 || | 286 | ctnetlink_dump_mark(skb, ct) < 0 || |
287 | ctnetlink_dump_id(skb, ct) < 0 || | 287 | ctnetlink_dump_id(skb, ct) < 0 || |
288 | ctnetlink_dump_use(skb, ct) < 0) | 288 | ctnetlink_dump_use(skb, ct) < 0) |
289 | goto nfattr_failure; | 289 | goto nfattr_failure; |
290 | 290 | ||
291 | nlh->nlmsg_len = skb->tail - b; | 291 | nlh->nlmsg_len = skb->tail - b; |
292 | return skb->len; | 292 | return skb->len; |
293 | 293 | ||
294 | nlmsg_failure: | 294 | nlmsg_failure: |
295 | nfattr_failure: | 295 | nfattr_failure: |
296 | skb_trim(skb, b - skb->data); | 296 | skb_trim(skb, b - skb->data); |
297 | return -1; | 297 | return -1; |
298 | } | 298 | } |
299 | 299 | ||
300 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 300 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
301 | static int ctnetlink_conntrack_event(struct notifier_block *this, | 301 | static int ctnetlink_conntrack_event(struct notifier_block *this, |
302 | unsigned long events, void *ptr) | 302 | unsigned long events, void *ptr) |
303 | { | 303 | { |
304 | struct nlmsghdr *nlh; | 304 | struct nlmsghdr *nlh; |
305 | struct nfgenmsg *nfmsg; | 305 | struct nfgenmsg *nfmsg; |
306 | struct nfattr *nest_parms; | 306 | struct nfattr *nest_parms; |
307 | struct ip_conntrack *ct = (struct ip_conntrack *)ptr; | 307 | struct ip_conntrack *ct = (struct ip_conntrack *)ptr; |
308 | struct sk_buff *skb; | 308 | struct sk_buff *skb; |
309 | unsigned int type; | 309 | unsigned int type; |
310 | unsigned char *b; | 310 | unsigned char *b; |
311 | unsigned int flags = 0, group; | 311 | unsigned int flags = 0, group; |
312 | 312 | ||
313 | /* ignore our fake conntrack entry */ | 313 | /* ignore our fake conntrack entry */ |
314 | if (ct == &ip_conntrack_untracked) | 314 | if (ct == &ip_conntrack_untracked) |
315 | return NOTIFY_DONE; | 315 | return NOTIFY_DONE; |
316 | 316 | ||
317 | if (events & IPCT_DESTROY) { | 317 | if (events & IPCT_DESTROY) { |
318 | type = IPCTNL_MSG_CT_DELETE; | 318 | type = IPCTNL_MSG_CT_DELETE; |
319 | group = NFNLGRP_CONNTRACK_DESTROY; | 319 | group = NFNLGRP_CONNTRACK_DESTROY; |
320 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { | 320 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { |
321 | type = IPCTNL_MSG_CT_NEW; | 321 | type = IPCTNL_MSG_CT_NEW; |
322 | flags = NLM_F_CREATE|NLM_F_EXCL; | 322 | flags = NLM_F_CREATE|NLM_F_EXCL; |
323 | /* dump everything */ | 323 | /* dump everything */ |
324 | events = ~0UL; | 324 | events = ~0UL; |
325 | group = NFNLGRP_CONNTRACK_NEW; | 325 | group = NFNLGRP_CONNTRACK_NEW; |
326 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { | 326 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { |
327 | type = IPCTNL_MSG_CT_NEW; | 327 | type = IPCTNL_MSG_CT_NEW; |
328 | group = NFNLGRP_CONNTRACK_UPDATE; | 328 | group = NFNLGRP_CONNTRACK_UPDATE; |
329 | } else | 329 | } else |
330 | return NOTIFY_DONE; | 330 | return NOTIFY_DONE; |
331 | 331 | ||
332 | if (!nfnetlink_has_listeners(group)) | 332 | if (!nfnetlink_has_listeners(group)) |
333 | return NOTIFY_DONE; | 333 | return NOTIFY_DONE; |
334 | 334 | ||
335 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 335 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
336 | if (!skb) | 336 | if (!skb) |
337 | return NOTIFY_DONE; | 337 | return NOTIFY_DONE; |
338 | 338 | ||
339 | b = skb->tail; | 339 | b = skb->tail; |
340 | 340 | ||
341 | type |= NFNL_SUBSYS_CTNETLINK << 8; | 341 | type |= NFNL_SUBSYS_CTNETLINK << 8; |
342 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | 342 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); |
343 | nfmsg = NLMSG_DATA(nlh); | 343 | nfmsg = NLMSG_DATA(nlh); |
344 | 344 | ||
345 | nlh->nlmsg_flags = flags; | 345 | nlh->nlmsg_flags = flags; |
346 | nfmsg->nfgen_family = AF_INET; | 346 | nfmsg->nfgen_family = AF_INET; |
347 | nfmsg->version = NFNETLINK_V0; | 347 | nfmsg->version = NFNETLINK_V0; |
348 | nfmsg->res_id = 0; | 348 | nfmsg->res_id = 0; |
349 | 349 | ||
350 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | 350 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); |
351 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | 351 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) |
352 | goto nfattr_failure; | 352 | goto nfattr_failure; |
353 | NFA_NEST_END(skb, nest_parms); | 353 | NFA_NEST_END(skb, nest_parms); |
354 | 354 | ||
355 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | 355 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); |
356 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | 356 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) |
357 | goto nfattr_failure; | 357 | goto nfattr_failure; |
358 | NFA_NEST_END(skb, nest_parms); | 358 | NFA_NEST_END(skb, nest_parms); |
359 | 359 | ||
360 | /* NAT stuff is now a status flag */ | 360 | /* NAT stuff is now a status flag */ |
361 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) | 361 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) |
362 | && ctnetlink_dump_status(skb, ct) < 0) | 362 | && ctnetlink_dump_status(skb, ct) < 0) |
363 | goto nfattr_failure; | 363 | goto nfattr_failure; |
364 | if (events & IPCT_REFRESH | 364 | if (events & IPCT_REFRESH |
365 | && ctnetlink_dump_timeout(skb, ct) < 0) | 365 | && ctnetlink_dump_timeout(skb, ct) < 0) |
366 | goto nfattr_failure; | 366 | goto nfattr_failure; |
367 | if (events & IPCT_PROTOINFO | 367 | if (events & IPCT_PROTOINFO |
368 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | 368 | && ctnetlink_dump_protoinfo(skb, ct) < 0) |
369 | goto nfattr_failure; | 369 | goto nfattr_failure; |
370 | if (events & IPCT_HELPINFO | 370 | if (events & IPCT_HELPINFO |
371 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | 371 | && ctnetlink_dump_helpinfo(skb, ct) < 0) |
372 | goto nfattr_failure; | 372 | goto nfattr_failure; |
373 | 373 | ||
374 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 374 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
375 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | 375 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
376 | goto nfattr_failure; | 376 | goto nfattr_failure; |
377 | 377 | ||
378 | if (events & IPCT_MARK | 378 | if (events & IPCT_MARK |
379 | && ctnetlink_dump_mark(skb, ct) < 0) | 379 | && ctnetlink_dump_mark(skb, ct) < 0) |
380 | goto nfattr_failure; | 380 | goto nfattr_failure; |
381 | 381 | ||
382 | nlh->nlmsg_len = skb->tail - b; | 382 | nlh->nlmsg_len = skb->tail - b; |
383 | nfnetlink_send(skb, 0, group, 0); | 383 | nfnetlink_send(skb, 0, group, 0); |
384 | return NOTIFY_DONE; | 384 | return NOTIFY_DONE; |
385 | 385 | ||
386 | nlmsg_failure: | 386 | nlmsg_failure: |
387 | nfattr_failure: | 387 | nfattr_failure: |
388 | kfree_skb(skb); | 388 | kfree_skb(skb); |
389 | return NOTIFY_DONE; | 389 | return NOTIFY_DONE; |
390 | } | 390 | } |
391 | #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | 391 | #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ |
392 | 392 | ||
393 | static int ctnetlink_done(struct netlink_callback *cb) | 393 | static int ctnetlink_done(struct netlink_callback *cb) |
394 | { | 394 | { |
395 | if (cb->args[1]) | 395 | if (cb->args[1]) |
396 | ip_conntrack_put((struct ip_conntrack *)cb->args[1]); | 396 | ip_conntrack_put((struct ip_conntrack *)cb->args[1]); |
397 | return 0; | 397 | return 0; |
398 | } | 398 | } |
399 | 399 | ||
400 | static int | 400 | static int |
401 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 401 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
402 | { | 402 | { |
403 | struct ip_conntrack *ct, *last; | 403 | struct ip_conntrack *ct, *last; |
404 | struct ip_conntrack_tuple_hash *h; | 404 | struct ip_conntrack_tuple_hash *h; |
405 | struct list_head *i; | 405 | struct list_head *i; |
406 | 406 | ||
407 | read_lock_bh(&ip_conntrack_lock); | 407 | read_lock_bh(&ip_conntrack_lock); |
408 | last = (struct ip_conntrack *)cb->args[1]; | 408 | last = (struct ip_conntrack *)cb->args[1]; |
409 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { | 409 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { |
410 | restart: | 410 | restart: |
411 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { | 411 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { |
412 | h = (struct ip_conntrack_tuple_hash *) i; | 412 | h = (struct ip_conntrack_tuple_hash *) i; |
413 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 413 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
414 | continue; | 414 | continue; |
415 | ct = tuplehash_to_ctrack(h); | 415 | ct = tuplehash_to_ctrack(h); |
416 | if (cb->args[1]) { | 416 | if (cb->args[1]) { |
417 | if (ct != last) | 417 | if (ct != last) |
418 | continue; | 418 | continue; |
419 | cb->args[1] = 0; | 419 | cb->args[1] = 0; |
420 | } | 420 | } |
421 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 421 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
422 | cb->nlh->nlmsg_seq, | 422 | cb->nlh->nlmsg_seq, |
423 | IPCTNL_MSG_CT_NEW, | 423 | IPCTNL_MSG_CT_NEW, |
424 | 1, ct) < 0) { | 424 | 1, ct) < 0) { |
425 | nf_conntrack_get(&ct->ct_general); | 425 | nf_conntrack_get(&ct->ct_general); |
426 | cb->args[1] = (unsigned long)ct; | 426 | cb->args[1] = (unsigned long)ct; |
427 | goto out; | 427 | goto out; |
428 | } | 428 | } |
429 | #ifdef CONFIG_NF_CT_ACCT | 429 | #ifdef CONFIG_NF_CT_ACCT |
430 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == | 430 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == |
431 | IPCTNL_MSG_CT_GET_CTRZERO) | 431 | IPCTNL_MSG_CT_GET_CTRZERO) |
432 | memset(&ct->counters, 0, sizeof(ct->counters)); | 432 | memset(&ct->counters, 0, sizeof(ct->counters)); |
433 | #endif | 433 | #endif |
434 | } | 434 | } |
435 | if (cb->args[1]) { | 435 | if (cb->args[1]) { |
436 | cb->args[1] = 0; | 436 | cb->args[1] = 0; |
437 | goto restart; | 437 | goto restart; |
438 | } | 438 | } |
439 | } | 439 | } |
440 | out: | 440 | out: |
441 | read_unlock_bh(&ip_conntrack_lock); | 441 | read_unlock_bh(&ip_conntrack_lock); |
442 | if (last) | 442 | if (last) |
443 | ip_conntrack_put(last); | 443 | ip_conntrack_put(last); |
444 | 444 | ||
445 | return skb->len; | 445 | return skb->len; |
446 | } | 446 | } |
447 | 447 | ||
448 | static const size_t cta_min_ip[CTA_IP_MAX] = { | 448 | static const size_t cta_min_ip[CTA_IP_MAX] = { |
449 | [CTA_IP_V4_SRC-1] = sizeof(__be32), | 449 | [CTA_IP_V4_SRC-1] = sizeof(__be32), |
450 | [CTA_IP_V4_DST-1] = sizeof(__be32), | 450 | [CTA_IP_V4_DST-1] = sizeof(__be32), |
451 | }; | 451 | }; |
452 | 452 | ||
453 | static inline int | 453 | static inline int |
454 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) | 454 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) |
455 | { | 455 | { |
456 | struct nfattr *tb[CTA_IP_MAX]; | 456 | struct nfattr *tb[CTA_IP_MAX]; |
457 | 457 | ||
458 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); | 458 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); |
459 | 459 | ||
460 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) | 460 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) |
461 | return -EINVAL; | 461 | return -EINVAL; |
462 | 462 | ||
463 | if (!tb[CTA_IP_V4_SRC-1]) | 463 | if (!tb[CTA_IP_V4_SRC-1]) |
464 | return -EINVAL; | 464 | return -EINVAL; |
465 | tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); | 465 | tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); |
466 | 466 | ||
467 | if (!tb[CTA_IP_V4_DST-1]) | 467 | if (!tb[CTA_IP_V4_DST-1]) |
468 | return -EINVAL; | 468 | return -EINVAL; |
469 | tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); | 469 | tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); |
470 | 470 | ||
471 | return 0; | 471 | return 0; |
472 | } | 472 | } |
473 | 473 | ||
474 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | 474 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { |
475 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), | 475 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), |
476 | [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), | 476 | [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), |
477 | [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t), | 477 | [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t), |
478 | [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), | 478 | [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), |
479 | [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), | 479 | [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), |
480 | [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t), | 480 | [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t), |
481 | }; | 481 | }; |
482 | 482 | ||
483 | static inline int | 483 | static inline int |
484 | ctnetlink_parse_tuple_proto(struct nfattr *attr, | 484 | ctnetlink_parse_tuple_proto(struct nfattr *attr, |
485 | struct ip_conntrack_tuple *tuple) | 485 | struct ip_conntrack_tuple *tuple) |
486 | { | 486 | { |
487 | struct nfattr *tb[CTA_PROTO_MAX]; | 487 | struct nfattr *tb[CTA_PROTO_MAX]; |
488 | struct ip_conntrack_protocol *proto; | 488 | struct ip_conntrack_protocol *proto; |
489 | int ret = 0; | 489 | int ret = 0; |
490 | 490 | ||
491 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); | 491 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); |
492 | 492 | ||
493 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | 493 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) |
494 | return -EINVAL; | 494 | return -EINVAL; |
495 | 495 | ||
496 | if (!tb[CTA_PROTO_NUM-1]) | 496 | if (!tb[CTA_PROTO_NUM-1]) |
497 | return -EINVAL; | 497 | return -EINVAL; |
498 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); | 498 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); |
499 | 499 | ||
500 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | 500 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); |
501 | 501 | ||
502 | if (likely(proto->nfattr_to_tuple)) | 502 | if (likely(proto->nfattr_to_tuple)) |
503 | ret = proto->nfattr_to_tuple(tb, tuple); | 503 | ret = proto->nfattr_to_tuple(tb, tuple); |
504 | 504 | ||
505 | ip_conntrack_proto_put(proto); | 505 | ip_conntrack_proto_put(proto); |
506 | 506 | ||
507 | return ret; | 507 | return ret; |
508 | } | 508 | } |
509 | 509 | ||
510 | static inline int | 510 | static inline int |
511 | ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, | 511 | ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, |
512 | enum ctattr_tuple type) | 512 | enum ctattr_tuple type) |
513 | { | 513 | { |
514 | struct nfattr *tb[CTA_TUPLE_MAX]; | 514 | struct nfattr *tb[CTA_TUPLE_MAX]; |
515 | int err; | 515 | int err; |
516 | 516 | ||
517 | memset(tuple, 0, sizeof(*tuple)); | 517 | memset(tuple, 0, sizeof(*tuple)); |
518 | 518 | ||
519 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); | 519 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); |
520 | 520 | ||
521 | if (!tb[CTA_TUPLE_IP-1]) | 521 | if (!tb[CTA_TUPLE_IP-1]) |
522 | return -EINVAL; | 522 | return -EINVAL; |
523 | 523 | ||
524 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); | 524 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); |
525 | if (err < 0) | 525 | if (err < 0) |
526 | return err; | 526 | return err; |
527 | 527 | ||
528 | if (!tb[CTA_TUPLE_PROTO-1]) | 528 | if (!tb[CTA_TUPLE_PROTO-1]) |
529 | return -EINVAL; | 529 | return -EINVAL; |
530 | 530 | ||
531 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); | 531 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); |
532 | if (err < 0) | 532 | if (err < 0) |
533 | return err; | 533 | return err; |
534 | 534 | ||
535 | /* orig and expect tuples get DIR_ORIGINAL */ | 535 | /* orig and expect tuples get DIR_ORIGINAL */ |
536 | if (type == CTA_TUPLE_REPLY) | 536 | if (type == CTA_TUPLE_REPLY) |
537 | tuple->dst.dir = IP_CT_DIR_REPLY; | 537 | tuple->dst.dir = IP_CT_DIR_REPLY; |
538 | else | 538 | else |
539 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | 539 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; |
540 | 540 | ||
541 | return 0; | 541 | return 0; |
542 | } | 542 | } |
543 | 543 | ||
544 | #ifdef CONFIG_IP_NF_NAT_NEEDED | 544 | #ifdef CONFIG_IP_NF_NAT_NEEDED |
545 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { | 545 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { |
546 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), | 546 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), |
547 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), | 547 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), |
548 | }; | 548 | }; |
549 | 549 | ||
550 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, | 550 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, |
551 | const struct ip_conntrack *ct, | 551 | const struct ip_conntrack *ct, |
552 | struct ip_nat_range *range) | 552 | struct ip_nat_range *range) |
553 | { | 553 | { |
554 | struct nfattr *tb[CTA_PROTONAT_MAX]; | 554 | struct nfattr *tb[CTA_PROTONAT_MAX]; |
555 | struct ip_nat_protocol *npt; | 555 | struct ip_nat_protocol *npt; |
556 | 556 | ||
557 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); | 557 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); |
558 | 558 | ||
559 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) | 559 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) |
560 | return -EINVAL; | 560 | return -EINVAL; |
561 | 561 | ||
562 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | 562 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); |
563 | 563 | ||
564 | if (!npt->nfattr_to_range) { | 564 | if (!npt->nfattr_to_range) { |
565 | ip_nat_proto_put(npt); | 565 | ip_nat_proto_put(npt); |
566 | return 0; | 566 | return 0; |
567 | } | 567 | } |
568 | 568 | ||
569 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ | 569 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ |
570 | if (npt->nfattr_to_range(tb, range) > 0) | 570 | if (npt->nfattr_to_range(tb, range) > 0) |
571 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | 571 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; |
572 | 572 | ||
573 | ip_nat_proto_put(npt); | 573 | ip_nat_proto_put(npt); |
574 | 574 | ||
575 | return 0; | 575 | return 0; |
576 | } | 576 | } |
577 | 577 | ||
578 | static const size_t cta_min_nat[CTA_NAT_MAX] = { | 578 | static const size_t cta_min_nat[CTA_NAT_MAX] = { |
579 | [CTA_NAT_MINIP-1] = sizeof(__be32), | 579 | [CTA_NAT_MINIP-1] = sizeof(__be32), |
580 | [CTA_NAT_MAXIP-1] = sizeof(__be32), | 580 | [CTA_NAT_MAXIP-1] = sizeof(__be32), |
581 | }; | 581 | }; |
582 | 582 | ||
583 | static inline int | 583 | static inline int |
584 | ctnetlink_parse_nat(struct nfattr *nat, | 584 | ctnetlink_parse_nat(struct nfattr *nat, |
585 | const struct ip_conntrack *ct, struct ip_nat_range *range) | 585 | const struct ip_conntrack *ct, struct ip_nat_range *range) |
586 | { | 586 | { |
587 | struct nfattr *tb[CTA_NAT_MAX]; | 587 | struct nfattr *tb[CTA_NAT_MAX]; |
588 | int err; | 588 | int err; |
589 | 589 | ||
590 | memset(range, 0, sizeof(*range)); | 590 | memset(range, 0, sizeof(*range)); |
591 | 591 | ||
592 | nfattr_parse_nested(tb, CTA_NAT_MAX, nat); | 592 | nfattr_parse_nested(tb, CTA_NAT_MAX, nat); |
593 | 593 | ||
594 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) | 594 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) |
595 | return -EINVAL; | 595 | return -EINVAL; |
596 | 596 | ||
597 | if (tb[CTA_NAT_MINIP-1]) | 597 | if (tb[CTA_NAT_MINIP-1]) |
598 | range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]); | 598 | range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]); |
599 | 599 | ||
600 | if (!tb[CTA_NAT_MAXIP-1]) | 600 | if (!tb[CTA_NAT_MAXIP-1]) |
601 | range->max_ip = range->min_ip; | 601 | range->max_ip = range->min_ip; |
602 | else | 602 | else |
603 | range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); | 603 | range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); |
604 | 604 | ||
605 | if (range->min_ip) | 605 | if (range->min_ip) |
606 | range->flags |= IP_NAT_RANGE_MAP_IPS; | 606 | range->flags |= IP_NAT_RANGE_MAP_IPS; |
607 | 607 | ||
608 | if (!tb[CTA_NAT_PROTO-1]) | 608 | if (!tb[CTA_NAT_PROTO-1]) |
609 | return 0; | 609 | return 0; |
610 | 610 | ||
611 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); | 611 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); |
612 | if (err < 0) | 612 | if (err < 0) |
613 | return err; | 613 | return err; |
614 | 614 | ||
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | #endif | 617 | #endif |
618 | 618 | ||
619 | static inline int | 619 | static inline int |
620 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) | 620 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) |
621 | { | 621 | { |
622 | struct nfattr *tb[CTA_HELP_MAX]; | 622 | struct nfattr *tb[CTA_HELP_MAX]; |
623 | 623 | ||
624 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); | 624 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); |
625 | 625 | ||
626 | if (!tb[CTA_HELP_NAME-1]) | 626 | if (!tb[CTA_HELP_NAME-1]) |
627 | return -EINVAL; | 627 | return -EINVAL; |
628 | 628 | ||
629 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); | 629 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); |
630 | 630 | ||
631 | return 0; | 631 | return 0; |
632 | } | 632 | } |
633 | 633 | ||
634 | static const size_t cta_min[CTA_MAX] = { | 634 | static const size_t cta_min[CTA_MAX] = { |
635 | [CTA_STATUS-1] = sizeof(__be32), | 635 | [CTA_STATUS-1] = sizeof(__be32), |
636 | [CTA_TIMEOUT-1] = sizeof(__be32), | 636 | [CTA_TIMEOUT-1] = sizeof(__be32), |
637 | [CTA_MARK-1] = sizeof(__be32), | 637 | [CTA_MARK-1] = sizeof(__be32), |
638 | [CTA_USE-1] = sizeof(__be32), | 638 | [CTA_USE-1] = sizeof(__be32), |
639 | [CTA_ID-1] = sizeof(__be32) | 639 | [CTA_ID-1] = sizeof(__be32) |
640 | }; | 640 | }; |
641 | 641 | ||
642 | static int | 642 | static int |
643 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | 643 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, |
644 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 644 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
645 | { | 645 | { |
646 | struct ip_conntrack_tuple_hash *h; | 646 | struct ip_conntrack_tuple_hash *h; |
647 | struct ip_conntrack_tuple tuple; | 647 | struct ip_conntrack_tuple tuple; |
648 | struct ip_conntrack *ct; | 648 | struct ip_conntrack *ct; |
649 | int err = 0; | 649 | int err = 0; |
650 | 650 | ||
651 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 651 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
652 | return -EINVAL; | 652 | return -EINVAL; |
653 | 653 | ||
654 | if (cda[CTA_TUPLE_ORIG-1]) | 654 | if (cda[CTA_TUPLE_ORIG-1]) |
655 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); | 655 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); |
656 | else if (cda[CTA_TUPLE_REPLY-1]) | 656 | else if (cda[CTA_TUPLE_REPLY-1]) |
657 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); | 657 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); |
658 | else { | 658 | else { |
659 | /* Flush the whole table */ | 659 | /* Flush the whole table */ |
660 | ip_conntrack_flush(); | 660 | ip_conntrack_flush(); |
661 | return 0; | 661 | return 0; |
662 | } | 662 | } |
663 | 663 | ||
664 | if (err < 0) | 664 | if (err < 0) |
665 | return err; | 665 | return err; |
666 | 666 | ||
667 | h = ip_conntrack_find_get(&tuple, NULL); | 667 | h = ip_conntrack_find_get(&tuple, NULL); |
668 | if (!h) | 668 | if (!h) |
669 | return -ENOENT; | 669 | return -ENOENT; |
670 | 670 | ||
671 | ct = tuplehash_to_ctrack(h); | 671 | ct = tuplehash_to_ctrack(h); |
672 | 672 | ||
673 | if (cda[CTA_ID-1]) { | 673 | if (cda[CTA_ID-1]) { |
674 | u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1])); | 674 | u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1])); |
675 | if (ct->id != id) { | 675 | if (ct->id != id) { |
676 | ip_conntrack_put(ct); | 676 | ip_conntrack_put(ct); |
677 | return -ENOENT; | 677 | return -ENOENT; |
678 | } | 678 | } |
679 | } | 679 | } |
680 | if (del_timer(&ct->timeout)) | 680 | if (del_timer(&ct->timeout)) |
681 | ct->timeout.function((unsigned long)ct); | 681 | ct->timeout.function((unsigned long)ct); |
682 | 682 | ||
683 | ip_conntrack_put(ct); | 683 | ip_conntrack_put(ct); |
684 | 684 | ||
685 | return 0; | 685 | return 0; |
686 | } | 686 | } |
687 | 687 | ||
688 | static int | 688 | static int |
689 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | 689 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, |
690 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 690 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
691 | { | 691 | { |
692 | struct ip_conntrack_tuple_hash *h; | 692 | struct ip_conntrack_tuple_hash *h; |
693 | struct ip_conntrack_tuple tuple; | 693 | struct ip_conntrack_tuple tuple; |
694 | struct ip_conntrack *ct; | 694 | struct ip_conntrack *ct; |
695 | struct sk_buff *skb2 = NULL; | 695 | struct sk_buff *skb2 = NULL; |
696 | int err = 0; | 696 | int err = 0; |
697 | 697 | ||
698 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 698 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
699 | struct nfgenmsg *msg = NLMSG_DATA(nlh); | 699 | struct nfgenmsg *msg = NLMSG_DATA(nlh); |
700 | u32 rlen; | 700 | u32 rlen; |
701 | 701 | ||
702 | if (msg->nfgen_family != AF_INET) | 702 | if (msg->nfgen_family != AF_INET) |
703 | return -EAFNOSUPPORT; | 703 | return -EAFNOSUPPORT; |
704 | 704 | ||
705 | #ifndef CONFIG_IP_NF_CT_ACCT | 705 | #ifndef CONFIG_IP_NF_CT_ACCT |
706 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) | 706 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) |
707 | return -ENOTSUPP; | 707 | return -ENOTSUPP; |
708 | #endif | 708 | #endif |
709 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 709 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
710 | ctnetlink_dump_table, | 710 | ctnetlink_dump_table, |
711 | ctnetlink_done)) != 0) | 711 | ctnetlink_done)) != 0) |
712 | return -EINVAL; | 712 | return -EINVAL; |
713 | 713 | ||
714 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 714 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
715 | if (rlen > skb->len) | 715 | if (rlen > skb->len) |
716 | rlen = skb->len; | 716 | rlen = skb->len; |
717 | skb_pull(skb, rlen); | 717 | skb_pull(skb, rlen); |
718 | return 0; | 718 | return 0; |
719 | } | 719 | } |
720 | 720 | ||
721 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 721 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
722 | return -EINVAL; | 722 | return -EINVAL; |
723 | 723 | ||
724 | if (cda[CTA_TUPLE_ORIG-1]) | 724 | if (cda[CTA_TUPLE_ORIG-1]) |
725 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); | 725 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); |
726 | else if (cda[CTA_TUPLE_REPLY-1]) | 726 | else if (cda[CTA_TUPLE_REPLY-1]) |
727 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); | 727 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); |
728 | else | 728 | else |
729 | return -EINVAL; | 729 | return -EINVAL; |
730 | 730 | ||
731 | if (err < 0) | 731 | if (err < 0) |
732 | return err; | 732 | return err; |
733 | 733 | ||
734 | h = ip_conntrack_find_get(&tuple, NULL); | 734 | h = ip_conntrack_find_get(&tuple, NULL); |
735 | if (!h) | 735 | if (!h) |
736 | return -ENOENT; | 736 | return -ENOENT; |
737 | 737 | ||
738 | ct = tuplehash_to_ctrack(h); | 738 | ct = tuplehash_to_ctrack(h); |
739 | 739 | ||
740 | err = -ENOMEM; | 740 | err = -ENOMEM; |
741 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 741 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
742 | if (!skb2) { | 742 | if (!skb2) { |
743 | ip_conntrack_put(ct); | 743 | ip_conntrack_put(ct); |
744 | return -ENOMEM; | 744 | return -ENOMEM; |
745 | } | 745 | } |
746 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | ||
747 | 746 | ||
748 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, | 747 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, |
749 | IPCTNL_MSG_CT_NEW, 1, ct); | 748 | IPCTNL_MSG_CT_NEW, 1, ct); |
750 | ip_conntrack_put(ct); | 749 | ip_conntrack_put(ct); |
751 | if (err <= 0) | 750 | if (err <= 0) |
752 | goto free; | 751 | goto free; |
753 | 752 | ||
754 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 753 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
755 | if (err < 0) | 754 | if (err < 0) |
756 | goto out; | 755 | goto out; |
757 | 756 | ||
758 | return 0; | 757 | return 0; |
759 | 758 | ||
760 | free: | 759 | free: |
761 | kfree_skb(skb2); | 760 | kfree_skb(skb2); |
762 | out: | 761 | out: |
763 | return err; | 762 | return err; |
764 | } | 763 | } |
765 | 764 | ||
766 | static inline int | 765 | static inline int |
767 | ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) | 766 | ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) |
768 | { | 767 | { |
769 | unsigned long d; | 768 | unsigned long d; |
770 | unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1])); | 769 | unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1])); |
771 | d = ct->status ^ status; | 770 | d = ct->status ^ status; |
772 | 771 | ||
773 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) | 772 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) |
774 | /* unchangeable */ | 773 | /* unchangeable */ |
775 | return -EINVAL; | 774 | return -EINVAL; |
776 | 775 | ||
777 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) | 776 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) |
778 | /* SEEN_REPLY bit can only be set */ | 777 | /* SEEN_REPLY bit can only be set */ |
779 | return -EINVAL; | 778 | return -EINVAL; |
780 | 779 | ||
781 | 780 | ||
782 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) | 781 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) |
783 | /* ASSURED bit can only be set */ | 782 | /* ASSURED bit can only be set */ |
784 | return -EINVAL; | 783 | return -EINVAL; |
785 | 784 | ||
786 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | 785 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { |
787 | #ifndef CONFIG_IP_NF_NAT_NEEDED | 786 | #ifndef CONFIG_IP_NF_NAT_NEEDED |
788 | return -EINVAL; | 787 | return -EINVAL; |
789 | #else | 788 | #else |
790 | struct ip_nat_range range; | 789 | struct ip_nat_range range; |
791 | 790 | ||
792 | if (cda[CTA_NAT_DST-1]) { | 791 | if (cda[CTA_NAT_DST-1]) { |
793 | if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, | 792 | if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, |
794 | &range) < 0) | 793 | &range) < 0) |
795 | return -EINVAL; | 794 | return -EINVAL; |
796 | if (ip_nat_initialized(ct, | 795 | if (ip_nat_initialized(ct, |
797 | HOOK2MANIP(NF_IP_PRE_ROUTING))) | 796 | HOOK2MANIP(NF_IP_PRE_ROUTING))) |
798 | return -EEXIST; | 797 | return -EEXIST; |
799 | ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | 798 | ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); |
800 | } | 799 | } |
801 | if (cda[CTA_NAT_SRC-1]) { | 800 | if (cda[CTA_NAT_SRC-1]) { |
802 | if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, | 801 | if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, |
803 | &range) < 0) | 802 | &range) < 0) |
804 | return -EINVAL; | 803 | return -EINVAL; |
805 | if (ip_nat_initialized(ct, | 804 | if (ip_nat_initialized(ct, |
806 | HOOK2MANIP(NF_IP_POST_ROUTING))) | 805 | HOOK2MANIP(NF_IP_POST_ROUTING))) |
807 | return -EEXIST; | 806 | return -EEXIST; |
808 | ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | 807 | ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); |
809 | } | 808 | } |
810 | #endif | 809 | #endif |
811 | } | 810 | } |
812 | 811 | ||
813 | /* Be careful here, modifying NAT bits can screw up things, | 812 | /* Be careful here, modifying NAT bits can screw up things, |
814 | * so don't let users modify them directly if they don't pass | 813 | * so don't let users modify them directly if they don't pass |
815 | * ip_nat_range. */ | 814 | * ip_nat_range. */ |
816 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); | 815 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); |
817 | return 0; | 816 | return 0; |
818 | } | 817 | } |
819 | 818 | ||
820 | 819 | ||
821 | static inline int | 820 | static inline int |
822 | ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) | 821 | ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) |
823 | { | 822 | { |
824 | struct ip_conntrack_helper *helper; | 823 | struct ip_conntrack_helper *helper; |
825 | char *helpname; | 824 | char *helpname; |
826 | int err; | 825 | int err; |
827 | 826 | ||
828 | /* don't change helper of sibling connections */ | 827 | /* don't change helper of sibling connections */ |
829 | if (ct->master) | 828 | if (ct->master) |
830 | return -EINVAL; | 829 | return -EINVAL; |
831 | 830 | ||
832 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); | 831 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); |
833 | if (err < 0) | 832 | if (err < 0) |
834 | return err; | 833 | return err; |
835 | 834 | ||
836 | helper = __ip_conntrack_helper_find_byname(helpname); | 835 | helper = __ip_conntrack_helper_find_byname(helpname); |
837 | if (!helper) { | 836 | if (!helper) { |
838 | if (!strcmp(helpname, "")) | 837 | if (!strcmp(helpname, "")) |
839 | helper = NULL; | 838 | helper = NULL; |
840 | else | 839 | else |
841 | return -EINVAL; | 840 | return -EINVAL; |
842 | } | 841 | } |
843 | 842 | ||
844 | if (ct->helper) { | 843 | if (ct->helper) { |
845 | if (!helper) { | 844 | if (!helper) { |
846 | /* we had a helper before ... */ | 845 | /* we had a helper before ... */ |
847 | ip_ct_remove_expectations(ct); | 846 | ip_ct_remove_expectations(ct); |
848 | ct->helper = NULL; | 847 | ct->helper = NULL; |
849 | } else { | 848 | } else { |
850 | /* need to zero data of old helper */ | 849 | /* need to zero data of old helper */ |
851 | memset(&ct->help, 0, sizeof(ct->help)); | 850 | memset(&ct->help, 0, sizeof(ct->help)); |
852 | } | 851 | } |
853 | } | 852 | } |
854 | 853 | ||
855 | ct->helper = helper; | 854 | ct->helper = helper; |
856 | 855 | ||
857 | return 0; | 856 | return 0; |
858 | } | 857 | } |
859 | 858 | ||
860 | static inline int | 859 | static inline int |
861 | ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) | 860 | ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) |
862 | { | 861 | { |
863 | u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); | 862 | u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); |
864 | 863 | ||
865 | if (!del_timer(&ct->timeout)) | 864 | if (!del_timer(&ct->timeout)) |
866 | return -ETIME; | 865 | return -ETIME; |
867 | 866 | ||
868 | ct->timeout.expires = jiffies + timeout * HZ; | 867 | ct->timeout.expires = jiffies + timeout * HZ; |
869 | add_timer(&ct->timeout); | 868 | add_timer(&ct->timeout); |
870 | 869 | ||
871 | return 0; | 870 | return 0; |
872 | } | 871 | } |
873 | 872 | ||
874 | static inline int | 873 | static inline int |
875 | ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]) | 874 | ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]) |
876 | { | 875 | { |
877 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; | 876 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; |
878 | struct ip_conntrack_protocol *proto; | 877 | struct ip_conntrack_protocol *proto; |
879 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; | 878 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; |
880 | int err = 0; | 879 | int err = 0; |
881 | 880 | ||
882 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); | 881 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); |
883 | 882 | ||
884 | proto = ip_conntrack_proto_find_get(npt); | 883 | proto = ip_conntrack_proto_find_get(npt); |
885 | 884 | ||
886 | if (proto->from_nfattr) | 885 | if (proto->from_nfattr) |
887 | err = proto->from_nfattr(tb, ct); | 886 | err = proto->from_nfattr(tb, ct); |
888 | ip_conntrack_proto_put(proto); | 887 | ip_conntrack_proto_put(proto); |
889 | 888 | ||
890 | return err; | 889 | return err; |
891 | } | 890 | } |
892 | 891 | ||
893 | static int | 892 | static int |
894 | ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) | 893 | ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) |
895 | { | 894 | { |
896 | int err; | 895 | int err; |
897 | 896 | ||
898 | if (cda[CTA_HELP-1]) { | 897 | if (cda[CTA_HELP-1]) { |
899 | err = ctnetlink_change_helper(ct, cda); | 898 | err = ctnetlink_change_helper(ct, cda); |
900 | if (err < 0) | 899 | if (err < 0) |
901 | return err; | 900 | return err; |
902 | } | 901 | } |
903 | 902 | ||
904 | if (cda[CTA_TIMEOUT-1]) { | 903 | if (cda[CTA_TIMEOUT-1]) { |
905 | err = ctnetlink_change_timeout(ct, cda); | 904 | err = ctnetlink_change_timeout(ct, cda); |
906 | if (err < 0) | 905 | if (err < 0) |
907 | return err; | 906 | return err; |
908 | } | 907 | } |
909 | 908 | ||
910 | if (cda[CTA_STATUS-1]) { | 909 | if (cda[CTA_STATUS-1]) { |
911 | err = ctnetlink_change_status(ct, cda); | 910 | err = ctnetlink_change_status(ct, cda); |
912 | if (err < 0) | 911 | if (err < 0) |
913 | return err; | 912 | return err; |
914 | } | 913 | } |
915 | 914 | ||
916 | if (cda[CTA_PROTOINFO-1]) { | 915 | if (cda[CTA_PROTOINFO-1]) { |
917 | err = ctnetlink_change_protoinfo(ct, cda); | 916 | err = ctnetlink_change_protoinfo(ct, cda); |
918 | if (err < 0) | 917 | if (err < 0) |
919 | return err; | 918 | return err; |
920 | } | 919 | } |
921 | 920 | ||
922 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | 921 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) |
923 | if (cda[CTA_MARK-1]) | 922 | if (cda[CTA_MARK-1]) |
924 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); | 923 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); |
925 | #endif | 924 | #endif |
926 | 925 | ||
927 | return 0; | 926 | return 0; |
928 | } | 927 | } |
929 | 928 | ||
930 | static int | 929 | static int |
931 | ctnetlink_create_conntrack(struct nfattr *cda[], | 930 | ctnetlink_create_conntrack(struct nfattr *cda[], |
932 | struct ip_conntrack_tuple *otuple, | 931 | struct ip_conntrack_tuple *otuple, |
933 | struct ip_conntrack_tuple *rtuple) | 932 | struct ip_conntrack_tuple *rtuple) |
934 | { | 933 | { |
935 | struct ip_conntrack *ct; | 934 | struct ip_conntrack *ct; |
936 | int err = -EINVAL; | 935 | int err = -EINVAL; |
937 | 936 | ||
938 | ct = ip_conntrack_alloc(otuple, rtuple); | 937 | ct = ip_conntrack_alloc(otuple, rtuple); |
939 | if (ct == NULL || IS_ERR(ct)) | 938 | if (ct == NULL || IS_ERR(ct)) |
940 | return -ENOMEM; | 939 | return -ENOMEM; |
941 | 940 | ||
942 | if (!cda[CTA_TIMEOUT-1]) | 941 | if (!cda[CTA_TIMEOUT-1]) |
943 | goto err; | 942 | goto err; |
944 | ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); | 943 | ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); |
945 | 944 | ||
946 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | 945 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; |
947 | ct->status |= IPS_CONFIRMED; | 946 | ct->status |= IPS_CONFIRMED; |
948 | 947 | ||
949 | err = ctnetlink_change_status(ct, cda); | 948 | err = ctnetlink_change_status(ct, cda); |
950 | if (err < 0) | 949 | if (err < 0) |
951 | goto err; | 950 | goto err; |
952 | 951 | ||
953 | if (cda[CTA_PROTOINFO-1]) { | 952 | if (cda[CTA_PROTOINFO-1]) { |
954 | err = ctnetlink_change_protoinfo(ct, cda); | 953 | err = ctnetlink_change_protoinfo(ct, cda); |
955 | if (err < 0) | 954 | if (err < 0) |
956 | return err; | 955 | return err; |
957 | } | 956 | } |
958 | 957 | ||
959 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | 958 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) |
960 | if (cda[CTA_MARK-1]) | 959 | if (cda[CTA_MARK-1]) |
961 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); | 960 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); |
962 | #endif | 961 | #endif |
963 | 962 | ||
964 | ct->helper = ip_conntrack_helper_find_get(rtuple); | 963 | ct->helper = ip_conntrack_helper_find_get(rtuple); |
965 | 964 | ||
966 | add_timer(&ct->timeout); | 965 | add_timer(&ct->timeout); |
967 | ip_conntrack_hash_insert(ct); | 966 | ip_conntrack_hash_insert(ct); |
968 | 967 | ||
969 | if (ct->helper) | 968 | if (ct->helper) |
970 | ip_conntrack_helper_put(ct->helper); | 969 | ip_conntrack_helper_put(ct->helper); |
971 | 970 | ||
972 | return 0; | 971 | return 0; |
973 | 972 | ||
974 | err: | 973 | err: |
975 | ip_conntrack_free(ct); | 974 | ip_conntrack_free(ct); |
976 | return err; | 975 | return err; |
977 | } | 976 | } |
978 | 977 | ||
979 | static int | 978 | static int |
980 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | 979 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, |
981 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 980 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
982 | { | 981 | { |
983 | struct ip_conntrack_tuple otuple, rtuple; | 982 | struct ip_conntrack_tuple otuple, rtuple; |
984 | struct ip_conntrack_tuple_hash *h = NULL; | 983 | struct ip_conntrack_tuple_hash *h = NULL; |
985 | int err = 0; | 984 | int err = 0; |
986 | 985 | ||
987 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 986 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
988 | return -EINVAL; | 987 | return -EINVAL; |
989 | 988 | ||
990 | if (cda[CTA_TUPLE_ORIG-1]) { | 989 | if (cda[CTA_TUPLE_ORIG-1]) { |
991 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG); | 990 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG); |
992 | if (err < 0) | 991 | if (err < 0) |
993 | return err; | 992 | return err; |
994 | } | 993 | } |
995 | 994 | ||
996 | if (cda[CTA_TUPLE_REPLY-1]) { | 995 | if (cda[CTA_TUPLE_REPLY-1]) { |
997 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY); | 996 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY); |
998 | if (err < 0) | 997 | if (err < 0) |
999 | return err; | 998 | return err; |
1000 | } | 999 | } |
1001 | 1000 | ||
1002 | write_lock_bh(&ip_conntrack_lock); | 1001 | write_lock_bh(&ip_conntrack_lock); |
1003 | if (cda[CTA_TUPLE_ORIG-1]) | 1002 | if (cda[CTA_TUPLE_ORIG-1]) |
1004 | h = __ip_conntrack_find(&otuple, NULL); | 1003 | h = __ip_conntrack_find(&otuple, NULL); |
1005 | else if (cda[CTA_TUPLE_REPLY-1]) | 1004 | else if (cda[CTA_TUPLE_REPLY-1]) |
1006 | h = __ip_conntrack_find(&rtuple, NULL); | 1005 | h = __ip_conntrack_find(&rtuple, NULL); |
1007 | 1006 | ||
1008 | if (h == NULL) { | 1007 | if (h == NULL) { |
1009 | write_unlock_bh(&ip_conntrack_lock); | 1008 | write_unlock_bh(&ip_conntrack_lock); |
1010 | err = -ENOENT; | 1009 | err = -ENOENT; |
1011 | if (nlh->nlmsg_flags & NLM_F_CREATE) | 1010 | if (nlh->nlmsg_flags & NLM_F_CREATE) |
1012 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); | 1011 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); |
1013 | return err; | 1012 | return err; |
1014 | } | 1013 | } |
1015 | /* implicit 'else' */ | 1014 | /* implicit 'else' */ |
1016 | 1015 | ||
1017 | /* we only allow nat config for new conntracks */ | 1016 | /* we only allow nat config for new conntracks */ |
1018 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | 1017 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { |
1019 | err = -EINVAL; | 1018 | err = -EINVAL; |
1020 | goto out_unlock; | 1019 | goto out_unlock; |
1021 | } | 1020 | } |
1022 | 1021 | ||
1023 | /* We manipulate the conntrack inside the global conntrack table lock, | 1022 | /* We manipulate the conntrack inside the global conntrack table lock, |
1024 | * so there's no need to increase the refcount */ | 1023 | * so there's no need to increase the refcount */ |
1025 | err = -EEXIST; | 1024 | err = -EEXIST; |
1026 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | 1025 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) |
1027 | err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda); | 1026 | err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda); |
1028 | 1027 | ||
1029 | out_unlock: | 1028 | out_unlock: |
1030 | write_unlock_bh(&ip_conntrack_lock); | 1029 | write_unlock_bh(&ip_conntrack_lock); |
1031 | return err; | 1030 | return err; |
1032 | } | 1031 | } |
1033 | 1032 | ||
1034 | /*********************************************************************** | 1033 | /*********************************************************************** |
1035 | * EXPECT | 1034 | * EXPECT |
1036 | ***********************************************************************/ | 1035 | ***********************************************************************/ |
1037 | 1036 | ||
1038 | static inline int | 1037 | static inline int |
1039 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, | 1038 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, |
1040 | const struct ip_conntrack_tuple *tuple, | 1039 | const struct ip_conntrack_tuple *tuple, |
1041 | enum ctattr_expect type) | 1040 | enum ctattr_expect type) |
1042 | { | 1041 | { |
1043 | struct nfattr *nest_parms = NFA_NEST(skb, type); | 1042 | struct nfattr *nest_parms = NFA_NEST(skb, type); |
1044 | 1043 | ||
1045 | if (ctnetlink_dump_tuples(skb, tuple) < 0) | 1044 | if (ctnetlink_dump_tuples(skb, tuple) < 0) |
1046 | goto nfattr_failure; | 1045 | goto nfattr_failure; |
1047 | 1046 | ||
1048 | NFA_NEST_END(skb, nest_parms); | 1047 | NFA_NEST_END(skb, nest_parms); |
1049 | 1048 | ||
1050 | return 0; | 1049 | return 0; |
1051 | 1050 | ||
1052 | nfattr_failure: | 1051 | nfattr_failure: |
1053 | return -1; | 1052 | return -1; |
1054 | } | 1053 | } |
1055 | 1054 | ||
1056 | static inline int | 1055 | static inline int |
1057 | ctnetlink_exp_dump_mask(struct sk_buff *skb, | 1056 | ctnetlink_exp_dump_mask(struct sk_buff *skb, |
1058 | const struct ip_conntrack_tuple *tuple, | 1057 | const struct ip_conntrack_tuple *tuple, |
1059 | const struct ip_conntrack_tuple *mask) | 1058 | const struct ip_conntrack_tuple *mask) |
1060 | { | 1059 | { |
1061 | int ret; | 1060 | int ret; |
1062 | struct ip_conntrack_protocol *proto; | 1061 | struct ip_conntrack_protocol *proto; |
1063 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); | 1062 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); |
1064 | 1063 | ||
1065 | ret = ctnetlink_dump_tuples_ip(skb, mask); | 1064 | ret = ctnetlink_dump_tuples_ip(skb, mask); |
1066 | if (unlikely(ret < 0)) | 1065 | if (unlikely(ret < 0)) |
1067 | goto nfattr_failure; | 1066 | goto nfattr_failure; |
1068 | 1067 | ||
1069 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | 1068 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); |
1070 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); | 1069 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); |
1071 | ip_conntrack_proto_put(proto); | 1070 | ip_conntrack_proto_put(proto); |
1072 | if (unlikely(ret < 0)) | 1071 | if (unlikely(ret < 0)) |
1073 | goto nfattr_failure; | 1072 | goto nfattr_failure; |
1074 | 1073 | ||
1075 | NFA_NEST_END(skb, nest_parms); | 1074 | NFA_NEST_END(skb, nest_parms); |
1076 | 1075 | ||
1077 | return 0; | 1076 | return 0; |
1078 | 1077 | ||
1079 | nfattr_failure: | 1078 | nfattr_failure: |
1080 | return -1; | 1079 | return -1; |
1081 | } | 1080 | } |
1082 | 1081 | ||
1083 | static inline int | 1082 | static inline int |
1084 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 1083 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
1085 | const struct ip_conntrack_expect *exp) | 1084 | const struct ip_conntrack_expect *exp) |
1086 | { | 1085 | { |
1087 | struct ip_conntrack *master = exp->master; | 1086 | struct ip_conntrack *master = exp->master; |
1088 | __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); | 1087 | __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); |
1089 | __be32 id = htonl(exp->id); | 1088 | __be32 id = htonl(exp->id); |
1090 | 1089 | ||
1091 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | 1090 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) |
1092 | goto nfattr_failure; | 1091 | goto nfattr_failure; |
1093 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) | 1092 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) |
1094 | goto nfattr_failure; | 1093 | goto nfattr_failure; |
1095 | if (ctnetlink_exp_dump_tuple(skb, | 1094 | if (ctnetlink_exp_dump_tuple(skb, |
1096 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 1095 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
1097 | CTA_EXPECT_MASTER) < 0) | 1096 | CTA_EXPECT_MASTER) < 0) |
1098 | goto nfattr_failure; | 1097 | goto nfattr_failure; |
1099 | 1098 | ||
1100 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout); | 1099 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout); |
1101 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id); | 1100 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id); |
1102 | 1101 | ||
1103 | return 0; | 1102 | return 0; |
1104 | 1103 | ||
1105 | nfattr_failure: | 1104 | nfattr_failure: |
1106 | return -1; | 1105 | return -1; |
1107 | } | 1106 | } |
1108 | 1107 | ||
1109 | static int | 1108 | static int |
1110 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | 1109 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, |
1111 | int event, | 1110 | int event, |
1112 | int nowait, | 1111 | int nowait, |
1113 | const struct ip_conntrack_expect *exp) | 1112 | const struct ip_conntrack_expect *exp) |
1114 | { | 1113 | { |
1115 | struct nlmsghdr *nlh; | 1114 | struct nlmsghdr *nlh; |
1116 | struct nfgenmsg *nfmsg; | 1115 | struct nfgenmsg *nfmsg; |
1117 | unsigned char *b; | 1116 | unsigned char *b; |
1118 | 1117 | ||
1119 | b = skb->tail; | 1118 | b = skb->tail; |
1120 | 1119 | ||
1121 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | 1120 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; |
1122 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | 1121 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); |
1123 | nfmsg = NLMSG_DATA(nlh); | 1122 | nfmsg = NLMSG_DATA(nlh); |
1124 | 1123 | ||
1125 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | 1124 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; |
1126 | nfmsg->nfgen_family = AF_INET; | 1125 | nfmsg->nfgen_family = AF_INET; |
1127 | nfmsg->version = NFNETLINK_V0; | 1126 | nfmsg->version = NFNETLINK_V0; |
1128 | nfmsg->res_id = 0; | 1127 | nfmsg->res_id = 0; |
1129 | 1128 | ||
1130 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | 1129 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) |
1131 | goto nfattr_failure; | 1130 | goto nfattr_failure; |
1132 | 1131 | ||
1133 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
1134 | return skb->len; | 1133 | return skb->len; |
1135 | 1134 | ||
1136 | nlmsg_failure: | 1135 | nlmsg_failure: |
1137 | nfattr_failure: | 1136 | nfattr_failure: |
1138 | skb_trim(skb, b - skb->data); | 1137 | skb_trim(skb, b - skb->data); |
1139 | return -1; | 1138 | return -1; |
1140 | } | 1139 | } |
1141 | 1140 | ||
1142 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 1141 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
1143 | static int ctnetlink_expect_event(struct notifier_block *this, | 1142 | static int ctnetlink_expect_event(struct notifier_block *this, |
1144 | unsigned long events, void *ptr) | 1143 | unsigned long events, void *ptr) |
1145 | { | 1144 | { |
1146 | struct nlmsghdr *nlh; | 1145 | struct nlmsghdr *nlh; |
1147 | struct nfgenmsg *nfmsg; | 1146 | struct nfgenmsg *nfmsg; |
1148 | struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr; | 1147 | struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr; |
1149 | struct sk_buff *skb; | 1148 | struct sk_buff *skb; |
1150 | unsigned int type; | 1149 | unsigned int type; |
1151 | unsigned char *b; | 1150 | unsigned char *b; |
1152 | int flags = 0; | 1151 | int flags = 0; |
1153 | 1152 | ||
1154 | if (events & IPEXP_NEW) { | 1153 | if (events & IPEXP_NEW) { |
1155 | type = IPCTNL_MSG_EXP_NEW; | 1154 | type = IPCTNL_MSG_EXP_NEW; |
1156 | flags = NLM_F_CREATE|NLM_F_EXCL; | 1155 | flags = NLM_F_CREATE|NLM_F_EXCL; |
1157 | } else | 1156 | } else |
1158 | return NOTIFY_DONE; | 1157 | return NOTIFY_DONE; |
1159 | 1158 | ||
1160 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) | 1159 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) |
1161 | return NOTIFY_DONE; | 1160 | return NOTIFY_DONE; |
1162 | 1161 | ||
1163 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 1162 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
1164 | if (!skb) | 1163 | if (!skb) |
1165 | return NOTIFY_DONE; | 1164 | return NOTIFY_DONE; |
1166 | 1165 | ||
1167 | b = skb->tail; | 1166 | b = skb->tail; |
1168 | 1167 | ||
1169 | type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | 1168 | type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; |
1170 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | 1169 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); |
1171 | nfmsg = NLMSG_DATA(nlh); | 1170 | nfmsg = NLMSG_DATA(nlh); |
1172 | 1171 | ||
1173 | nlh->nlmsg_flags = flags; | 1172 | nlh->nlmsg_flags = flags; |
1174 | nfmsg->nfgen_family = AF_INET; | 1173 | nfmsg->nfgen_family = AF_INET; |
1175 | nfmsg->version = NFNETLINK_V0; | 1174 | nfmsg->version = NFNETLINK_V0; |
1176 | nfmsg->res_id = 0; | 1175 | nfmsg->res_id = 0; |
1177 | 1176 | ||
1178 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | 1177 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) |
1179 | goto nfattr_failure; | 1178 | goto nfattr_failure; |
1180 | 1179 | ||
1181 | nlh->nlmsg_len = skb->tail - b; | 1180 | nlh->nlmsg_len = skb->tail - b; |
1182 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); | 1181 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); |
1183 | return NOTIFY_DONE; | 1182 | return NOTIFY_DONE; |
1184 | 1183 | ||
1185 | nlmsg_failure: | 1184 | nlmsg_failure: |
1186 | nfattr_failure: | 1185 | nfattr_failure: |
1187 | kfree_skb(skb); | 1186 | kfree_skb(skb); |
1188 | return NOTIFY_DONE; | 1187 | return NOTIFY_DONE; |
1189 | } | 1188 | } |
1190 | #endif | 1189 | #endif |
1191 | 1190 | ||
1192 | static int | 1191 | static int |
1193 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 1192 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
1194 | { | 1193 | { |
1195 | struct ip_conntrack_expect *exp = NULL; | 1194 | struct ip_conntrack_expect *exp = NULL; |
1196 | struct list_head *i; | 1195 | struct list_head *i; |
1197 | u_int32_t *id = (u_int32_t *) &cb->args[0]; | 1196 | u_int32_t *id = (u_int32_t *) &cb->args[0]; |
1198 | 1197 | ||
1199 | read_lock_bh(&ip_conntrack_lock); | 1198 | read_lock_bh(&ip_conntrack_lock); |
1200 | list_for_each_prev(i, &ip_conntrack_expect_list) { | 1199 | list_for_each_prev(i, &ip_conntrack_expect_list) { |
1201 | exp = (struct ip_conntrack_expect *) i; | 1200 | exp = (struct ip_conntrack_expect *) i; |
1202 | if (exp->id <= *id) | 1201 | if (exp->id <= *id) |
1203 | continue; | 1202 | continue; |
1204 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, | 1203 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, |
1205 | cb->nlh->nlmsg_seq, | 1204 | cb->nlh->nlmsg_seq, |
1206 | IPCTNL_MSG_EXP_NEW, | 1205 | IPCTNL_MSG_EXP_NEW, |
1207 | 1, exp) < 0) | 1206 | 1, exp) < 0) |
1208 | goto out; | 1207 | goto out; |
1209 | *id = exp->id; | 1208 | *id = exp->id; |
1210 | } | 1209 | } |
1211 | out: | 1210 | out: |
1212 | read_unlock_bh(&ip_conntrack_lock); | 1211 | read_unlock_bh(&ip_conntrack_lock); |
1213 | 1212 | ||
1214 | return skb->len; | 1213 | return skb->len; |
1215 | } | 1214 | } |
1216 | 1215 | ||
1217 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { | 1216 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { |
1218 | [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32), | 1217 | [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32), |
1219 | [CTA_EXPECT_ID-1] = sizeof(__be32) | 1218 | [CTA_EXPECT_ID-1] = sizeof(__be32) |
1220 | }; | 1219 | }; |
1221 | 1220 | ||
1222 | static int | 1221 | static int |
1223 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | 1222 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, |
1224 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1223 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1225 | { | 1224 | { |
1226 | struct ip_conntrack_tuple tuple; | 1225 | struct ip_conntrack_tuple tuple; |
1227 | struct ip_conntrack_expect *exp; | 1226 | struct ip_conntrack_expect *exp; |
1228 | struct sk_buff *skb2; | 1227 | struct sk_buff *skb2; |
1229 | int err = 0; | 1228 | int err = 0; |
1230 | 1229 | ||
1231 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1230 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1232 | return -EINVAL; | 1231 | return -EINVAL; |
1233 | 1232 | ||
1234 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 1233 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
1235 | struct nfgenmsg *msg = NLMSG_DATA(nlh); | 1234 | struct nfgenmsg *msg = NLMSG_DATA(nlh); |
1236 | u32 rlen; | 1235 | u32 rlen; |
1237 | 1236 | ||
1238 | if (msg->nfgen_family != AF_INET) | 1237 | if (msg->nfgen_family != AF_INET) |
1239 | return -EAFNOSUPPORT; | 1238 | return -EAFNOSUPPORT; |
1240 | 1239 | ||
1241 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 1240 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
1242 | ctnetlink_exp_dump_table, | 1241 | ctnetlink_exp_dump_table, |
1243 | ctnetlink_done)) != 0) | 1242 | ctnetlink_done)) != 0) |
1244 | return -EINVAL; | 1243 | return -EINVAL; |
1245 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 1244 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
1246 | if (rlen > skb->len) | 1245 | if (rlen > skb->len) |
1247 | rlen = skb->len; | 1246 | rlen = skb->len; |
1248 | skb_pull(skb, rlen); | 1247 | skb_pull(skb, rlen); |
1249 | return 0; | 1248 | return 0; |
1250 | } | 1249 | } |
1251 | 1250 | ||
1252 | if (cda[CTA_EXPECT_MASTER-1]) | 1251 | if (cda[CTA_EXPECT_MASTER-1]) |
1253 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER); | 1252 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER); |
1254 | else | 1253 | else |
1255 | return -EINVAL; | 1254 | return -EINVAL; |
1256 | 1255 | ||
1257 | if (err < 0) | 1256 | if (err < 0) |
1258 | return err; | 1257 | return err; |
1259 | 1258 | ||
1260 | exp = ip_conntrack_expect_find(&tuple); | 1259 | exp = ip_conntrack_expect_find(&tuple); |
1261 | if (!exp) | 1260 | if (!exp) |
1262 | return -ENOENT; | 1261 | return -ENOENT; |
1263 | 1262 | ||
1264 | if (cda[CTA_EXPECT_ID-1]) { | 1263 | if (cda[CTA_EXPECT_ID-1]) { |
1265 | __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | 1264 | __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); |
1266 | if (exp->id != ntohl(id)) { | 1265 | if (exp->id != ntohl(id)) { |
1267 | ip_conntrack_expect_put(exp); | 1266 | ip_conntrack_expect_put(exp); |
1268 | return -ENOENT; | 1267 | return -ENOENT; |
1269 | } | 1268 | } |
1270 | } | 1269 | } |
1271 | 1270 | ||
1272 | err = -ENOMEM; | 1271 | err = -ENOMEM; |
1273 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 1272 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1274 | if (!skb2) | 1273 | if (!skb2) |
1275 | goto out; | 1274 | goto out; |
1276 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | 1275 | |
1277 | |||
1278 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, | 1276 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, |
1279 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, | 1277 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, |
1280 | 1, exp); | 1278 | 1, exp); |
1281 | if (err <= 0) | 1279 | if (err <= 0) |
1282 | goto free; | 1280 | goto free; |
1283 | 1281 | ||
1284 | ip_conntrack_expect_put(exp); | 1282 | ip_conntrack_expect_put(exp); |
1285 | 1283 | ||
1286 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1284 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1287 | 1285 | ||
1288 | free: | 1286 | free: |
1289 | kfree_skb(skb2); | 1287 | kfree_skb(skb2); |
1290 | out: | 1288 | out: |
1291 | ip_conntrack_expect_put(exp); | 1289 | ip_conntrack_expect_put(exp); |
1292 | return err; | 1290 | return err; |
1293 | } | 1291 | } |
1294 | 1292 | ||
1295 | static int | 1293 | static int |
1296 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | 1294 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, |
1297 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1295 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1298 | { | 1296 | { |
1299 | struct ip_conntrack_expect *exp, *tmp; | 1297 | struct ip_conntrack_expect *exp, *tmp; |
1300 | struct ip_conntrack_tuple tuple; | 1298 | struct ip_conntrack_tuple tuple; |
1301 | struct ip_conntrack_helper *h; | 1299 | struct ip_conntrack_helper *h; |
1302 | int err; | 1300 | int err; |
1303 | 1301 | ||
1304 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1302 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1305 | return -EINVAL; | 1303 | return -EINVAL; |
1306 | 1304 | ||
1307 | if (cda[CTA_EXPECT_TUPLE-1]) { | 1305 | if (cda[CTA_EXPECT_TUPLE-1]) { |
1308 | /* delete a single expect by tuple */ | 1306 | /* delete a single expect by tuple */ |
1309 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | 1307 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); |
1310 | if (err < 0) | 1308 | if (err < 0) |
1311 | return err; | 1309 | return err; |
1312 | 1310 | ||
1313 | /* bump usage count to 2 */ | 1311 | /* bump usage count to 2 */ |
1314 | exp = ip_conntrack_expect_find(&tuple); | 1312 | exp = ip_conntrack_expect_find(&tuple); |
1315 | if (!exp) | 1313 | if (!exp) |
1316 | return -ENOENT; | 1314 | return -ENOENT; |
1317 | 1315 | ||
1318 | if (cda[CTA_EXPECT_ID-1]) { | 1316 | if (cda[CTA_EXPECT_ID-1]) { |
1319 | __be32 id = | 1317 | __be32 id = |
1320 | *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | 1318 | *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); |
1321 | if (exp->id != ntohl(id)) { | 1319 | if (exp->id != ntohl(id)) { |
1322 | ip_conntrack_expect_put(exp); | 1320 | ip_conntrack_expect_put(exp); |
1323 | return -ENOENT; | 1321 | return -ENOENT; |
1324 | } | 1322 | } |
1325 | } | 1323 | } |
1326 | 1324 | ||
1327 | /* after list removal, usage count == 1 */ | 1325 | /* after list removal, usage count == 1 */ |
1328 | ip_conntrack_unexpect_related(exp); | 1326 | ip_conntrack_unexpect_related(exp); |
1329 | /* have to put what we 'get' above. | 1327 | /* have to put what we 'get' above. |
1330 | * after this line usage count == 0 */ | 1328 | * after this line usage count == 0 */ |
1331 | ip_conntrack_expect_put(exp); | 1329 | ip_conntrack_expect_put(exp); |
1332 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { | 1330 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { |
1333 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); | 1331 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); |
1334 | 1332 | ||
1335 | /* delete all expectations for this helper */ | 1333 | /* delete all expectations for this helper */ |
1336 | write_lock_bh(&ip_conntrack_lock); | 1334 | write_lock_bh(&ip_conntrack_lock); |
1337 | h = __ip_conntrack_helper_find_byname(name); | 1335 | h = __ip_conntrack_helper_find_byname(name); |
1338 | if (!h) { | 1336 | if (!h) { |
1339 | write_unlock_bh(&ip_conntrack_lock); | 1337 | write_unlock_bh(&ip_conntrack_lock); |
1340 | return -EINVAL; | 1338 | return -EINVAL; |
1341 | } | 1339 | } |
1342 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | 1340 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, |
1343 | list) { | 1341 | list) { |
1344 | if (exp->master->helper == h | 1342 | if (exp->master->helper == h |
1345 | && del_timer(&exp->timeout)) { | 1343 | && del_timer(&exp->timeout)) { |
1346 | ip_ct_unlink_expect(exp); | 1344 | ip_ct_unlink_expect(exp); |
1347 | ip_conntrack_expect_put(exp); | 1345 | ip_conntrack_expect_put(exp); |
1348 | } | 1346 | } |
1349 | } | 1347 | } |
1350 | write_unlock_bh(&ip_conntrack_lock); | 1348 | write_unlock_bh(&ip_conntrack_lock); |
1351 | } else { | 1349 | } else { |
1352 | /* This basically means we have to flush everything*/ | 1350 | /* This basically means we have to flush everything*/ |
1353 | write_lock_bh(&ip_conntrack_lock); | 1351 | write_lock_bh(&ip_conntrack_lock); |
1354 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | 1352 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, |
1355 | list) { | 1353 | list) { |
1356 | if (del_timer(&exp->timeout)) { | 1354 | if (del_timer(&exp->timeout)) { |
1357 | ip_ct_unlink_expect(exp); | 1355 | ip_ct_unlink_expect(exp); |
1358 | ip_conntrack_expect_put(exp); | 1356 | ip_conntrack_expect_put(exp); |
1359 | } | 1357 | } |
1360 | } | 1358 | } |
1361 | write_unlock_bh(&ip_conntrack_lock); | 1359 | write_unlock_bh(&ip_conntrack_lock); |
1362 | } | 1360 | } |
1363 | 1361 | ||
1364 | return 0; | 1362 | return 0; |
1365 | } | 1363 | } |
1366 | static int | 1364 | static int |
1367 | ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[]) | 1365 | ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[]) |
1368 | { | 1366 | { |
1369 | return -EOPNOTSUPP; | 1367 | return -EOPNOTSUPP; |
1370 | } | 1368 | } |
1371 | 1369 | ||
1372 | static int | 1370 | static int |
1373 | ctnetlink_create_expect(struct nfattr *cda[]) | 1371 | ctnetlink_create_expect(struct nfattr *cda[]) |
1374 | { | 1372 | { |
1375 | struct ip_conntrack_tuple tuple, mask, master_tuple; | 1373 | struct ip_conntrack_tuple tuple, mask, master_tuple; |
1376 | struct ip_conntrack_tuple_hash *h = NULL; | 1374 | struct ip_conntrack_tuple_hash *h = NULL; |
1377 | struct ip_conntrack_expect *exp; | 1375 | struct ip_conntrack_expect *exp; |
1378 | struct ip_conntrack *ct; | 1376 | struct ip_conntrack *ct; |
1379 | int err = 0; | 1377 | int err = 0; |
1380 | 1378 | ||
1381 | /* caller guarantees that those three CTA_EXPECT_* exist */ | 1379 | /* caller guarantees that those three CTA_EXPECT_* exist */ |
1382 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | 1380 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); |
1383 | if (err < 0) | 1381 | if (err < 0) |
1384 | return err; | 1382 | return err; |
1385 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK); | 1383 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK); |
1386 | if (err < 0) | 1384 | if (err < 0) |
1387 | return err; | 1385 | return err; |
1388 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER); | 1386 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER); |
1389 | if (err < 0) | 1387 | if (err < 0) |
1390 | return err; | 1388 | return err; |
1391 | 1389 | ||
1392 | /* Look for master conntrack of this expectation */ | 1390 | /* Look for master conntrack of this expectation */ |
1393 | h = ip_conntrack_find_get(&master_tuple, NULL); | 1391 | h = ip_conntrack_find_get(&master_tuple, NULL); |
1394 | if (!h) | 1392 | if (!h) |
1395 | return -ENOENT; | 1393 | return -ENOENT; |
1396 | ct = tuplehash_to_ctrack(h); | 1394 | ct = tuplehash_to_ctrack(h); |
1397 | 1395 | ||
1398 | if (!ct->helper) { | 1396 | if (!ct->helper) { |
1399 | /* such conntrack hasn't got any helper, abort */ | 1397 | /* such conntrack hasn't got any helper, abort */ |
1400 | err = -EINVAL; | 1398 | err = -EINVAL; |
1401 | goto out; | 1399 | goto out; |
1402 | } | 1400 | } |
1403 | 1401 | ||
1404 | exp = ip_conntrack_expect_alloc(ct); | 1402 | exp = ip_conntrack_expect_alloc(ct); |
1405 | if (!exp) { | 1403 | if (!exp) { |
1406 | err = -ENOMEM; | 1404 | err = -ENOMEM; |
1407 | goto out; | 1405 | goto out; |
1408 | } | 1406 | } |
1409 | 1407 | ||
1410 | exp->expectfn = NULL; | 1408 | exp->expectfn = NULL; |
1411 | exp->flags = 0; | 1409 | exp->flags = 0; |
1412 | exp->master = ct; | 1410 | exp->master = ct; |
1413 | memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); | 1411 | memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); |
1414 | memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); | 1412 | memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); |
1415 | 1413 | ||
1416 | err = ip_conntrack_expect_related(exp); | 1414 | err = ip_conntrack_expect_related(exp); |
1417 | ip_conntrack_expect_put(exp); | 1415 | ip_conntrack_expect_put(exp); |
1418 | 1416 | ||
1419 | out: | 1417 | out: |
1420 | ip_conntrack_put(tuplehash_to_ctrack(h)); | 1418 | ip_conntrack_put(tuplehash_to_ctrack(h)); |
1421 | return err; | 1419 | return err; |
1422 | } | 1420 | } |
1423 | 1421 | ||
1424 | static int | 1422 | static int |
1425 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | 1423 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, |
1426 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1424 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1427 | { | 1425 | { |
1428 | struct ip_conntrack_tuple tuple; | 1426 | struct ip_conntrack_tuple tuple; |
1429 | struct ip_conntrack_expect *exp; | 1427 | struct ip_conntrack_expect *exp; |
1430 | int err = 0; | 1428 | int err = 0; |
1431 | 1429 | ||
1432 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1430 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1433 | return -EINVAL; | 1431 | return -EINVAL; |
1434 | 1432 | ||
1435 | if (!cda[CTA_EXPECT_TUPLE-1] | 1433 | if (!cda[CTA_EXPECT_TUPLE-1] |
1436 | || !cda[CTA_EXPECT_MASK-1] | 1434 | || !cda[CTA_EXPECT_MASK-1] |
1437 | || !cda[CTA_EXPECT_MASTER-1]) | 1435 | || !cda[CTA_EXPECT_MASTER-1]) |
1438 | return -EINVAL; | 1436 | return -EINVAL; |
1439 | 1437 | ||
1440 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | 1438 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); |
1441 | if (err < 0) | 1439 | if (err < 0) |
1442 | return err; | 1440 | return err; |
1443 | 1441 | ||
1444 | write_lock_bh(&ip_conntrack_lock); | 1442 | write_lock_bh(&ip_conntrack_lock); |
1445 | exp = __ip_conntrack_expect_find(&tuple); | 1443 | exp = __ip_conntrack_expect_find(&tuple); |
1446 | 1444 | ||
1447 | if (!exp) { | 1445 | if (!exp) { |
1448 | write_unlock_bh(&ip_conntrack_lock); | 1446 | write_unlock_bh(&ip_conntrack_lock); |
1449 | err = -ENOENT; | 1447 | err = -ENOENT; |
1450 | if (nlh->nlmsg_flags & NLM_F_CREATE) | 1448 | if (nlh->nlmsg_flags & NLM_F_CREATE) |
1451 | err = ctnetlink_create_expect(cda); | 1449 | err = ctnetlink_create_expect(cda); |
1452 | return err; | 1450 | return err; |
1453 | } | 1451 | } |
1454 | 1452 | ||
1455 | err = -EEXIST; | 1453 | err = -EEXIST; |
1456 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | 1454 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) |
1457 | err = ctnetlink_change_expect(exp, cda); | 1455 | err = ctnetlink_change_expect(exp, cda); |
1458 | write_unlock_bh(&ip_conntrack_lock); | 1456 | write_unlock_bh(&ip_conntrack_lock); |
1459 | 1457 | ||
1460 | return err; | 1458 | return err; |
1461 | } | 1459 | } |
1462 | 1460 | ||
1463 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 1461 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
1464 | static struct notifier_block ctnl_notifier = { | 1462 | static struct notifier_block ctnl_notifier = { |
1465 | .notifier_call = ctnetlink_conntrack_event, | 1463 | .notifier_call = ctnetlink_conntrack_event, |
1466 | }; | 1464 | }; |
1467 | 1465 | ||
1468 | static struct notifier_block ctnl_notifier_exp = { | 1466 | static struct notifier_block ctnl_notifier_exp = { |
1469 | .notifier_call = ctnetlink_expect_event, | 1467 | .notifier_call = ctnetlink_expect_event, |
1470 | }; | 1468 | }; |
1471 | #endif | 1469 | #endif |
1472 | 1470 | ||
1473 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { | 1471 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { |
1474 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, | 1472 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, |
1475 | .attr_count = CTA_MAX, }, | 1473 | .attr_count = CTA_MAX, }, |
1476 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, | 1474 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, |
1477 | .attr_count = CTA_MAX, }, | 1475 | .attr_count = CTA_MAX, }, |
1478 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, | 1476 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, |
1479 | .attr_count = CTA_MAX, }, | 1477 | .attr_count = CTA_MAX, }, |
1480 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, | 1478 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, |
1481 | .attr_count = CTA_MAX, }, | 1479 | .attr_count = CTA_MAX, }, |
1482 | }; | 1480 | }; |
1483 | 1481 | ||
1484 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | 1482 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { |
1485 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, | 1483 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, |
1486 | .attr_count = CTA_EXPECT_MAX, }, | 1484 | .attr_count = CTA_EXPECT_MAX, }, |
1487 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, | 1485 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, |
1488 | .attr_count = CTA_EXPECT_MAX, }, | 1486 | .attr_count = CTA_EXPECT_MAX, }, |
1489 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, | 1487 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, |
1490 | .attr_count = CTA_EXPECT_MAX, }, | 1488 | .attr_count = CTA_EXPECT_MAX, }, |
1491 | }; | 1489 | }; |
1492 | 1490 | ||
1493 | static struct nfnetlink_subsystem ctnl_subsys = { | 1491 | static struct nfnetlink_subsystem ctnl_subsys = { |
1494 | .name = "conntrack", | 1492 | .name = "conntrack", |
1495 | .subsys_id = NFNL_SUBSYS_CTNETLINK, | 1493 | .subsys_id = NFNL_SUBSYS_CTNETLINK, |
1496 | .cb_count = IPCTNL_MSG_MAX, | 1494 | .cb_count = IPCTNL_MSG_MAX, |
1497 | .cb = ctnl_cb, | 1495 | .cb = ctnl_cb, |
1498 | }; | 1496 | }; |
1499 | 1497 | ||
1500 | static struct nfnetlink_subsystem ctnl_exp_subsys = { | 1498 | static struct nfnetlink_subsystem ctnl_exp_subsys = { |
1501 | .name = "conntrack_expect", | 1499 | .name = "conntrack_expect", |
1502 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, | 1500 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, |
1503 | .cb_count = IPCTNL_MSG_EXP_MAX, | 1501 | .cb_count = IPCTNL_MSG_EXP_MAX, |
1504 | .cb = ctnl_exp_cb, | 1502 | .cb = ctnl_exp_cb, |
1505 | }; | 1503 | }; |
1506 | 1504 | ||
1507 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); | 1505 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); |
1508 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); | 1506 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); |
1509 | 1507 | ||
1510 | static int __init ctnetlink_init(void) | 1508 | static int __init ctnetlink_init(void) |
1511 | { | 1509 | { |
1512 | int ret; | 1510 | int ret; |
1513 | 1511 | ||
1514 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); | 1512 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); |
1515 | ret = nfnetlink_subsys_register(&ctnl_subsys); | 1513 | ret = nfnetlink_subsys_register(&ctnl_subsys); |
1516 | if (ret < 0) { | 1514 | if (ret < 0) { |
1517 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); | 1515 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); |
1518 | goto err_out; | 1516 | goto err_out; |
1519 | } | 1517 | } |
1520 | 1518 | ||
1521 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); | 1519 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); |
1522 | if (ret < 0) { | 1520 | if (ret < 0) { |
1523 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); | 1521 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); |
1524 | goto err_unreg_subsys; | 1522 | goto err_unreg_subsys; |
1525 | } | 1523 | } |
1526 | 1524 | ||
1527 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 1525 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
1528 | ret = ip_conntrack_register_notifier(&ctnl_notifier); | 1526 | ret = ip_conntrack_register_notifier(&ctnl_notifier); |
1529 | if (ret < 0) { | 1527 | if (ret < 0) { |
1530 | printk("ctnetlink_init: cannot register notifier.\n"); | 1528 | printk("ctnetlink_init: cannot register notifier.\n"); |
1531 | goto err_unreg_exp_subsys; | 1529 | goto err_unreg_exp_subsys; |
1532 | } | 1530 | } |
1533 | 1531 | ||
1534 | ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp); | 1532 | ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp); |
1535 | if (ret < 0) { | 1533 | if (ret < 0) { |
1536 | printk("ctnetlink_init: cannot expect register notifier.\n"); | 1534 | printk("ctnetlink_init: cannot expect register notifier.\n"); |
1537 | goto err_unreg_notifier; | 1535 | goto err_unreg_notifier; |
1538 | } | 1536 | } |
1539 | #endif | 1537 | #endif |
1540 | 1538 | ||
1541 | return 0; | 1539 | return 0; |
1542 | 1540 | ||
1543 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 1541 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
1544 | err_unreg_notifier: | 1542 | err_unreg_notifier: |
1545 | ip_conntrack_unregister_notifier(&ctnl_notifier); | 1543 | ip_conntrack_unregister_notifier(&ctnl_notifier); |
1546 | err_unreg_exp_subsys: | 1544 | err_unreg_exp_subsys: |
1547 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | 1545 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); |
1548 | #endif | 1546 | #endif |
1549 | err_unreg_subsys: | 1547 | err_unreg_subsys: |
1550 | nfnetlink_subsys_unregister(&ctnl_subsys); | 1548 | nfnetlink_subsys_unregister(&ctnl_subsys); |
1551 | err_out: | 1549 | err_out: |
1552 | return ret; | 1550 | return ret; |
1553 | } | 1551 | } |
1554 | 1552 | ||
1555 | static void __exit ctnetlink_exit(void) | 1553 | static void __exit ctnetlink_exit(void) |
1556 | { | 1554 | { |
1557 | printk("ctnetlink: unregistering from nfnetlink.\n"); | 1555 | printk("ctnetlink: unregistering from nfnetlink.\n"); |
1558 | 1556 | ||
1559 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 1557 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
1560 | ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); | 1558 | ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); |
1561 | ip_conntrack_unregister_notifier(&ctnl_notifier); | 1559 | ip_conntrack_unregister_notifier(&ctnl_notifier); |
1562 | #endif | 1560 | #endif |
1563 | 1561 | ||
1564 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | 1562 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); |
1565 | nfnetlink_subsys_unregister(&ctnl_subsys); | 1563 | nfnetlink_subsys_unregister(&ctnl_subsys); |
1566 | return; | 1564 | return; |
1567 | } | 1565 | } |
1568 | 1566 | ||
1569 | module_init(ctnetlink_init); | 1567 | module_init(ctnetlink_init); |
1570 | module_exit(ctnetlink_exit); | 1568 | module_exit(ctnetlink_exit); |
1571 | 1569 |
net/netfilter/nf_conntrack_netlink.c
1 | /* Connection tracking via netlink socket. Allows for user space | 1 | /* Connection tracking via netlink socket. Allows for user space |
2 | * protocol helpers and general trouble making from userspace. | 2 | * protocol helpers and general trouble making from userspace. |
3 | * | 3 | * |
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> | 7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> |
8 | * | 8 | * |
9 | * I've reworked this stuff to use attributes instead of conntrack | 9 | * I've reworked this stuff to use attributes instead of conntrack |
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | 10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. |
11 | * | 11 | * |
12 | * Initial connection tracking via netlink development funded and | 12 | * Initial connection tracking via netlink development funded and |
13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) | 13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) |
14 | * | 14 | * |
15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) | 15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) |
16 | * | 16 | * |
17 | * This software may be used and distributed according to the terms | 17 | * This software may be used and distributed according to the terms |
18 | * of the GNU General Public License, incorporated herein by reference. | 18 | * of the GNU General Public License, incorporated herein by reference. |
19 | * | 19 | * |
20 | * Derived from ip_conntrack_netlink.c: Port by Pablo Neira Ayuso (05/11/14) | 20 | * Derived from ip_conntrack_netlink.c: Port by Pablo Neira Ayuso (05/11/14) |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/timer.h> | 27 | #include <linux/timer.h> |
28 | #include <linux/skbuff.h> | 28 | #include <linux/skbuff.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/netlink.h> | 30 | #include <linux/netlink.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
33 | #include <linux/notifier.h> | 33 | #include <linux/notifier.h> |
34 | 34 | ||
35 | #include <linux/netfilter.h> | 35 | #include <linux/netfilter.h> |
36 | #include <net/netfilter/nf_conntrack.h> | 36 | #include <net/netfilter/nf_conntrack.h> |
37 | #include <net/netfilter/nf_conntrack_core.h> | 37 | #include <net/netfilter/nf_conntrack_core.h> |
38 | #include <net/netfilter/nf_conntrack_helper.h> | 38 | #include <net/netfilter/nf_conntrack_helper.h> |
39 | #include <net/netfilter/nf_conntrack_l3proto.h> | 39 | #include <net/netfilter/nf_conntrack_l3proto.h> |
40 | #include <net/netfilter/nf_conntrack_protocol.h> | 40 | #include <net/netfilter/nf_conntrack_protocol.h> |
41 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | 41 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> |
42 | 42 | ||
43 | #include <linux/netfilter/nfnetlink.h> | 43 | #include <linux/netfilter/nfnetlink.h> |
44 | #include <linux/netfilter/nfnetlink_conntrack.h> | 44 | #include <linux/netfilter/nfnetlink_conntrack.h> |
45 | 45 | ||
46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
47 | 47 | ||
48 | static char __initdata version[] = "0.93"; | 48 | static char __initdata version[] = "0.93"; |
49 | 49 | ||
50 | static inline int | 50 | static inline int |
51 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | 51 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, |
52 | const struct nf_conntrack_tuple *tuple, | 52 | const struct nf_conntrack_tuple *tuple, |
53 | struct nf_conntrack_protocol *proto) | 53 | struct nf_conntrack_protocol *proto) |
54 | { | 54 | { |
55 | int ret = 0; | 55 | int ret = 0; |
56 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | 56 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); |
57 | 57 | ||
58 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | 58 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); |
59 | 59 | ||
60 | if (likely(proto->tuple_to_nfattr)) | 60 | if (likely(proto->tuple_to_nfattr)) |
61 | ret = proto->tuple_to_nfattr(skb, tuple); | 61 | ret = proto->tuple_to_nfattr(skb, tuple); |
62 | 62 | ||
63 | NFA_NEST_END(skb, nest_parms); | 63 | NFA_NEST_END(skb, nest_parms); |
64 | 64 | ||
65 | return ret; | 65 | return ret; |
66 | 66 | ||
67 | nfattr_failure: | 67 | nfattr_failure: |
68 | return -1; | 68 | return -1; |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline int | 71 | static inline int |
72 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, | 72 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, |
73 | const struct nf_conntrack_tuple *tuple, | 73 | const struct nf_conntrack_tuple *tuple, |
74 | struct nf_conntrack_l3proto *l3proto) | 74 | struct nf_conntrack_l3proto *l3proto) |
75 | { | 75 | { |
76 | int ret = 0; | 76 | int ret = 0; |
77 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | 77 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); |
78 | 78 | ||
79 | if (likely(l3proto->tuple_to_nfattr)) | 79 | if (likely(l3proto->tuple_to_nfattr)) |
80 | ret = l3proto->tuple_to_nfattr(skb, tuple); | 80 | ret = l3proto->tuple_to_nfattr(skb, tuple); |
81 | 81 | ||
82 | NFA_NEST_END(skb, nest_parms); | 82 | NFA_NEST_END(skb, nest_parms); |
83 | 83 | ||
84 | return ret; | 84 | return ret; |
85 | 85 | ||
86 | nfattr_failure: | 86 | nfattr_failure: |
87 | return -1; | 87 | return -1; |
88 | } | 88 | } |
89 | 89 | ||
90 | static inline int | 90 | static inline int |
91 | ctnetlink_dump_tuples(struct sk_buff *skb, | 91 | ctnetlink_dump_tuples(struct sk_buff *skb, |
92 | const struct nf_conntrack_tuple *tuple) | 92 | const struct nf_conntrack_tuple *tuple) |
93 | { | 93 | { |
94 | int ret; | 94 | int ret; |
95 | struct nf_conntrack_l3proto *l3proto; | 95 | struct nf_conntrack_l3proto *l3proto; |
96 | struct nf_conntrack_protocol *proto; | 96 | struct nf_conntrack_protocol *proto; |
97 | 97 | ||
98 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | 98 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); |
99 | ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); | 99 | ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); |
100 | nf_ct_l3proto_put(l3proto); | 100 | nf_ct_l3proto_put(l3proto); |
101 | 101 | ||
102 | if (unlikely(ret < 0)) | 102 | if (unlikely(ret < 0)) |
103 | return ret; | 103 | return ret; |
104 | 104 | ||
105 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | 105 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); |
106 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); | 106 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); |
107 | nf_ct_proto_put(proto); | 107 | nf_ct_proto_put(proto); |
108 | 108 | ||
109 | return ret; | 109 | return ret; |
110 | } | 110 | } |
111 | 111 | ||
112 | static inline int | 112 | static inline int |
113 | ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) | 113 | ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) |
114 | { | 114 | { |
115 | u_int32_t status = htonl((u_int32_t) ct->status); | 115 | u_int32_t status = htonl((u_int32_t) ct->status); |
116 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); | 116 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); |
117 | return 0; | 117 | return 0; |
118 | 118 | ||
119 | nfattr_failure: | 119 | nfattr_failure: |
120 | return -1; | 120 | return -1; |
121 | } | 121 | } |
122 | 122 | ||
123 | static inline int | 123 | static inline int |
124 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) | 124 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) |
125 | { | 125 | { |
126 | long timeout_l = ct->timeout.expires - jiffies; | 126 | long timeout_l = ct->timeout.expires - jiffies; |
127 | u_int32_t timeout; | 127 | u_int32_t timeout; |
128 | 128 | ||
129 | if (timeout_l < 0) | 129 | if (timeout_l < 0) |
130 | timeout = 0; | 130 | timeout = 0; |
131 | else | 131 | else |
132 | timeout = htonl(timeout_l / HZ); | 132 | timeout = htonl(timeout_l / HZ); |
133 | 133 | ||
134 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); | 134 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); |
135 | return 0; | 135 | return 0; |
136 | 136 | ||
137 | nfattr_failure: | 137 | nfattr_failure: |
138 | return -1; | 138 | return -1; |
139 | } | 139 | } |
140 | 140 | ||
141 | static inline int | 141 | static inline int |
142 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) | 142 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) |
143 | { | 143 | { |
144 | struct nf_conntrack_protocol *proto = nf_ct_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | 144 | struct nf_conntrack_protocol *proto = nf_ct_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); |
145 | struct nfattr *nest_proto; | 145 | struct nfattr *nest_proto; |
146 | int ret; | 146 | int ret; |
147 | 147 | ||
148 | if (!proto->to_nfattr) { | 148 | if (!proto->to_nfattr) { |
149 | nf_ct_proto_put(proto); | 149 | nf_ct_proto_put(proto); |
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); | 153 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); |
154 | 154 | ||
155 | ret = proto->to_nfattr(skb, nest_proto, ct); | 155 | ret = proto->to_nfattr(skb, nest_proto, ct); |
156 | 156 | ||
157 | nf_ct_proto_put(proto); | 157 | nf_ct_proto_put(proto); |
158 | 158 | ||
159 | NFA_NEST_END(skb, nest_proto); | 159 | NFA_NEST_END(skb, nest_proto); |
160 | 160 | ||
161 | return ret; | 161 | return ret; |
162 | 162 | ||
163 | nfattr_failure: | 163 | nfattr_failure: |
164 | nf_ct_proto_put(proto); | 164 | nf_ct_proto_put(proto); |
165 | return -1; | 165 | return -1; |
166 | } | 166 | } |
167 | 167 | ||
168 | static inline int | 168 | static inline int |
169 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) | 169 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) |
170 | { | 170 | { |
171 | struct nfattr *nest_helper; | 171 | struct nfattr *nest_helper; |
172 | const struct nf_conn_help *help = nfct_help(ct); | 172 | const struct nf_conn_help *help = nfct_help(ct); |
173 | 173 | ||
174 | if (!help || !help->helper) | 174 | if (!help || !help->helper) |
175 | return 0; | 175 | return 0; |
176 | 176 | ||
177 | nest_helper = NFA_NEST(skb, CTA_HELP); | 177 | nest_helper = NFA_NEST(skb, CTA_HELP); |
178 | NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); | 178 | NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); |
179 | 179 | ||
180 | if (help->helper->to_nfattr) | 180 | if (help->helper->to_nfattr) |
181 | help->helper->to_nfattr(skb, ct); | 181 | help->helper->to_nfattr(skb, ct); |
182 | 182 | ||
183 | NFA_NEST_END(skb, nest_helper); | 183 | NFA_NEST_END(skb, nest_helper); |
184 | 184 | ||
185 | return 0; | 185 | return 0; |
186 | 186 | ||
187 | nfattr_failure: | 187 | nfattr_failure: |
188 | return -1; | 188 | return -1; |
189 | } | 189 | } |
190 | 190 | ||
191 | #ifdef CONFIG_NF_CT_ACCT | 191 | #ifdef CONFIG_NF_CT_ACCT |
192 | static inline int | 192 | static inline int |
193 | ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, | 193 | ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, |
194 | enum ip_conntrack_dir dir) | 194 | enum ip_conntrack_dir dir) |
195 | { | 195 | { |
196 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; | 196 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; |
197 | struct nfattr *nest_count = NFA_NEST(skb, type); | 197 | struct nfattr *nest_count = NFA_NEST(skb, type); |
198 | u_int32_t tmp; | 198 | u_int32_t tmp; |
199 | 199 | ||
200 | tmp = htonl(ct->counters[dir].packets); | 200 | tmp = htonl(ct->counters[dir].packets); |
201 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); | 201 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); |
202 | 202 | ||
203 | tmp = htonl(ct->counters[dir].bytes); | 203 | tmp = htonl(ct->counters[dir].bytes); |
204 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); | 204 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); |
205 | 205 | ||
206 | NFA_NEST_END(skb, nest_count); | 206 | NFA_NEST_END(skb, nest_count); |
207 | 207 | ||
208 | return 0; | 208 | return 0; |
209 | 209 | ||
210 | nfattr_failure: | 210 | nfattr_failure: |
211 | return -1; | 211 | return -1; |
212 | } | 212 | } |
213 | #else | 213 | #else |
214 | #define ctnetlink_dump_counters(a, b, c) (0) | 214 | #define ctnetlink_dump_counters(a, b, c) (0) |
215 | #endif | 215 | #endif |
216 | 216 | ||
217 | #ifdef CONFIG_NF_CONNTRACK_MARK | 217 | #ifdef CONFIG_NF_CONNTRACK_MARK |
218 | static inline int | 218 | static inline int |
219 | ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) | 219 | ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) |
220 | { | 220 | { |
221 | u_int32_t mark = htonl(ct->mark); | 221 | u_int32_t mark = htonl(ct->mark); |
222 | 222 | ||
223 | NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); | 223 | NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); |
224 | return 0; | 224 | return 0; |
225 | 225 | ||
226 | nfattr_failure: | 226 | nfattr_failure: |
227 | return -1; | 227 | return -1; |
228 | } | 228 | } |
229 | #else | 229 | #else |
230 | #define ctnetlink_dump_mark(a, b) (0) | 230 | #define ctnetlink_dump_mark(a, b) (0) |
231 | #endif | 231 | #endif |
232 | 232 | ||
233 | static inline int | 233 | static inline int |
234 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) | 234 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) |
235 | { | 235 | { |
236 | u_int32_t id = htonl(ct->id); | 236 | u_int32_t id = htonl(ct->id); |
237 | NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); | 237 | NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); |
238 | return 0; | 238 | return 0; |
239 | 239 | ||
240 | nfattr_failure: | 240 | nfattr_failure: |
241 | return -1; | 241 | return -1; |
242 | } | 242 | } |
243 | 243 | ||
244 | static inline int | 244 | static inline int |
245 | ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct) | 245 | ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct) |
246 | { | 246 | { |
247 | u_int32_t use = htonl(atomic_read(&ct->ct_general.use)); | 247 | u_int32_t use = htonl(atomic_read(&ct->ct_general.use)); |
248 | 248 | ||
249 | NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); | 249 | NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); |
250 | return 0; | 250 | return 0; |
251 | 251 | ||
252 | nfattr_failure: | 252 | nfattr_failure: |
253 | return -1; | 253 | return -1; |
254 | } | 254 | } |
255 | 255 | ||
256 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) | 256 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) |
257 | 257 | ||
258 | static int | 258 | static int |
259 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | 259 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, |
260 | int event, int nowait, | 260 | int event, int nowait, |
261 | const struct nf_conn *ct) | 261 | const struct nf_conn *ct) |
262 | { | 262 | { |
263 | struct nlmsghdr *nlh; | 263 | struct nlmsghdr *nlh; |
264 | struct nfgenmsg *nfmsg; | 264 | struct nfgenmsg *nfmsg; |
265 | struct nfattr *nest_parms; | 265 | struct nfattr *nest_parms; |
266 | unsigned char *b; | 266 | unsigned char *b; |
267 | 267 | ||
268 | b = skb->tail; | 268 | b = skb->tail; |
269 | 269 | ||
270 | event |= NFNL_SUBSYS_CTNETLINK << 8; | 270 | event |= NFNL_SUBSYS_CTNETLINK << 8; |
271 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | 271 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); |
272 | nfmsg = NLMSG_DATA(nlh); | 272 | nfmsg = NLMSG_DATA(nlh); |
273 | 273 | ||
274 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | 274 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; |
275 | nfmsg->nfgen_family = | 275 | nfmsg->nfgen_family = |
276 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | 276 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; |
277 | nfmsg->version = NFNETLINK_V0; | 277 | nfmsg->version = NFNETLINK_V0; |
278 | nfmsg->res_id = 0; | 278 | nfmsg->res_id = 0; |
279 | 279 | ||
280 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | 280 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); |
281 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | 281 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) |
282 | goto nfattr_failure; | 282 | goto nfattr_failure; |
283 | NFA_NEST_END(skb, nest_parms); | 283 | NFA_NEST_END(skb, nest_parms); |
284 | 284 | ||
285 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | 285 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); |
286 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | 286 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) |
287 | goto nfattr_failure; | 287 | goto nfattr_failure; |
288 | NFA_NEST_END(skb, nest_parms); | 288 | NFA_NEST_END(skb, nest_parms); |
289 | 289 | ||
290 | if (ctnetlink_dump_status(skb, ct) < 0 || | 290 | if (ctnetlink_dump_status(skb, ct) < 0 || |
291 | ctnetlink_dump_timeout(skb, ct) < 0 || | 291 | ctnetlink_dump_timeout(skb, ct) < 0 || |
292 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 292 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
293 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || | 293 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || |
294 | ctnetlink_dump_protoinfo(skb, ct) < 0 || | 294 | ctnetlink_dump_protoinfo(skb, ct) < 0 || |
295 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | 295 | ctnetlink_dump_helpinfo(skb, ct) < 0 || |
296 | ctnetlink_dump_mark(skb, ct) < 0 || | 296 | ctnetlink_dump_mark(skb, ct) < 0 || |
297 | ctnetlink_dump_id(skb, ct) < 0 || | 297 | ctnetlink_dump_id(skb, ct) < 0 || |
298 | ctnetlink_dump_use(skb, ct) < 0) | 298 | ctnetlink_dump_use(skb, ct) < 0) |
299 | goto nfattr_failure; | 299 | goto nfattr_failure; |
300 | 300 | ||
301 | nlh->nlmsg_len = skb->tail - b; | 301 | nlh->nlmsg_len = skb->tail - b; |
302 | return skb->len; | 302 | return skb->len; |
303 | 303 | ||
304 | nlmsg_failure: | 304 | nlmsg_failure: |
305 | nfattr_failure: | 305 | nfattr_failure: |
306 | skb_trim(skb, b - skb->data); | 306 | skb_trim(skb, b - skb->data); |
307 | return -1; | 307 | return -1; |
308 | } | 308 | } |
309 | 309 | ||
310 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 310 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
311 | static int ctnetlink_conntrack_event(struct notifier_block *this, | 311 | static int ctnetlink_conntrack_event(struct notifier_block *this, |
312 | unsigned long events, void *ptr) | 312 | unsigned long events, void *ptr) |
313 | { | 313 | { |
314 | struct nlmsghdr *nlh; | 314 | struct nlmsghdr *nlh; |
315 | struct nfgenmsg *nfmsg; | 315 | struct nfgenmsg *nfmsg; |
316 | struct nfattr *nest_parms; | 316 | struct nfattr *nest_parms; |
317 | struct nf_conn *ct = (struct nf_conn *)ptr; | 317 | struct nf_conn *ct = (struct nf_conn *)ptr; |
318 | struct sk_buff *skb; | 318 | struct sk_buff *skb; |
319 | unsigned int type; | 319 | unsigned int type; |
320 | unsigned char *b; | 320 | unsigned char *b; |
321 | unsigned int flags = 0, group; | 321 | unsigned int flags = 0, group; |
322 | 322 | ||
323 | /* ignore our fake conntrack entry */ | 323 | /* ignore our fake conntrack entry */ |
324 | if (ct == &nf_conntrack_untracked) | 324 | if (ct == &nf_conntrack_untracked) |
325 | return NOTIFY_DONE; | 325 | return NOTIFY_DONE; |
326 | 326 | ||
327 | if (events & IPCT_DESTROY) { | 327 | if (events & IPCT_DESTROY) { |
328 | type = IPCTNL_MSG_CT_DELETE; | 328 | type = IPCTNL_MSG_CT_DELETE; |
329 | group = NFNLGRP_CONNTRACK_DESTROY; | 329 | group = NFNLGRP_CONNTRACK_DESTROY; |
330 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { | 330 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { |
331 | type = IPCTNL_MSG_CT_NEW; | 331 | type = IPCTNL_MSG_CT_NEW; |
332 | flags = NLM_F_CREATE|NLM_F_EXCL; | 332 | flags = NLM_F_CREATE|NLM_F_EXCL; |
333 | /* dump everything */ | 333 | /* dump everything */ |
334 | events = ~0UL; | 334 | events = ~0UL; |
335 | group = NFNLGRP_CONNTRACK_NEW; | 335 | group = NFNLGRP_CONNTRACK_NEW; |
336 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { | 336 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { |
337 | type = IPCTNL_MSG_CT_NEW; | 337 | type = IPCTNL_MSG_CT_NEW; |
338 | group = NFNLGRP_CONNTRACK_UPDATE; | 338 | group = NFNLGRP_CONNTRACK_UPDATE; |
339 | } else | 339 | } else |
340 | return NOTIFY_DONE; | 340 | return NOTIFY_DONE; |
341 | 341 | ||
342 | if (!nfnetlink_has_listeners(group)) | 342 | if (!nfnetlink_has_listeners(group)) |
343 | return NOTIFY_DONE; | 343 | return NOTIFY_DONE; |
344 | 344 | ||
345 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 345 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
346 | if (!skb) | 346 | if (!skb) |
347 | return NOTIFY_DONE; | 347 | return NOTIFY_DONE; |
348 | 348 | ||
349 | b = skb->tail; | 349 | b = skb->tail; |
350 | 350 | ||
351 | type |= NFNL_SUBSYS_CTNETLINK << 8; | 351 | type |= NFNL_SUBSYS_CTNETLINK << 8; |
352 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | 352 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); |
353 | nfmsg = NLMSG_DATA(nlh); | 353 | nfmsg = NLMSG_DATA(nlh); |
354 | 354 | ||
355 | nlh->nlmsg_flags = flags; | 355 | nlh->nlmsg_flags = flags; |
356 | nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | 356 | nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; |
357 | nfmsg->version = NFNETLINK_V0; | 357 | nfmsg->version = NFNETLINK_V0; |
358 | nfmsg->res_id = 0; | 358 | nfmsg->res_id = 0; |
359 | 359 | ||
360 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | 360 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); |
361 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | 361 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) |
362 | goto nfattr_failure; | 362 | goto nfattr_failure; |
363 | NFA_NEST_END(skb, nest_parms); | 363 | NFA_NEST_END(skb, nest_parms); |
364 | 364 | ||
365 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | 365 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); |
366 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | 366 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) |
367 | goto nfattr_failure; | 367 | goto nfattr_failure; |
368 | NFA_NEST_END(skb, nest_parms); | 368 | NFA_NEST_END(skb, nest_parms); |
369 | 369 | ||
370 | /* NAT stuff is now a status flag */ | 370 | /* NAT stuff is now a status flag */ |
371 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) | 371 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) |
372 | && ctnetlink_dump_status(skb, ct) < 0) | 372 | && ctnetlink_dump_status(skb, ct) < 0) |
373 | goto nfattr_failure; | 373 | goto nfattr_failure; |
374 | if (events & IPCT_REFRESH | 374 | if (events & IPCT_REFRESH |
375 | && ctnetlink_dump_timeout(skb, ct) < 0) | 375 | && ctnetlink_dump_timeout(skb, ct) < 0) |
376 | goto nfattr_failure; | 376 | goto nfattr_failure; |
377 | if (events & IPCT_PROTOINFO | 377 | if (events & IPCT_PROTOINFO |
378 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | 378 | && ctnetlink_dump_protoinfo(skb, ct) < 0) |
379 | goto nfattr_failure; | 379 | goto nfattr_failure; |
380 | if (events & IPCT_HELPINFO | 380 | if (events & IPCT_HELPINFO |
381 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | 381 | && ctnetlink_dump_helpinfo(skb, ct) < 0) |
382 | goto nfattr_failure; | 382 | goto nfattr_failure; |
383 | 383 | ||
384 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 384 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
385 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | 385 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
386 | goto nfattr_failure; | 386 | goto nfattr_failure; |
387 | 387 | ||
388 | if (events & IPCT_MARK | 388 | if (events & IPCT_MARK |
389 | && ctnetlink_dump_mark(skb, ct) < 0) | 389 | && ctnetlink_dump_mark(skb, ct) < 0) |
390 | goto nfattr_failure; | 390 | goto nfattr_failure; |
391 | 391 | ||
392 | nlh->nlmsg_len = skb->tail - b; | 392 | nlh->nlmsg_len = skb->tail - b; |
393 | nfnetlink_send(skb, 0, group, 0); | 393 | nfnetlink_send(skb, 0, group, 0); |
394 | return NOTIFY_DONE; | 394 | return NOTIFY_DONE; |
395 | 395 | ||
396 | nlmsg_failure: | 396 | nlmsg_failure: |
397 | nfattr_failure: | 397 | nfattr_failure: |
398 | kfree_skb(skb); | 398 | kfree_skb(skb); |
399 | return NOTIFY_DONE; | 399 | return NOTIFY_DONE; |
400 | } | 400 | } |
401 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ | 401 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ |
402 | 402 | ||
403 | static int ctnetlink_done(struct netlink_callback *cb) | 403 | static int ctnetlink_done(struct netlink_callback *cb) |
404 | { | 404 | { |
405 | if (cb->args[1]) | 405 | if (cb->args[1]) |
406 | nf_ct_put((struct nf_conn *)cb->args[1]); | 406 | nf_ct_put((struct nf_conn *)cb->args[1]); |
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | #define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num | 410 | #define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num |
411 | 411 | ||
412 | static int | 412 | static int |
413 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 413 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
414 | { | 414 | { |
415 | struct nf_conn *ct, *last; | 415 | struct nf_conn *ct, *last; |
416 | struct nf_conntrack_tuple_hash *h; | 416 | struct nf_conntrack_tuple_hash *h; |
417 | struct list_head *i; | 417 | struct list_head *i; |
418 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 418 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
419 | u_int8_t l3proto = nfmsg->nfgen_family; | 419 | u_int8_t l3proto = nfmsg->nfgen_family; |
420 | 420 | ||
421 | read_lock_bh(&nf_conntrack_lock); | 421 | read_lock_bh(&nf_conntrack_lock); |
422 | last = (struct nf_conn *)cb->args[1]; | 422 | last = (struct nf_conn *)cb->args[1]; |
423 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { | 423 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { |
424 | restart: | 424 | restart: |
425 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { | 425 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { |
426 | h = (struct nf_conntrack_tuple_hash *) i; | 426 | h = (struct nf_conntrack_tuple_hash *) i; |
427 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 427 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
428 | continue; | 428 | continue; |
429 | ct = nf_ct_tuplehash_to_ctrack(h); | 429 | ct = nf_ct_tuplehash_to_ctrack(h); |
430 | /* Dump entries of a given L3 protocol number. | 430 | /* Dump entries of a given L3 protocol number. |
431 | * If it is not specified, ie. l3proto == 0, | 431 | * If it is not specified, ie. l3proto == 0, |
432 | * then dump everything. */ | 432 | * then dump everything. */ |
433 | if (l3proto && L3PROTO(ct) != l3proto) | 433 | if (l3proto && L3PROTO(ct) != l3proto) |
434 | continue; | 434 | continue; |
435 | if (cb->args[1]) { | 435 | if (cb->args[1]) { |
436 | if (ct != last) | 436 | if (ct != last) |
437 | continue; | 437 | continue; |
438 | cb->args[1] = 0; | 438 | cb->args[1] = 0; |
439 | } | 439 | } |
440 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 440 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
441 | cb->nlh->nlmsg_seq, | 441 | cb->nlh->nlmsg_seq, |
442 | IPCTNL_MSG_CT_NEW, | 442 | IPCTNL_MSG_CT_NEW, |
443 | 1, ct) < 0) { | 443 | 1, ct) < 0) { |
444 | nf_conntrack_get(&ct->ct_general); | 444 | nf_conntrack_get(&ct->ct_general); |
445 | cb->args[1] = (unsigned long)ct; | 445 | cb->args[1] = (unsigned long)ct; |
446 | goto out; | 446 | goto out; |
447 | } | 447 | } |
448 | #ifdef CONFIG_NF_CT_ACCT | 448 | #ifdef CONFIG_NF_CT_ACCT |
449 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == | 449 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == |
450 | IPCTNL_MSG_CT_GET_CTRZERO) | 450 | IPCTNL_MSG_CT_GET_CTRZERO) |
451 | memset(&ct->counters, 0, sizeof(ct->counters)); | 451 | memset(&ct->counters, 0, sizeof(ct->counters)); |
452 | #endif | 452 | #endif |
453 | } | 453 | } |
454 | if (cb->args[1]) { | 454 | if (cb->args[1]) { |
455 | cb->args[1] = 0; | 455 | cb->args[1] = 0; |
456 | goto restart; | 456 | goto restart; |
457 | } | 457 | } |
458 | } | 458 | } |
459 | out: | 459 | out: |
460 | read_unlock_bh(&nf_conntrack_lock); | 460 | read_unlock_bh(&nf_conntrack_lock); |
461 | if (last) | 461 | if (last) |
462 | nf_ct_put(last); | 462 | nf_ct_put(last); |
463 | 463 | ||
464 | return skb->len; | 464 | return skb->len; |
465 | } | 465 | } |
466 | 466 | ||
467 | static inline int | 467 | static inline int |
468 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) | 468 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) |
469 | { | 469 | { |
470 | struct nfattr *tb[CTA_IP_MAX]; | 470 | struct nfattr *tb[CTA_IP_MAX]; |
471 | struct nf_conntrack_l3proto *l3proto; | 471 | struct nf_conntrack_l3proto *l3proto; |
472 | int ret = 0; | 472 | int ret = 0; |
473 | 473 | ||
474 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); | 474 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); |
475 | 475 | ||
476 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | 476 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); |
477 | 477 | ||
478 | if (likely(l3proto->nfattr_to_tuple)) | 478 | if (likely(l3proto->nfattr_to_tuple)) |
479 | ret = l3proto->nfattr_to_tuple(tb, tuple); | 479 | ret = l3proto->nfattr_to_tuple(tb, tuple); |
480 | 480 | ||
481 | nf_ct_l3proto_put(l3proto); | 481 | nf_ct_l3proto_put(l3proto); |
482 | 482 | ||
483 | return ret; | 483 | return ret; |
484 | } | 484 | } |
485 | 485 | ||
486 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | 486 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { |
487 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), | 487 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), |
488 | }; | 488 | }; |
489 | 489 | ||
490 | static inline int | 490 | static inline int |
491 | ctnetlink_parse_tuple_proto(struct nfattr *attr, | 491 | ctnetlink_parse_tuple_proto(struct nfattr *attr, |
492 | struct nf_conntrack_tuple *tuple) | 492 | struct nf_conntrack_tuple *tuple) |
493 | { | 493 | { |
494 | struct nfattr *tb[CTA_PROTO_MAX]; | 494 | struct nfattr *tb[CTA_PROTO_MAX]; |
495 | struct nf_conntrack_protocol *proto; | 495 | struct nf_conntrack_protocol *proto; |
496 | int ret = 0; | 496 | int ret = 0; |
497 | 497 | ||
498 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); | 498 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); |
499 | 499 | ||
500 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | 500 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) |
501 | return -EINVAL; | 501 | return -EINVAL; |
502 | 502 | ||
503 | if (!tb[CTA_PROTO_NUM-1]) | 503 | if (!tb[CTA_PROTO_NUM-1]) |
504 | return -EINVAL; | 504 | return -EINVAL; |
505 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); | 505 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); |
506 | 506 | ||
507 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | 507 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); |
508 | 508 | ||
509 | if (likely(proto->nfattr_to_tuple)) | 509 | if (likely(proto->nfattr_to_tuple)) |
510 | ret = proto->nfattr_to_tuple(tb, tuple); | 510 | ret = proto->nfattr_to_tuple(tb, tuple); |
511 | 511 | ||
512 | nf_ct_proto_put(proto); | 512 | nf_ct_proto_put(proto); |
513 | 513 | ||
514 | return ret; | 514 | return ret; |
515 | } | 515 | } |
516 | 516 | ||
517 | static inline int | 517 | static inline int |
518 | ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, | 518 | ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, |
519 | enum ctattr_tuple type, u_int8_t l3num) | 519 | enum ctattr_tuple type, u_int8_t l3num) |
520 | { | 520 | { |
521 | struct nfattr *tb[CTA_TUPLE_MAX]; | 521 | struct nfattr *tb[CTA_TUPLE_MAX]; |
522 | int err; | 522 | int err; |
523 | 523 | ||
524 | memset(tuple, 0, sizeof(*tuple)); | 524 | memset(tuple, 0, sizeof(*tuple)); |
525 | 525 | ||
526 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); | 526 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); |
527 | 527 | ||
528 | if (!tb[CTA_TUPLE_IP-1]) | 528 | if (!tb[CTA_TUPLE_IP-1]) |
529 | return -EINVAL; | 529 | return -EINVAL; |
530 | 530 | ||
531 | tuple->src.l3num = l3num; | 531 | tuple->src.l3num = l3num; |
532 | 532 | ||
533 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); | 533 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); |
534 | if (err < 0) | 534 | if (err < 0) |
535 | return err; | 535 | return err; |
536 | 536 | ||
537 | if (!tb[CTA_TUPLE_PROTO-1]) | 537 | if (!tb[CTA_TUPLE_PROTO-1]) |
538 | return -EINVAL; | 538 | return -EINVAL; |
539 | 539 | ||
540 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); | 540 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); |
541 | if (err < 0) | 541 | if (err < 0) |
542 | return err; | 542 | return err; |
543 | 543 | ||
544 | /* orig and expect tuples get DIR_ORIGINAL */ | 544 | /* orig and expect tuples get DIR_ORIGINAL */ |
545 | if (type == CTA_TUPLE_REPLY) | 545 | if (type == CTA_TUPLE_REPLY) |
546 | tuple->dst.dir = IP_CT_DIR_REPLY; | 546 | tuple->dst.dir = IP_CT_DIR_REPLY; |
547 | else | 547 | else |
548 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | 548 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; |
549 | 549 | ||
550 | return 0; | 550 | return 0; |
551 | } | 551 | } |
552 | 552 | ||
553 | #ifdef CONFIG_IP_NF_NAT_NEEDED | 553 | #ifdef CONFIG_IP_NF_NAT_NEEDED |
554 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { | 554 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { |
555 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), | 555 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), |
556 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), | 556 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), |
557 | }; | 557 | }; |
558 | 558 | ||
559 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, | 559 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, |
560 | const struct nf_conn *ct, | 560 | const struct nf_conn *ct, |
561 | struct ip_nat_range *range) | 561 | struct ip_nat_range *range) |
562 | { | 562 | { |
563 | struct nfattr *tb[CTA_PROTONAT_MAX]; | 563 | struct nfattr *tb[CTA_PROTONAT_MAX]; |
564 | struct ip_nat_protocol *npt; | 564 | struct ip_nat_protocol *npt; |
565 | 565 | ||
566 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); | 566 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); |
567 | 567 | ||
568 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) | 568 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) |
569 | return -EINVAL; | 569 | return -EINVAL; |
570 | 570 | ||
571 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | 571 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); |
572 | 572 | ||
573 | if (!npt->nfattr_to_range) { | 573 | if (!npt->nfattr_to_range) { |
574 | ip_nat_proto_put(npt); | 574 | ip_nat_proto_put(npt); |
575 | return 0; | 575 | return 0; |
576 | } | 576 | } |
577 | 577 | ||
578 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ | 578 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ |
579 | if (npt->nfattr_to_range(tb, range) > 0) | 579 | if (npt->nfattr_to_range(tb, range) > 0) |
580 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | 580 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; |
581 | 581 | ||
582 | ip_nat_proto_put(npt); | 582 | ip_nat_proto_put(npt); |
583 | 583 | ||
584 | return 0; | 584 | return 0; |
585 | } | 585 | } |
586 | 586 | ||
587 | static const size_t cta_min_nat[CTA_NAT_MAX] = { | 587 | static const size_t cta_min_nat[CTA_NAT_MAX] = { |
588 | [CTA_NAT_MINIP-1] = sizeof(u_int32_t), | 588 | [CTA_NAT_MINIP-1] = sizeof(u_int32_t), |
589 | [CTA_NAT_MAXIP-1] = sizeof(u_int32_t), | 589 | [CTA_NAT_MAXIP-1] = sizeof(u_int32_t), |
590 | }; | 590 | }; |
591 | 591 | ||
592 | static inline int | 592 | static inline int |
593 | ctnetlink_parse_nat(struct nfattr *nat, | 593 | ctnetlink_parse_nat(struct nfattr *nat, |
594 | const struct nf_conn *ct, struct ip_nat_range *range) | 594 | const struct nf_conn *ct, struct ip_nat_range *range) |
595 | { | 595 | { |
596 | struct nfattr *tb[CTA_NAT_MAX]; | 596 | struct nfattr *tb[CTA_NAT_MAX]; |
597 | int err; | 597 | int err; |
598 | 598 | ||
599 | memset(range, 0, sizeof(*range)); | 599 | memset(range, 0, sizeof(*range)); |
600 | 600 | ||
601 | nfattr_parse_nested(tb, CTA_NAT_MAX, nat); | 601 | nfattr_parse_nested(tb, CTA_NAT_MAX, nat); |
602 | 602 | ||
603 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) | 603 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) |
604 | return -EINVAL; | 604 | return -EINVAL; |
605 | 605 | ||
606 | if (tb[CTA_NAT_MINIP-1]) | 606 | if (tb[CTA_NAT_MINIP-1]) |
607 | range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); | 607 | range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); |
608 | 608 | ||
609 | if (!tb[CTA_NAT_MAXIP-1]) | 609 | if (!tb[CTA_NAT_MAXIP-1]) |
610 | range->max_ip = range->min_ip; | 610 | range->max_ip = range->min_ip; |
611 | else | 611 | else |
612 | range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); | 612 | range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); |
613 | 613 | ||
614 | if (range->min_ip) | 614 | if (range->min_ip) |
615 | range->flags |= IP_NAT_RANGE_MAP_IPS; | 615 | range->flags |= IP_NAT_RANGE_MAP_IPS; |
616 | 616 | ||
617 | if (!tb[CTA_NAT_PROTO-1]) | 617 | if (!tb[CTA_NAT_PROTO-1]) |
618 | return 0; | 618 | return 0; |
619 | 619 | ||
620 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); | 620 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); |
621 | if (err < 0) | 621 | if (err < 0) |
622 | return err; | 622 | return err; |
623 | 623 | ||
624 | return 0; | 624 | return 0; |
625 | } | 625 | } |
626 | #endif | 626 | #endif |
627 | 627 | ||
628 | static inline int | 628 | static inline int |
629 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) | 629 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) |
630 | { | 630 | { |
631 | struct nfattr *tb[CTA_HELP_MAX]; | 631 | struct nfattr *tb[CTA_HELP_MAX]; |
632 | 632 | ||
633 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); | 633 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); |
634 | 634 | ||
635 | if (!tb[CTA_HELP_NAME-1]) | 635 | if (!tb[CTA_HELP_NAME-1]) |
636 | return -EINVAL; | 636 | return -EINVAL; |
637 | 637 | ||
638 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); | 638 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); |
639 | 639 | ||
640 | return 0; | 640 | return 0; |
641 | } | 641 | } |
642 | 642 | ||
643 | static const size_t cta_min[CTA_MAX] = { | 643 | static const size_t cta_min[CTA_MAX] = { |
644 | [CTA_STATUS-1] = sizeof(u_int32_t), | 644 | [CTA_STATUS-1] = sizeof(u_int32_t), |
645 | [CTA_TIMEOUT-1] = sizeof(u_int32_t), | 645 | [CTA_TIMEOUT-1] = sizeof(u_int32_t), |
646 | [CTA_MARK-1] = sizeof(u_int32_t), | 646 | [CTA_MARK-1] = sizeof(u_int32_t), |
647 | [CTA_USE-1] = sizeof(u_int32_t), | 647 | [CTA_USE-1] = sizeof(u_int32_t), |
648 | [CTA_ID-1] = sizeof(u_int32_t) | 648 | [CTA_ID-1] = sizeof(u_int32_t) |
649 | }; | 649 | }; |
650 | 650 | ||
651 | static int | 651 | static int |
652 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | 652 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, |
653 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 653 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
654 | { | 654 | { |
655 | struct nf_conntrack_tuple_hash *h; | 655 | struct nf_conntrack_tuple_hash *h; |
656 | struct nf_conntrack_tuple tuple; | 656 | struct nf_conntrack_tuple tuple; |
657 | struct nf_conn *ct; | 657 | struct nf_conn *ct; |
658 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 658 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
659 | u_int8_t u3 = nfmsg->nfgen_family; | 659 | u_int8_t u3 = nfmsg->nfgen_family; |
660 | int err = 0; | 660 | int err = 0; |
661 | 661 | ||
662 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 662 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
663 | return -EINVAL; | 663 | return -EINVAL; |
664 | 664 | ||
665 | if (cda[CTA_TUPLE_ORIG-1]) | 665 | if (cda[CTA_TUPLE_ORIG-1]) |
666 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); | 666 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); |
667 | else if (cda[CTA_TUPLE_REPLY-1]) | 667 | else if (cda[CTA_TUPLE_REPLY-1]) |
668 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); | 668 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); |
669 | else { | 669 | else { |
670 | /* Flush the whole table */ | 670 | /* Flush the whole table */ |
671 | nf_conntrack_flush(); | 671 | nf_conntrack_flush(); |
672 | return 0; | 672 | return 0; |
673 | } | 673 | } |
674 | 674 | ||
675 | if (err < 0) | 675 | if (err < 0) |
676 | return err; | 676 | return err; |
677 | 677 | ||
678 | h = nf_conntrack_find_get(&tuple, NULL); | 678 | h = nf_conntrack_find_get(&tuple, NULL); |
679 | if (!h) | 679 | if (!h) |
680 | return -ENOENT; | 680 | return -ENOENT; |
681 | 681 | ||
682 | ct = nf_ct_tuplehash_to_ctrack(h); | 682 | ct = nf_ct_tuplehash_to_ctrack(h); |
683 | 683 | ||
684 | if (cda[CTA_ID-1]) { | 684 | if (cda[CTA_ID-1]) { |
685 | u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); | 685 | u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); |
686 | if (ct->id != id) { | 686 | if (ct->id != id) { |
687 | nf_ct_put(ct); | 687 | nf_ct_put(ct); |
688 | return -ENOENT; | 688 | return -ENOENT; |
689 | } | 689 | } |
690 | } | 690 | } |
691 | if (del_timer(&ct->timeout)) | 691 | if (del_timer(&ct->timeout)) |
692 | ct->timeout.function((unsigned long)ct); | 692 | ct->timeout.function((unsigned long)ct); |
693 | 693 | ||
694 | nf_ct_put(ct); | 694 | nf_ct_put(ct); |
695 | 695 | ||
696 | return 0; | 696 | return 0; |
697 | } | 697 | } |
698 | 698 | ||
699 | static int | 699 | static int |
700 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | 700 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, |
701 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 701 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
702 | { | 702 | { |
703 | struct nf_conntrack_tuple_hash *h; | 703 | struct nf_conntrack_tuple_hash *h; |
704 | struct nf_conntrack_tuple tuple; | 704 | struct nf_conntrack_tuple tuple; |
705 | struct nf_conn *ct; | 705 | struct nf_conn *ct; |
706 | struct sk_buff *skb2 = NULL; | 706 | struct sk_buff *skb2 = NULL; |
707 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 707 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
708 | u_int8_t u3 = nfmsg->nfgen_family; | 708 | u_int8_t u3 = nfmsg->nfgen_family; |
709 | int err = 0; | 709 | int err = 0; |
710 | 710 | ||
711 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 711 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
712 | u32 rlen; | 712 | u32 rlen; |
713 | 713 | ||
714 | #ifndef CONFIG_NF_CT_ACCT | 714 | #ifndef CONFIG_NF_CT_ACCT |
715 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) | 715 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) |
716 | return -ENOTSUPP; | 716 | return -ENOTSUPP; |
717 | #endif | 717 | #endif |
718 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 718 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
719 | ctnetlink_dump_table, | 719 | ctnetlink_dump_table, |
720 | ctnetlink_done)) != 0) | 720 | ctnetlink_done)) != 0) |
721 | return -EINVAL; | 721 | return -EINVAL; |
722 | 722 | ||
723 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 723 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
724 | if (rlen > skb->len) | 724 | if (rlen > skb->len) |
725 | rlen = skb->len; | 725 | rlen = skb->len; |
726 | skb_pull(skb, rlen); | 726 | skb_pull(skb, rlen); |
727 | return 0; | 727 | return 0; |
728 | } | 728 | } |
729 | 729 | ||
730 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 730 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
731 | return -EINVAL; | 731 | return -EINVAL; |
732 | 732 | ||
733 | if (cda[CTA_TUPLE_ORIG-1]) | 733 | if (cda[CTA_TUPLE_ORIG-1]) |
734 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); | 734 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); |
735 | else if (cda[CTA_TUPLE_REPLY-1]) | 735 | else if (cda[CTA_TUPLE_REPLY-1]) |
736 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); | 736 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); |
737 | else | 737 | else |
738 | return -EINVAL; | 738 | return -EINVAL; |
739 | 739 | ||
740 | if (err < 0) | 740 | if (err < 0) |
741 | return err; | 741 | return err; |
742 | 742 | ||
743 | h = nf_conntrack_find_get(&tuple, NULL); | 743 | h = nf_conntrack_find_get(&tuple, NULL); |
744 | if (!h) | 744 | if (!h) |
745 | return -ENOENT; | 745 | return -ENOENT; |
746 | 746 | ||
747 | ct = nf_ct_tuplehash_to_ctrack(h); | 747 | ct = nf_ct_tuplehash_to_ctrack(h); |
748 | 748 | ||
749 | err = -ENOMEM; | 749 | err = -ENOMEM; |
750 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 750 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
751 | if (!skb2) { | 751 | if (!skb2) { |
752 | nf_ct_put(ct); | 752 | nf_ct_put(ct); |
753 | return -ENOMEM; | 753 | return -ENOMEM; |
754 | } | 754 | } |
755 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | ||
756 | 755 | ||
757 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, | 756 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, |
758 | IPCTNL_MSG_CT_NEW, 1, ct); | 757 | IPCTNL_MSG_CT_NEW, 1, ct); |
759 | nf_ct_put(ct); | 758 | nf_ct_put(ct); |
760 | if (err <= 0) | 759 | if (err <= 0) |
761 | goto free; | 760 | goto free; |
762 | 761 | ||
763 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 762 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
764 | if (err < 0) | 763 | if (err < 0) |
765 | goto out; | 764 | goto out; |
766 | 765 | ||
767 | return 0; | 766 | return 0; |
768 | 767 | ||
769 | free: | 768 | free: |
770 | kfree_skb(skb2); | 769 | kfree_skb(skb2); |
771 | out: | 770 | out: |
772 | return err; | 771 | return err; |
773 | } | 772 | } |
774 | 773 | ||
775 | static inline int | 774 | static inline int |
776 | ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) | 775 | ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) |
777 | { | 776 | { |
778 | unsigned long d; | 777 | unsigned long d; |
779 | unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); | 778 | unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); |
780 | d = ct->status ^ status; | 779 | d = ct->status ^ status; |
781 | 780 | ||
782 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) | 781 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) |
783 | /* unchangeable */ | 782 | /* unchangeable */ |
784 | return -EINVAL; | 783 | return -EINVAL; |
785 | 784 | ||
786 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) | 785 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) |
787 | /* SEEN_REPLY bit can only be set */ | 786 | /* SEEN_REPLY bit can only be set */ |
788 | return -EINVAL; | 787 | return -EINVAL; |
789 | 788 | ||
790 | 789 | ||
791 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) | 790 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) |
792 | /* ASSURED bit can only be set */ | 791 | /* ASSURED bit can only be set */ |
793 | return -EINVAL; | 792 | return -EINVAL; |
794 | 793 | ||
795 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | 794 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { |
796 | #ifndef CONFIG_IP_NF_NAT_NEEDED | 795 | #ifndef CONFIG_IP_NF_NAT_NEEDED |
797 | return -EINVAL; | 796 | return -EINVAL; |
798 | #else | 797 | #else |
799 | struct ip_nat_range range; | 798 | struct ip_nat_range range; |
800 | 799 | ||
801 | if (cda[CTA_NAT_DST-1]) { | 800 | if (cda[CTA_NAT_DST-1]) { |
802 | if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, | 801 | if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, |
803 | &range) < 0) | 802 | &range) < 0) |
804 | return -EINVAL; | 803 | return -EINVAL; |
805 | if (ip_nat_initialized(ct, | 804 | if (ip_nat_initialized(ct, |
806 | HOOK2MANIP(NF_IP_PRE_ROUTING))) | 805 | HOOK2MANIP(NF_IP_PRE_ROUTING))) |
807 | return -EEXIST; | 806 | return -EEXIST; |
808 | ip_nat_setup_info(ct, &range, hooknum); | 807 | ip_nat_setup_info(ct, &range, hooknum); |
809 | } | 808 | } |
810 | if (cda[CTA_NAT_SRC-1]) { | 809 | if (cda[CTA_NAT_SRC-1]) { |
811 | if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, | 810 | if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, |
812 | &range) < 0) | 811 | &range) < 0) |
813 | return -EINVAL; | 812 | return -EINVAL; |
814 | if (ip_nat_initialized(ct, | 813 | if (ip_nat_initialized(ct, |
815 | HOOK2MANIP(NF_IP_POST_ROUTING))) | 814 | HOOK2MANIP(NF_IP_POST_ROUTING))) |
816 | return -EEXIST; | 815 | return -EEXIST; |
817 | ip_nat_setup_info(ct, &range, hooknum); | 816 | ip_nat_setup_info(ct, &range, hooknum); |
818 | } | 817 | } |
819 | #endif | 818 | #endif |
820 | } | 819 | } |
821 | 820 | ||
822 | /* Be careful here, modifying NAT bits can screw up things, | 821 | /* Be careful here, modifying NAT bits can screw up things, |
823 | * so don't let users modify them directly if they don't pass | 822 | * so don't let users modify them directly if they don't pass |
824 | * ip_nat_range. */ | 823 | * ip_nat_range. */ |
825 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); | 824 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); |
826 | return 0; | 825 | return 0; |
827 | } | 826 | } |
828 | 827 | ||
829 | 828 | ||
830 | static inline int | 829 | static inline int |
831 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | 830 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) |
832 | { | 831 | { |
833 | struct nf_conntrack_helper *helper; | 832 | struct nf_conntrack_helper *helper; |
834 | struct nf_conn_help *help = nfct_help(ct); | 833 | struct nf_conn_help *help = nfct_help(ct); |
835 | char *helpname; | 834 | char *helpname; |
836 | int err; | 835 | int err; |
837 | 836 | ||
838 | if (!help) { | 837 | if (!help) { |
839 | /* FIXME: we need to reallocate and rehash */ | 838 | /* FIXME: we need to reallocate and rehash */ |
840 | return -EBUSY; | 839 | return -EBUSY; |
841 | } | 840 | } |
842 | 841 | ||
843 | /* don't change helper of sibling connections */ | 842 | /* don't change helper of sibling connections */ |
844 | if (ct->master) | 843 | if (ct->master) |
845 | return -EINVAL; | 844 | return -EINVAL; |
846 | 845 | ||
847 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); | 846 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); |
848 | if (err < 0) | 847 | if (err < 0) |
849 | return err; | 848 | return err; |
850 | 849 | ||
851 | helper = __nf_conntrack_helper_find_byname(helpname); | 850 | helper = __nf_conntrack_helper_find_byname(helpname); |
852 | if (!helper) { | 851 | if (!helper) { |
853 | if (!strcmp(helpname, "")) | 852 | if (!strcmp(helpname, "")) |
854 | helper = NULL; | 853 | helper = NULL; |
855 | else | 854 | else |
856 | return -EINVAL; | 855 | return -EINVAL; |
857 | } | 856 | } |
858 | 857 | ||
859 | if (help->helper) { | 858 | if (help->helper) { |
860 | if (!helper) { | 859 | if (!helper) { |
861 | /* we had a helper before ... */ | 860 | /* we had a helper before ... */ |
862 | nf_ct_remove_expectations(ct); | 861 | nf_ct_remove_expectations(ct); |
863 | help->helper = NULL; | 862 | help->helper = NULL; |
864 | } else { | 863 | } else { |
865 | /* need to zero data of old helper */ | 864 | /* need to zero data of old helper */ |
866 | memset(&help->help, 0, sizeof(help->help)); | 865 | memset(&help->help, 0, sizeof(help->help)); |
867 | } | 866 | } |
868 | } | 867 | } |
869 | 868 | ||
870 | help->helper = helper; | 869 | help->helper = helper; |
871 | 870 | ||
872 | return 0; | 871 | return 0; |
873 | } | 872 | } |
874 | 873 | ||
875 | static inline int | 874 | static inline int |
876 | ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[]) | 875 | ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[]) |
877 | { | 876 | { |
878 | u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); | 877 | u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); |
879 | 878 | ||
880 | if (!del_timer(&ct->timeout)) | 879 | if (!del_timer(&ct->timeout)) |
881 | return -ETIME; | 880 | return -ETIME; |
882 | 881 | ||
883 | ct->timeout.expires = jiffies + timeout * HZ; | 882 | ct->timeout.expires = jiffies + timeout * HZ; |
884 | add_timer(&ct->timeout); | 883 | add_timer(&ct->timeout); |
885 | 884 | ||
886 | return 0; | 885 | return 0; |
887 | } | 886 | } |
888 | 887 | ||
889 | static inline int | 888 | static inline int |
890 | ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) | 889 | ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) |
891 | { | 890 | { |
892 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; | 891 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; |
893 | struct nf_conntrack_protocol *proto; | 892 | struct nf_conntrack_protocol *proto; |
894 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; | 893 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; |
895 | u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | 894 | u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; |
896 | int err = 0; | 895 | int err = 0; |
897 | 896 | ||
898 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); | 897 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); |
899 | 898 | ||
900 | proto = nf_ct_proto_find_get(l3num, npt); | 899 | proto = nf_ct_proto_find_get(l3num, npt); |
901 | 900 | ||
902 | if (proto->from_nfattr) | 901 | if (proto->from_nfattr) |
903 | err = proto->from_nfattr(tb, ct); | 902 | err = proto->from_nfattr(tb, ct); |
904 | nf_ct_proto_put(proto); | 903 | nf_ct_proto_put(proto); |
905 | 904 | ||
906 | return err; | 905 | return err; |
907 | } | 906 | } |
908 | 907 | ||
909 | static int | 908 | static int |
910 | ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) | 909 | ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) |
911 | { | 910 | { |
912 | int err; | 911 | int err; |
913 | 912 | ||
914 | if (cda[CTA_HELP-1]) { | 913 | if (cda[CTA_HELP-1]) { |
915 | err = ctnetlink_change_helper(ct, cda); | 914 | err = ctnetlink_change_helper(ct, cda); |
916 | if (err < 0) | 915 | if (err < 0) |
917 | return err; | 916 | return err; |
918 | } | 917 | } |
919 | 918 | ||
920 | if (cda[CTA_TIMEOUT-1]) { | 919 | if (cda[CTA_TIMEOUT-1]) { |
921 | err = ctnetlink_change_timeout(ct, cda); | 920 | err = ctnetlink_change_timeout(ct, cda); |
922 | if (err < 0) | 921 | if (err < 0) |
923 | return err; | 922 | return err; |
924 | } | 923 | } |
925 | 924 | ||
926 | if (cda[CTA_STATUS-1]) { | 925 | if (cda[CTA_STATUS-1]) { |
927 | err = ctnetlink_change_status(ct, cda); | 926 | err = ctnetlink_change_status(ct, cda); |
928 | if (err < 0) | 927 | if (err < 0) |
929 | return err; | 928 | return err; |
930 | } | 929 | } |
931 | 930 | ||
932 | if (cda[CTA_PROTOINFO-1]) { | 931 | if (cda[CTA_PROTOINFO-1]) { |
933 | err = ctnetlink_change_protoinfo(ct, cda); | 932 | err = ctnetlink_change_protoinfo(ct, cda); |
934 | if (err < 0) | 933 | if (err < 0) |
935 | return err; | 934 | return err; |
936 | } | 935 | } |
937 | 936 | ||
938 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 937 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
939 | if (cda[CTA_MARK-1]) | 938 | if (cda[CTA_MARK-1]) |
940 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | 939 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); |
941 | #endif | 940 | #endif |
942 | 941 | ||
943 | return 0; | 942 | return 0; |
944 | } | 943 | } |
945 | 944 | ||
946 | static int | 945 | static int |
947 | ctnetlink_create_conntrack(struct nfattr *cda[], | 946 | ctnetlink_create_conntrack(struct nfattr *cda[], |
948 | struct nf_conntrack_tuple *otuple, | 947 | struct nf_conntrack_tuple *otuple, |
949 | struct nf_conntrack_tuple *rtuple) | 948 | struct nf_conntrack_tuple *rtuple) |
950 | { | 949 | { |
951 | struct nf_conn *ct; | 950 | struct nf_conn *ct; |
952 | int err = -EINVAL; | 951 | int err = -EINVAL; |
953 | struct nf_conn_help *help; | 952 | struct nf_conn_help *help; |
954 | 953 | ||
955 | ct = nf_conntrack_alloc(otuple, rtuple); | 954 | ct = nf_conntrack_alloc(otuple, rtuple); |
956 | if (ct == NULL || IS_ERR(ct)) | 955 | if (ct == NULL || IS_ERR(ct)) |
957 | return -ENOMEM; | 956 | return -ENOMEM; |
958 | 957 | ||
959 | if (!cda[CTA_TIMEOUT-1]) | 958 | if (!cda[CTA_TIMEOUT-1]) |
960 | goto err; | 959 | goto err; |
961 | ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); | 960 | ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); |
962 | 961 | ||
963 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | 962 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; |
964 | ct->status |= IPS_CONFIRMED; | 963 | ct->status |= IPS_CONFIRMED; |
965 | 964 | ||
966 | err = ctnetlink_change_status(ct, cda); | 965 | err = ctnetlink_change_status(ct, cda); |
967 | if (err < 0) | 966 | if (err < 0) |
968 | goto err; | 967 | goto err; |
969 | 968 | ||
970 | if (cda[CTA_PROTOINFO-1]) { | 969 | if (cda[CTA_PROTOINFO-1]) { |
971 | err = ctnetlink_change_protoinfo(ct, cda); | 970 | err = ctnetlink_change_protoinfo(ct, cda); |
972 | if (err < 0) | 971 | if (err < 0) |
973 | return err; | 972 | return err; |
974 | } | 973 | } |
975 | 974 | ||
976 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 975 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
977 | if (cda[CTA_MARK-1]) | 976 | if (cda[CTA_MARK-1]) |
978 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | 977 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); |
979 | #endif | 978 | #endif |
980 | 979 | ||
981 | help = nfct_help(ct); | 980 | help = nfct_help(ct); |
982 | if (help) | 981 | if (help) |
983 | help->helper = nf_ct_helper_find_get(rtuple); | 982 | help->helper = nf_ct_helper_find_get(rtuple); |
984 | 983 | ||
985 | add_timer(&ct->timeout); | 984 | add_timer(&ct->timeout); |
986 | nf_conntrack_hash_insert(ct); | 985 | nf_conntrack_hash_insert(ct); |
987 | 986 | ||
988 | if (help && help->helper) | 987 | if (help && help->helper) |
989 | nf_ct_helper_put(help->helper); | 988 | nf_ct_helper_put(help->helper); |
990 | 989 | ||
991 | return 0; | 990 | return 0; |
992 | 991 | ||
993 | err: | 992 | err: |
994 | nf_conntrack_free(ct); | 993 | nf_conntrack_free(ct); |
995 | return err; | 994 | return err; |
996 | } | 995 | } |
997 | 996 | ||
998 | static int | 997 | static int |
999 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | 998 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, |
1000 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 999 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1001 | { | 1000 | { |
1002 | struct nf_conntrack_tuple otuple, rtuple; | 1001 | struct nf_conntrack_tuple otuple, rtuple; |
1003 | struct nf_conntrack_tuple_hash *h = NULL; | 1002 | struct nf_conntrack_tuple_hash *h = NULL; |
1004 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 1003 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
1005 | u_int8_t u3 = nfmsg->nfgen_family; | 1004 | u_int8_t u3 = nfmsg->nfgen_family; |
1006 | int err = 0; | 1005 | int err = 0; |
1007 | 1006 | ||
1008 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 1007 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
1009 | return -EINVAL; | 1008 | return -EINVAL; |
1010 | 1009 | ||
1011 | if (cda[CTA_TUPLE_ORIG-1]) { | 1010 | if (cda[CTA_TUPLE_ORIG-1]) { |
1012 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); | 1011 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); |
1013 | if (err < 0) | 1012 | if (err < 0) |
1014 | return err; | 1013 | return err; |
1015 | } | 1014 | } |
1016 | 1015 | ||
1017 | if (cda[CTA_TUPLE_REPLY-1]) { | 1016 | if (cda[CTA_TUPLE_REPLY-1]) { |
1018 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3); | 1017 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3); |
1019 | if (err < 0) | 1018 | if (err < 0) |
1020 | return err; | 1019 | return err; |
1021 | } | 1020 | } |
1022 | 1021 | ||
1023 | write_lock_bh(&nf_conntrack_lock); | 1022 | write_lock_bh(&nf_conntrack_lock); |
1024 | if (cda[CTA_TUPLE_ORIG-1]) | 1023 | if (cda[CTA_TUPLE_ORIG-1]) |
1025 | h = __nf_conntrack_find(&otuple, NULL); | 1024 | h = __nf_conntrack_find(&otuple, NULL); |
1026 | else if (cda[CTA_TUPLE_REPLY-1]) | 1025 | else if (cda[CTA_TUPLE_REPLY-1]) |
1027 | h = __nf_conntrack_find(&rtuple, NULL); | 1026 | h = __nf_conntrack_find(&rtuple, NULL); |
1028 | 1027 | ||
1029 | if (h == NULL) { | 1028 | if (h == NULL) { |
1030 | write_unlock_bh(&nf_conntrack_lock); | 1029 | write_unlock_bh(&nf_conntrack_lock); |
1031 | err = -ENOENT; | 1030 | err = -ENOENT; |
1032 | if (nlh->nlmsg_flags & NLM_F_CREATE) | 1031 | if (nlh->nlmsg_flags & NLM_F_CREATE) |
1033 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); | 1032 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); |
1034 | return err; | 1033 | return err; |
1035 | } | 1034 | } |
1036 | /* implicit 'else' */ | 1035 | /* implicit 'else' */ |
1037 | 1036 | ||
1038 | /* we only allow nat config for new conntracks */ | 1037 | /* we only allow nat config for new conntracks */ |
1039 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | 1038 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { |
1040 | err = -EINVAL; | 1039 | err = -EINVAL; |
1041 | goto out_unlock; | 1040 | goto out_unlock; |
1042 | } | 1041 | } |
1043 | 1042 | ||
1044 | /* We manipulate the conntrack inside the global conntrack table lock, | 1043 | /* We manipulate the conntrack inside the global conntrack table lock, |
1045 | * so there's no need to increase the refcount */ | 1044 | * so there's no need to increase the refcount */ |
1046 | err = -EEXIST; | 1045 | err = -EEXIST; |
1047 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | 1046 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) |
1048 | err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda); | 1047 | err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda); |
1049 | 1048 | ||
1050 | out_unlock: | 1049 | out_unlock: |
1051 | write_unlock_bh(&nf_conntrack_lock); | 1050 | write_unlock_bh(&nf_conntrack_lock); |
1052 | return err; | 1051 | return err; |
1053 | } | 1052 | } |
1054 | 1053 | ||
1055 | /*********************************************************************** | 1054 | /*********************************************************************** |
1056 | * EXPECT | 1055 | * EXPECT |
1057 | ***********************************************************************/ | 1056 | ***********************************************************************/ |
1058 | 1057 | ||
1059 | static inline int | 1058 | static inline int |
1060 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, | 1059 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, |
1061 | const struct nf_conntrack_tuple *tuple, | 1060 | const struct nf_conntrack_tuple *tuple, |
1062 | enum ctattr_expect type) | 1061 | enum ctattr_expect type) |
1063 | { | 1062 | { |
1064 | struct nfattr *nest_parms = NFA_NEST(skb, type); | 1063 | struct nfattr *nest_parms = NFA_NEST(skb, type); |
1065 | 1064 | ||
1066 | if (ctnetlink_dump_tuples(skb, tuple) < 0) | 1065 | if (ctnetlink_dump_tuples(skb, tuple) < 0) |
1067 | goto nfattr_failure; | 1066 | goto nfattr_failure; |
1068 | 1067 | ||
1069 | NFA_NEST_END(skb, nest_parms); | 1068 | NFA_NEST_END(skb, nest_parms); |
1070 | 1069 | ||
1071 | return 0; | 1070 | return 0; |
1072 | 1071 | ||
1073 | nfattr_failure: | 1072 | nfattr_failure: |
1074 | return -1; | 1073 | return -1; |
1075 | } | 1074 | } |
1076 | 1075 | ||
1077 | static inline int | 1076 | static inline int |
1078 | ctnetlink_exp_dump_mask(struct sk_buff *skb, | 1077 | ctnetlink_exp_dump_mask(struct sk_buff *skb, |
1079 | const struct nf_conntrack_tuple *tuple, | 1078 | const struct nf_conntrack_tuple *tuple, |
1080 | const struct nf_conntrack_tuple *mask) | 1079 | const struct nf_conntrack_tuple *mask) |
1081 | { | 1080 | { |
1082 | int ret; | 1081 | int ret; |
1083 | struct nf_conntrack_l3proto *l3proto; | 1082 | struct nf_conntrack_l3proto *l3proto; |
1084 | struct nf_conntrack_protocol *proto; | 1083 | struct nf_conntrack_protocol *proto; |
1085 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); | 1084 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); |
1086 | 1085 | ||
1087 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | 1086 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); |
1088 | ret = ctnetlink_dump_tuples_ip(skb, mask, l3proto); | 1087 | ret = ctnetlink_dump_tuples_ip(skb, mask, l3proto); |
1089 | nf_ct_l3proto_put(l3proto); | 1088 | nf_ct_l3proto_put(l3proto); |
1090 | 1089 | ||
1091 | if (unlikely(ret < 0)) | 1090 | if (unlikely(ret < 0)) |
1092 | goto nfattr_failure; | 1091 | goto nfattr_failure; |
1093 | 1092 | ||
1094 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | 1093 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); |
1095 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); | 1094 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); |
1096 | nf_ct_proto_put(proto); | 1095 | nf_ct_proto_put(proto); |
1097 | if (unlikely(ret < 0)) | 1096 | if (unlikely(ret < 0)) |
1098 | goto nfattr_failure; | 1097 | goto nfattr_failure; |
1099 | 1098 | ||
1100 | NFA_NEST_END(skb, nest_parms); | 1099 | NFA_NEST_END(skb, nest_parms); |
1101 | 1100 | ||
1102 | return 0; | 1101 | return 0; |
1103 | 1102 | ||
1104 | nfattr_failure: | 1103 | nfattr_failure: |
1105 | return -1; | 1104 | return -1; |
1106 | } | 1105 | } |
1107 | 1106 | ||
1108 | static inline int | 1107 | static inline int |
1109 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 1108 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
1110 | const struct nf_conntrack_expect *exp) | 1109 | const struct nf_conntrack_expect *exp) |
1111 | { | 1110 | { |
1112 | struct nf_conn *master = exp->master; | 1111 | struct nf_conn *master = exp->master; |
1113 | u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ); | 1112 | u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ); |
1114 | u_int32_t id = htonl(exp->id); | 1113 | u_int32_t id = htonl(exp->id); |
1115 | 1114 | ||
1116 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | 1115 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) |
1117 | goto nfattr_failure; | 1116 | goto nfattr_failure; |
1118 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) | 1117 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) |
1119 | goto nfattr_failure; | 1118 | goto nfattr_failure; |
1120 | if (ctnetlink_exp_dump_tuple(skb, | 1119 | if (ctnetlink_exp_dump_tuple(skb, |
1121 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 1120 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
1122 | CTA_EXPECT_MASTER) < 0) | 1121 | CTA_EXPECT_MASTER) < 0) |
1123 | goto nfattr_failure; | 1122 | goto nfattr_failure; |
1124 | 1123 | ||
1125 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); | 1124 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); |
1126 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); | 1125 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); |
1127 | 1126 | ||
1128 | return 0; | 1127 | return 0; |
1129 | 1128 | ||
1130 | nfattr_failure: | 1129 | nfattr_failure: |
1131 | return -1; | 1130 | return -1; |
1132 | } | 1131 | } |
1133 | 1132 | ||
1134 | static int | 1133 | static int |
1135 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | 1134 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, |
1136 | int event, | 1135 | int event, |
1137 | int nowait, | 1136 | int nowait, |
1138 | const struct nf_conntrack_expect *exp) | 1137 | const struct nf_conntrack_expect *exp) |
1139 | { | 1138 | { |
1140 | struct nlmsghdr *nlh; | 1139 | struct nlmsghdr *nlh; |
1141 | struct nfgenmsg *nfmsg; | 1140 | struct nfgenmsg *nfmsg; |
1142 | unsigned char *b; | 1141 | unsigned char *b; |
1143 | 1142 | ||
1144 | b = skb->tail; | 1143 | b = skb->tail; |
1145 | 1144 | ||
1146 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | 1145 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; |
1147 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | 1146 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); |
1148 | nfmsg = NLMSG_DATA(nlh); | 1147 | nfmsg = NLMSG_DATA(nlh); |
1149 | 1148 | ||
1150 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | 1149 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; |
1151 | nfmsg->nfgen_family = exp->tuple.src.l3num; | 1150 | nfmsg->nfgen_family = exp->tuple.src.l3num; |
1152 | nfmsg->version = NFNETLINK_V0; | 1151 | nfmsg->version = NFNETLINK_V0; |
1153 | nfmsg->res_id = 0; | 1152 | nfmsg->res_id = 0; |
1154 | 1153 | ||
1155 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | 1154 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) |
1156 | goto nfattr_failure; | 1155 | goto nfattr_failure; |
1157 | 1156 | ||
1158 | nlh->nlmsg_len = skb->tail - b; | 1157 | nlh->nlmsg_len = skb->tail - b; |
1159 | return skb->len; | 1158 | return skb->len; |
1160 | 1159 | ||
1161 | nlmsg_failure: | 1160 | nlmsg_failure: |
1162 | nfattr_failure: | 1161 | nfattr_failure: |
1163 | skb_trim(skb, b - skb->data); | 1162 | skb_trim(skb, b - skb->data); |
1164 | return -1; | 1163 | return -1; |
1165 | } | 1164 | } |
1166 | 1165 | ||
1167 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 1166 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1168 | static int ctnetlink_expect_event(struct notifier_block *this, | 1167 | static int ctnetlink_expect_event(struct notifier_block *this, |
1169 | unsigned long events, void *ptr) | 1168 | unsigned long events, void *ptr) |
1170 | { | 1169 | { |
1171 | struct nlmsghdr *nlh; | 1170 | struct nlmsghdr *nlh; |
1172 | struct nfgenmsg *nfmsg; | 1171 | struct nfgenmsg *nfmsg; |
1173 | struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr; | 1172 | struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr; |
1174 | struct sk_buff *skb; | 1173 | struct sk_buff *skb; |
1175 | unsigned int type; | 1174 | unsigned int type; |
1176 | unsigned char *b; | 1175 | unsigned char *b; |
1177 | int flags = 0; | 1176 | int flags = 0; |
1178 | 1177 | ||
1179 | if (events & IPEXP_NEW) { | 1178 | if (events & IPEXP_NEW) { |
1180 | type = IPCTNL_MSG_EXP_NEW; | 1179 | type = IPCTNL_MSG_EXP_NEW; |
1181 | flags = NLM_F_CREATE|NLM_F_EXCL; | 1180 | flags = NLM_F_CREATE|NLM_F_EXCL; |
1182 | } else | 1181 | } else |
1183 | return NOTIFY_DONE; | 1182 | return NOTIFY_DONE; |
1184 | 1183 | ||
1185 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) | 1184 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) |
1186 | return NOTIFY_DONE; | 1185 | return NOTIFY_DONE; |
1187 | 1186 | ||
1188 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 1187 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
1189 | if (!skb) | 1188 | if (!skb) |
1190 | return NOTIFY_DONE; | 1189 | return NOTIFY_DONE; |
1191 | 1190 | ||
1192 | b = skb->tail; | 1191 | b = skb->tail; |
1193 | 1192 | ||
1194 | type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | 1193 | type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; |
1195 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | 1194 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); |
1196 | nfmsg = NLMSG_DATA(nlh); | 1195 | nfmsg = NLMSG_DATA(nlh); |
1197 | 1196 | ||
1198 | nlh->nlmsg_flags = flags; | 1197 | nlh->nlmsg_flags = flags; |
1199 | nfmsg->nfgen_family = exp->tuple.src.l3num; | 1198 | nfmsg->nfgen_family = exp->tuple.src.l3num; |
1200 | nfmsg->version = NFNETLINK_V0; | 1199 | nfmsg->version = NFNETLINK_V0; |
1201 | nfmsg->res_id = 0; | 1200 | nfmsg->res_id = 0; |
1202 | 1201 | ||
1203 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | 1202 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) |
1204 | goto nfattr_failure; | 1203 | goto nfattr_failure; |
1205 | 1204 | ||
1206 | nlh->nlmsg_len = skb->tail - b; | 1205 | nlh->nlmsg_len = skb->tail - b; |
1207 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); | 1206 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); |
1208 | return NOTIFY_DONE; | 1207 | return NOTIFY_DONE; |
1209 | 1208 | ||
1210 | nlmsg_failure: | 1209 | nlmsg_failure: |
1211 | nfattr_failure: | 1210 | nfattr_failure: |
1212 | kfree_skb(skb); | 1211 | kfree_skb(skb); |
1213 | return NOTIFY_DONE; | 1212 | return NOTIFY_DONE; |
1214 | } | 1213 | } |
1215 | #endif | 1214 | #endif |
1216 | 1215 | ||
1217 | static int | 1216 | static int |
1218 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 1217 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
1219 | { | 1218 | { |
1220 | struct nf_conntrack_expect *exp = NULL; | 1219 | struct nf_conntrack_expect *exp = NULL; |
1221 | struct list_head *i; | 1220 | struct list_head *i; |
1222 | u_int32_t *id = (u_int32_t *) &cb->args[0]; | 1221 | u_int32_t *id = (u_int32_t *) &cb->args[0]; |
1223 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 1222 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
1224 | u_int8_t l3proto = nfmsg->nfgen_family; | 1223 | u_int8_t l3proto = nfmsg->nfgen_family; |
1225 | 1224 | ||
1226 | read_lock_bh(&nf_conntrack_lock); | 1225 | read_lock_bh(&nf_conntrack_lock); |
1227 | list_for_each_prev(i, &nf_conntrack_expect_list) { | 1226 | list_for_each_prev(i, &nf_conntrack_expect_list) { |
1228 | exp = (struct nf_conntrack_expect *) i; | 1227 | exp = (struct nf_conntrack_expect *) i; |
1229 | if (l3proto && exp->tuple.src.l3num != l3proto) | 1228 | if (l3proto && exp->tuple.src.l3num != l3proto) |
1230 | continue; | 1229 | continue; |
1231 | if (exp->id <= *id) | 1230 | if (exp->id <= *id) |
1232 | continue; | 1231 | continue; |
1233 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, | 1232 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, |
1234 | cb->nlh->nlmsg_seq, | 1233 | cb->nlh->nlmsg_seq, |
1235 | IPCTNL_MSG_EXP_NEW, | 1234 | IPCTNL_MSG_EXP_NEW, |
1236 | 1, exp) < 0) | 1235 | 1, exp) < 0) |
1237 | goto out; | 1236 | goto out; |
1238 | *id = exp->id; | 1237 | *id = exp->id; |
1239 | } | 1238 | } |
1240 | out: | 1239 | out: |
1241 | read_unlock_bh(&nf_conntrack_lock); | 1240 | read_unlock_bh(&nf_conntrack_lock); |
1242 | 1241 | ||
1243 | return skb->len; | 1242 | return skb->len; |
1244 | } | 1243 | } |
1245 | 1244 | ||
1246 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { | 1245 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { |
1247 | [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t), | 1246 | [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t), |
1248 | [CTA_EXPECT_ID-1] = sizeof(u_int32_t) | 1247 | [CTA_EXPECT_ID-1] = sizeof(u_int32_t) |
1249 | }; | 1248 | }; |
1250 | 1249 | ||
1251 | static int | 1250 | static int |
1252 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | 1251 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, |
1253 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1252 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1254 | { | 1253 | { |
1255 | struct nf_conntrack_tuple tuple; | 1254 | struct nf_conntrack_tuple tuple; |
1256 | struct nf_conntrack_expect *exp; | 1255 | struct nf_conntrack_expect *exp; |
1257 | struct sk_buff *skb2; | 1256 | struct sk_buff *skb2; |
1258 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 1257 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
1259 | u_int8_t u3 = nfmsg->nfgen_family; | 1258 | u_int8_t u3 = nfmsg->nfgen_family; |
1260 | int err = 0; | 1259 | int err = 0; |
1261 | 1260 | ||
1262 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1261 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1263 | return -EINVAL; | 1262 | return -EINVAL; |
1264 | 1263 | ||
1265 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 1264 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
1266 | u32 rlen; | 1265 | u32 rlen; |
1267 | 1266 | ||
1268 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 1267 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
1269 | ctnetlink_exp_dump_table, | 1268 | ctnetlink_exp_dump_table, |
1270 | ctnetlink_done)) != 0) | 1269 | ctnetlink_done)) != 0) |
1271 | return -EINVAL; | 1270 | return -EINVAL; |
1272 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 1271 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
1273 | if (rlen > skb->len) | 1272 | if (rlen > skb->len) |
1274 | rlen = skb->len; | 1273 | rlen = skb->len; |
1275 | skb_pull(skb, rlen); | 1274 | skb_pull(skb, rlen); |
1276 | return 0; | 1275 | return 0; |
1277 | } | 1276 | } |
1278 | 1277 | ||
1279 | if (cda[CTA_EXPECT_MASTER-1]) | 1278 | if (cda[CTA_EXPECT_MASTER-1]) |
1280 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3); | 1279 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3); |
1281 | else | 1280 | else |
1282 | return -EINVAL; | 1281 | return -EINVAL; |
1283 | 1282 | ||
1284 | if (err < 0) | 1283 | if (err < 0) |
1285 | return err; | 1284 | return err; |
1286 | 1285 | ||
1287 | exp = nf_conntrack_expect_find(&tuple); | 1286 | exp = nf_conntrack_expect_find(&tuple); |
1288 | if (!exp) | 1287 | if (!exp) |
1289 | return -ENOENT; | 1288 | return -ENOENT; |
1290 | 1289 | ||
1291 | if (cda[CTA_EXPECT_ID-1]) { | 1290 | if (cda[CTA_EXPECT_ID-1]) { |
1292 | u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | 1291 | u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); |
1293 | if (exp->id != ntohl(id)) { | 1292 | if (exp->id != ntohl(id)) { |
1294 | nf_conntrack_expect_put(exp); | 1293 | nf_conntrack_expect_put(exp); |
1295 | return -ENOENT; | 1294 | return -ENOENT; |
1296 | } | 1295 | } |
1297 | } | 1296 | } |
1298 | 1297 | ||
1299 | err = -ENOMEM; | 1298 | err = -ENOMEM; |
1300 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 1299 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1301 | if (!skb2) | 1300 | if (!skb2) |
1302 | goto out; | 1301 | goto out; |
1303 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | 1302 | |
1304 | |||
1305 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, | 1303 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, |
1306 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, | 1304 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, |
1307 | 1, exp); | 1305 | 1, exp); |
1308 | if (err <= 0) | 1306 | if (err <= 0) |
1309 | goto free; | 1307 | goto free; |
1310 | 1308 | ||
1311 | nf_conntrack_expect_put(exp); | 1309 | nf_conntrack_expect_put(exp); |
1312 | 1310 | ||
1313 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1311 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1314 | 1312 | ||
1315 | free: | 1313 | free: |
1316 | kfree_skb(skb2); | 1314 | kfree_skb(skb2); |
1317 | out: | 1315 | out: |
1318 | nf_conntrack_expect_put(exp); | 1316 | nf_conntrack_expect_put(exp); |
1319 | return err; | 1317 | return err; |
1320 | } | 1318 | } |
1321 | 1319 | ||
1322 | static int | 1320 | static int |
1323 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | 1321 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, |
1324 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1322 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1325 | { | 1323 | { |
1326 | struct nf_conntrack_expect *exp, *tmp; | 1324 | struct nf_conntrack_expect *exp, *tmp; |
1327 | struct nf_conntrack_tuple tuple; | 1325 | struct nf_conntrack_tuple tuple; |
1328 | struct nf_conntrack_helper *h; | 1326 | struct nf_conntrack_helper *h; |
1329 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 1327 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
1330 | u_int8_t u3 = nfmsg->nfgen_family; | 1328 | u_int8_t u3 = nfmsg->nfgen_family; |
1331 | int err; | 1329 | int err; |
1332 | 1330 | ||
1333 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1331 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1334 | return -EINVAL; | 1332 | return -EINVAL; |
1335 | 1333 | ||
1336 | if (cda[CTA_EXPECT_TUPLE-1]) { | 1334 | if (cda[CTA_EXPECT_TUPLE-1]) { |
1337 | /* delete a single expect by tuple */ | 1335 | /* delete a single expect by tuple */ |
1338 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | 1336 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); |
1339 | if (err < 0) | 1337 | if (err < 0) |
1340 | return err; | 1338 | return err; |
1341 | 1339 | ||
1342 | /* bump usage count to 2 */ | 1340 | /* bump usage count to 2 */ |
1343 | exp = nf_conntrack_expect_find(&tuple); | 1341 | exp = nf_conntrack_expect_find(&tuple); |
1344 | if (!exp) | 1342 | if (!exp) |
1345 | return -ENOENT; | 1343 | return -ENOENT; |
1346 | 1344 | ||
1347 | if (cda[CTA_EXPECT_ID-1]) { | 1345 | if (cda[CTA_EXPECT_ID-1]) { |
1348 | u_int32_t id = | 1346 | u_int32_t id = |
1349 | *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | 1347 | *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); |
1350 | if (exp->id != ntohl(id)) { | 1348 | if (exp->id != ntohl(id)) { |
1351 | nf_conntrack_expect_put(exp); | 1349 | nf_conntrack_expect_put(exp); |
1352 | return -ENOENT; | 1350 | return -ENOENT; |
1353 | } | 1351 | } |
1354 | } | 1352 | } |
1355 | 1353 | ||
1356 | /* after list removal, usage count == 1 */ | 1354 | /* after list removal, usage count == 1 */ |
1357 | nf_conntrack_unexpect_related(exp); | 1355 | nf_conntrack_unexpect_related(exp); |
1358 | /* have to put what we 'get' above. | 1356 | /* have to put what we 'get' above. |
1359 | * after this line usage count == 0 */ | 1357 | * after this line usage count == 0 */ |
1360 | nf_conntrack_expect_put(exp); | 1358 | nf_conntrack_expect_put(exp); |
1361 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { | 1359 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { |
1362 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); | 1360 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); |
1363 | 1361 | ||
1364 | /* delete all expectations for this helper */ | 1362 | /* delete all expectations for this helper */ |
1365 | write_lock_bh(&nf_conntrack_lock); | 1363 | write_lock_bh(&nf_conntrack_lock); |
1366 | h = __nf_conntrack_helper_find_byname(name); | 1364 | h = __nf_conntrack_helper_find_byname(name); |
1367 | if (!h) { | 1365 | if (!h) { |
1368 | write_unlock_bh(&nf_conntrack_lock); | 1366 | write_unlock_bh(&nf_conntrack_lock); |
1369 | return -EINVAL; | 1367 | return -EINVAL; |
1370 | } | 1368 | } |
1371 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | 1369 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, |
1372 | list) { | 1370 | list) { |
1373 | struct nf_conn_help *m_help = nfct_help(exp->master); | 1371 | struct nf_conn_help *m_help = nfct_help(exp->master); |
1374 | if (m_help->helper == h | 1372 | if (m_help->helper == h |
1375 | && del_timer(&exp->timeout)) { | 1373 | && del_timer(&exp->timeout)) { |
1376 | nf_ct_unlink_expect(exp); | 1374 | nf_ct_unlink_expect(exp); |
1377 | nf_conntrack_expect_put(exp); | 1375 | nf_conntrack_expect_put(exp); |
1378 | } | 1376 | } |
1379 | } | 1377 | } |
1380 | write_unlock_bh(&nf_conntrack_lock); | 1378 | write_unlock_bh(&nf_conntrack_lock); |
1381 | } else { | 1379 | } else { |
1382 | /* This basically means we have to flush everything*/ | 1380 | /* This basically means we have to flush everything*/ |
1383 | write_lock_bh(&nf_conntrack_lock); | 1381 | write_lock_bh(&nf_conntrack_lock); |
1384 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | 1382 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, |
1385 | list) { | 1383 | list) { |
1386 | if (del_timer(&exp->timeout)) { | 1384 | if (del_timer(&exp->timeout)) { |
1387 | nf_ct_unlink_expect(exp); | 1385 | nf_ct_unlink_expect(exp); |
1388 | nf_conntrack_expect_put(exp); | 1386 | nf_conntrack_expect_put(exp); |
1389 | } | 1387 | } |
1390 | } | 1388 | } |
1391 | write_unlock_bh(&nf_conntrack_lock); | 1389 | write_unlock_bh(&nf_conntrack_lock); |
1392 | } | 1390 | } |
1393 | 1391 | ||
1394 | return 0; | 1392 | return 0; |
1395 | } | 1393 | } |
1396 | static int | 1394 | static int |
1397 | ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nfattr *cda[]) | 1395 | ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nfattr *cda[]) |
1398 | { | 1396 | { |
1399 | return -EOPNOTSUPP; | 1397 | return -EOPNOTSUPP; |
1400 | } | 1398 | } |
1401 | 1399 | ||
1402 | static int | 1400 | static int |
1403 | ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | 1401 | ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) |
1404 | { | 1402 | { |
1405 | struct nf_conntrack_tuple tuple, mask, master_tuple; | 1403 | struct nf_conntrack_tuple tuple, mask, master_tuple; |
1406 | struct nf_conntrack_tuple_hash *h = NULL; | 1404 | struct nf_conntrack_tuple_hash *h = NULL; |
1407 | struct nf_conntrack_expect *exp; | 1405 | struct nf_conntrack_expect *exp; |
1408 | struct nf_conn *ct; | 1406 | struct nf_conn *ct; |
1409 | struct nf_conn_help *help; | 1407 | struct nf_conn_help *help; |
1410 | int err = 0; | 1408 | int err = 0; |
1411 | 1409 | ||
1412 | /* caller guarantees that those three CTA_EXPECT_* exist */ | 1410 | /* caller guarantees that those three CTA_EXPECT_* exist */ |
1413 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | 1411 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); |
1414 | if (err < 0) | 1412 | if (err < 0) |
1415 | return err; | 1413 | return err; |
1416 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3); | 1414 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3); |
1417 | if (err < 0) | 1415 | if (err < 0) |
1418 | return err; | 1416 | return err; |
1419 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3); | 1417 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3); |
1420 | if (err < 0) | 1418 | if (err < 0) |
1421 | return err; | 1419 | return err; |
1422 | 1420 | ||
1423 | /* Look for master conntrack of this expectation */ | 1421 | /* Look for master conntrack of this expectation */ |
1424 | h = nf_conntrack_find_get(&master_tuple, NULL); | 1422 | h = nf_conntrack_find_get(&master_tuple, NULL); |
1425 | if (!h) | 1423 | if (!h) |
1426 | return -ENOENT; | 1424 | return -ENOENT; |
1427 | ct = nf_ct_tuplehash_to_ctrack(h); | 1425 | ct = nf_ct_tuplehash_to_ctrack(h); |
1428 | help = nfct_help(ct); | 1426 | help = nfct_help(ct); |
1429 | 1427 | ||
1430 | if (!help || !help->helper) { | 1428 | if (!help || !help->helper) { |
1431 | /* such conntrack hasn't got any helper, abort */ | 1429 | /* such conntrack hasn't got any helper, abort */ |
1432 | err = -EINVAL; | 1430 | err = -EINVAL; |
1433 | goto out; | 1431 | goto out; |
1434 | } | 1432 | } |
1435 | 1433 | ||
1436 | exp = nf_conntrack_expect_alloc(ct); | 1434 | exp = nf_conntrack_expect_alloc(ct); |
1437 | if (!exp) { | 1435 | if (!exp) { |
1438 | err = -ENOMEM; | 1436 | err = -ENOMEM; |
1439 | goto out; | 1437 | goto out; |
1440 | } | 1438 | } |
1441 | 1439 | ||
1442 | exp->expectfn = NULL; | 1440 | exp->expectfn = NULL; |
1443 | exp->flags = 0; | 1441 | exp->flags = 0; |
1444 | exp->master = ct; | 1442 | exp->master = ct; |
1445 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); | 1443 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); |
1446 | memcpy(&exp->mask, &mask, sizeof(struct nf_conntrack_tuple)); | 1444 | memcpy(&exp->mask, &mask, sizeof(struct nf_conntrack_tuple)); |
1447 | 1445 | ||
1448 | err = nf_conntrack_expect_related(exp); | 1446 | err = nf_conntrack_expect_related(exp); |
1449 | nf_conntrack_expect_put(exp); | 1447 | nf_conntrack_expect_put(exp); |
1450 | 1448 | ||
1451 | out: | 1449 | out: |
1452 | nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); | 1450 | nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); |
1453 | return err; | 1451 | return err; |
1454 | } | 1452 | } |
1455 | 1453 | ||
1456 | static int | 1454 | static int |
1457 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | 1455 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, |
1458 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1456 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) |
1459 | { | 1457 | { |
1460 | struct nf_conntrack_tuple tuple; | 1458 | struct nf_conntrack_tuple tuple; |
1461 | struct nf_conntrack_expect *exp; | 1459 | struct nf_conntrack_expect *exp; |
1462 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 1460 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
1463 | u_int8_t u3 = nfmsg->nfgen_family; | 1461 | u_int8_t u3 = nfmsg->nfgen_family; |
1464 | int err = 0; | 1462 | int err = 0; |
1465 | 1463 | ||
1466 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | 1464 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) |
1467 | return -EINVAL; | 1465 | return -EINVAL; |
1468 | 1466 | ||
1469 | if (!cda[CTA_EXPECT_TUPLE-1] | 1467 | if (!cda[CTA_EXPECT_TUPLE-1] |
1470 | || !cda[CTA_EXPECT_MASK-1] | 1468 | || !cda[CTA_EXPECT_MASK-1] |
1471 | || !cda[CTA_EXPECT_MASTER-1]) | 1469 | || !cda[CTA_EXPECT_MASTER-1]) |
1472 | return -EINVAL; | 1470 | return -EINVAL; |
1473 | 1471 | ||
1474 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | 1472 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); |
1475 | if (err < 0) | 1473 | if (err < 0) |
1476 | return err; | 1474 | return err; |
1477 | 1475 | ||
1478 | write_lock_bh(&nf_conntrack_lock); | 1476 | write_lock_bh(&nf_conntrack_lock); |
1479 | exp = __nf_conntrack_expect_find(&tuple); | 1477 | exp = __nf_conntrack_expect_find(&tuple); |
1480 | 1478 | ||
1481 | if (!exp) { | 1479 | if (!exp) { |
1482 | write_unlock_bh(&nf_conntrack_lock); | 1480 | write_unlock_bh(&nf_conntrack_lock); |
1483 | err = -ENOENT; | 1481 | err = -ENOENT; |
1484 | if (nlh->nlmsg_flags & NLM_F_CREATE) | 1482 | if (nlh->nlmsg_flags & NLM_F_CREATE) |
1485 | err = ctnetlink_create_expect(cda, u3); | 1483 | err = ctnetlink_create_expect(cda, u3); |
1486 | return err; | 1484 | return err; |
1487 | } | 1485 | } |
1488 | 1486 | ||
1489 | err = -EEXIST; | 1487 | err = -EEXIST; |
1490 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | 1488 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) |
1491 | err = ctnetlink_change_expect(exp, cda); | 1489 | err = ctnetlink_change_expect(exp, cda); |
1492 | write_unlock_bh(&nf_conntrack_lock); | 1490 | write_unlock_bh(&nf_conntrack_lock); |
1493 | 1491 | ||
1494 | return err; | 1492 | return err; |
1495 | } | 1493 | } |
1496 | 1494 | ||
1497 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 1495 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1498 | static struct notifier_block ctnl_notifier = { | 1496 | static struct notifier_block ctnl_notifier = { |
1499 | .notifier_call = ctnetlink_conntrack_event, | 1497 | .notifier_call = ctnetlink_conntrack_event, |
1500 | }; | 1498 | }; |
1501 | 1499 | ||
1502 | static struct notifier_block ctnl_notifier_exp = { | 1500 | static struct notifier_block ctnl_notifier_exp = { |
1503 | .notifier_call = ctnetlink_expect_event, | 1501 | .notifier_call = ctnetlink_expect_event, |
1504 | }; | 1502 | }; |
1505 | #endif | 1503 | #endif |
1506 | 1504 | ||
1507 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { | 1505 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { |
1508 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, | 1506 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, |
1509 | .attr_count = CTA_MAX, }, | 1507 | .attr_count = CTA_MAX, }, |
1510 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, | 1508 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, |
1511 | .attr_count = CTA_MAX, }, | 1509 | .attr_count = CTA_MAX, }, |
1512 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, | 1510 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, |
1513 | .attr_count = CTA_MAX, }, | 1511 | .attr_count = CTA_MAX, }, |
1514 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, | 1512 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, |
1515 | .attr_count = CTA_MAX, }, | 1513 | .attr_count = CTA_MAX, }, |
1516 | }; | 1514 | }; |
1517 | 1515 | ||
1518 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | 1516 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { |
1519 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, | 1517 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, |
1520 | .attr_count = CTA_EXPECT_MAX, }, | 1518 | .attr_count = CTA_EXPECT_MAX, }, |
1521 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, | 1519 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, |
1522 | .attr_count = CTA_EXPECT_MAX, }, | 1520 | .attr_count = CTA_EXPECT_MAX, }, |
1523 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, | 1521 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, |
1524 | .attr_count = CTA_EXPECT_MAX, }, | 1522 | .attr_count = CTA_EXPECT_MAX, }, |
1525 | }; | 1523 | }; |
1526 | 1524 | ||
1527 | static struct nfnetlink_subsystem ctnl_subsys = { | 1525 | static struct nfnetlink_subsystem ctnl_subsys = { |
1528 | .name = "conntrack", | 1526 | .name = "conntrack", |
1529 | .subsys_id = NFNL_SUBSYS_CTNETLINK, | 1527 | .subsys_id = NFNL_SUBSYS_CTNETLINK, |
1530 | .cb_count = IPCTNL_MSG_MAX, | 1528 | .cb_count = IPCTNL_MSG_MAX, |
1531 | .cb = ctnl_cb, | 1529 | .cb = ctnl_cb, |
1532 | }; | 1530 | }; |
1533 | 1531 | ||
1534 | static struct nfnetlink_subsystem ctnl_exp_subsys = { | 1532 | static struct nfnetlink_subsystem ctnl_exp_subsys = { |
1535 | .name = "conntrack_expect", | 1533 | .name = "conntrack_expect", |
1536 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, | 1534 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, |
1537 | .cb_count = IPCTNL_MSG_EXP_MAX, | 1535 | .cb_count = IPCTNL_MSG_EXP_MAX, |
1538 | .cb = ctnl_exp_cb, | 1536 | .cb = ctnl_exp_cb, |
1539 | }; | 1537 | }; |
1540 | 1538 | ||
1541 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); | 1539 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); |
1542 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); | 1540 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); |
1543 | 1541 | ||
1544 | static int __init ctnetlink_init(void) | 1542 | static int __init ctnetlink_init(void) |
1545 | { | 1543 | { |
1546 | int ret; | 1544 | int ret; |
1547 | 1545 | ||
1548 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); | 1546 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); |
1549 | ret = nfnetlink_subsys_register(&ctnl_subsys); | 1547 | ret = nfnetlink_subsys_register(&ctnl_subsys); |
1550 | if (ret < 0) { | 1548 | if (ret < 0) { |
1551 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); | 1549 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); |
1552 | goto err_out; | 1550 | goto err_out; |
1553 | } | 1551 | } |
1554 | 1552 | ||
1555 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); | 1553 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); |
1556 | if (ret < 0) { | 1554 | if (ret < 0) { |
1557 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); | 1555 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); |
1558 | goto err_unreg_subsys; | 1556 | goto err_unreg_subsys; |
1559 | } | 1557 | } |
1560 | 1558 | ||
1561 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 1559 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1562 | ret = nf_conntrack_register_notifier(&ctnl_notifier); | 1560 | ret = nf_conntrack_register_notifier(&ctnl_notifier); |
1563 | if (ret < 0) { | 1561 | if (ret < 0) { |
1564 | printk("ctnetlink_init: cannot register notifier.\n"); | 1562 | printk("ctnetlink_init: cannot register notifier.\n"); |
1565 | goto err_unreg_exp_subsys; | 1563 | goto err_unreg_exp_subsys; |
1566 | } | 1564 | } |
1567 | 1565 | ||
1568 | ret = nf_conntrack_expect_register_notifier(&ctnl_notifier_exp); | 1566 | ret = nf_conntrack_expect_register_notifier(&ctnl_notifier_exp); |
1569 | if (ret < 0) { | 1567 | if (ret < 0) { |
1570 | printk("ctnetlink_init: cannot expect register notifier.\n"); | 1568 | printk("ctnetlink_init: cannot expect register notifier.\n"); |
1571 | goto err_unreg_notifier; | 1569 | goto err_unreg_notifier; |
1572 | } | 1570 | } |
1573 | #endif | 1571 | #endif |
1574 | 1572 | ||
1575 | return 0; | 1573 | return 0; |
1576 | 1574 | ||
1577 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 1575 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1578 | err_unreg_notifier: | 1576 | err_unreg_notifier: |
1579 | nf_conntrack_unregister_notifier(&ctnl_notifier); | 1577 | nf_conntrack_unregister_notifier(&ctnl_notifier); |
1580 | err_unreg_exp_subsys: | 1578 | err_unreg_exp_subsys: |
1581 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | 1579 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); |
1582 | #endif | 1580 | #endif |
1583 | err_unreg_subsys: | 1581 | err_unreg_subsys: |
1584 | nfnetlink_subsys_unregister(&ctnl_subsys); | 1582 | nfnetlink_subsys_unregister(&ctnl_subsys); |
1585 | err_out: | 1583 | err_out: |
1586 | return ret; | 1584 | return ret; |
1587 | } | 1585 | } |
1588 | 1586 | ||
1589 | static void __exit ctnetlink_exit(void) | 1587 | static void __exit ctnetlink_exit(void) |
1590 | { | 1588 | { |
1591 | printk("ctnetlink: unregistering from nfnetlink.\n"); | 1589 | printk("ctnetlink: unregistering from nfnetlink.\n"); |
1592 | 1590 | ||
1593 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 1591 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1594 | nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); | 1592 | nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); |
1595 | nf_conntrack_unregister_notifier(&ctnl_notifier); | 1593 | nf_conntrack_unregister_notifier(&ctnl_notifier); |
1596 | #endif | 1594 | #endif |
1597 | 1595 | ||
1598 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | 1596 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); |
1599 | nfnetlink_subsys_unregister(&ctnl_subsys); | 1597 | nfnetlink_subsys_unregister(&ctnl_subsys); |
1600 | return; | 1598 | return; |
1601 | } | 1599 | } |
1602 | 1600 | ||
1603 | module_init(ctnetlink_init); | 1601 | module_init(ctnetlink_init); |
1604 | module_exit(ctnetlink_exit); | 1602 | module_exit(ctnetlink_exit); |
1605 | 1603 |
net/netlink/af_netlink.c
1 | /* | 1 | /* |
2 | * NETLINK Kernel-user communication protocol. | 2 | * NETLINK Kernel-user communication protocol. |
3 | * | 3 | * |
4 | * Authors: Alan Cox <alan@redhat.com> | 4 | * Authors: Alan Cox <alan@redhat.com> |
5 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 5 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith | 12 | * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith |
13 | * added netlink_proto_exit | 13 | * added netlink_proto_exit |
14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> | 14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> |
15 | * use nlk_sk, as sk->protinfo is on a diet 8) | 15 | * use nlk_sk, as sk->protinfo is on a diet 8) |
16 | * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org> | 16 | * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org> |
17 | * - inc module use count of module that owns | 17 | * - inc module use count of module that owns |
18 | * the kernel socket in case userspace opens | 18 | * the kernel socket in case userspace opens |
19 | * socket of same protocol | 19 | * socket of same protocol |
20 | * - remove all module support, since netlink is | 20 | * - remove all module support, since netlink is |
21 | * mandatory if CONFIG_NET=y these days | 21 | * mandatory if CONFIG_NET=y these days |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | 25 | ||
26 | #include <linux/capability.h> | 26 | #include <linux/capability.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
31 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/stat.h> | 33 | #include <linux/stat.h> |
34 | #include <linux/socket.h> | 34 | #include <linux/socket.h> |
35 | #include <linux/un.h> | 35 | #include <linux/un.h> |
36 | #include <linux/fcntl.h> | 36 | #include <linux/fcntl.h> |
37 | #include <linux/termios.h> | 37 | #include <linux/termios.h> |
38 | #include <linux/sockios.h> | 38 | #include <linux/sockios.h> |
39 | #include <linux/net.h> | 39 | #include <linux/net.h> |
40 | #include <linux/fs.h> | 40 | #include <linux/fs.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
43 | #include <linux/skbuff.h> | 43 | #include <linux/skbuff.h> |
44 | #include <linux/netdevice.h> | 44 | #include <linux/netdevice.h> |
45 | #include <linux/rtnetlink.h> | 45 | #include <linux/rtnetlink.h> |
46 | #include <linux/proc_fs.h> | 46 | #include <linux/proc_fs.h> |
47 | #include <linux/seq_file.h> | 47 | #include <linux/seq_file.h> |
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/notifier.h> | 49 | #include <linux/notifier.h> |
50 | #include <linux/security.h> | 50 | #include <linux/security.h> |
51 | #include <linux/jhash.h> | 51 | #include <linux/jhash.h> |
52 | #include <linux/jiffies.h> | 52 | #include <linux/jiffies.h> |
53 | #include <linux/random.h> | 53 | #include <linux/random.h> |
54 | #include <linux/bitops.h> | 54 | #include <linux/bitops.h> |
55 | #include <linux/mm.h> | 55 | #include <linux/mm.h> |
56 | #include <linux/types.h> | 56 | #include <linux/types.h> |
57 | #include <linux/audit.h> | 57 | #include <linux/audit.h> |
58 | #include <linux/selinux.h> | 58 | #include <linux/selinux.h> |
59 | 59 | ||
60 | #include <net/sock.h> | 60 | #include <net/sock.h> |
61 | #include <net/scm.h> | 61 | #include <net/scm.h> |
62 | #include <net/netlink.h> | 62 | #include <net/netlink.h> |
63 | 63 | ||
64 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 64 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
65 | 65 | ||
66 | struct netlink_sock { | 66 | struct netlink_sock { |
67 | /* struct sock has to be the first member of netlink_sock */ | 67 | /* struct sock has to be the first member of netlink_sock */ |
68 | struct sock sk; | 68 | struct sock sk; |
69 | u32 pid; | 69 | u32 pid; |
70 | u32 dst_pid; | 70 | u32 dst_pid; |
71 | u32 dst_group; | 71 | u32 dst_group; |
72 | u32 flags; | 72 | u32 flags; |
73 | u32 subscriptions; | 73 | u32 subscriptions; |
74 | u32 ngroups; | 74 | u32 ngroups; |
75 | unsigned long *groups; | 75 | unsigned long *groups; |
76 | unsigned long state; | 76 | unsigned long state; |
77 | wait_queue_head_t wait; | 77 | wait_queue_head_t wait; |
78 | struct netlink_callback *cb; | 78 | struct netlink_callback *cb; |
79 | spinlock_t cb_lock; | 79 | spinlock_t cb_lock; |
80 | void (*data_ready)(struct sock *sk, int bytes); | 80 | void (*data_ready)(struct sock *sk, int bytes); |
81 | struct module *module; | 81 | struct module *module; |
82 | }; | 82 | }; |
83 | 83 | ||
84 | #define NETLINK_KERNEL_SOCKET 0x1 | 84 | #define NETLINK_KERNEL_SOCKET 0x1 |
85 | #define NETLINK_RECV_PKTINFO 0x2 | 85 | #define NETLINK_RECV_PKTINFO 0x2 |
86 | 86 | ||
87 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 87 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |
88 | { | 88 | { |
89 | return (struct netlink_sock *)sk; | 89 | return (struct netlink_sock *)sk; |
90 | } | 90 | } |
91 | 91 | ||
92 | struct nl_pid_hash { | 92 | struct nl_pid_hash { |
93 | struct hlist_head *table; | 93 | struct hlist_head *table; |
94 | unsigned long rehash_time; | 94 | unsigned long rehash_time; |
95 | 95 | ||
96 | unsigned int mask; | 96 | unsigned int mask; |
97 | unsigned int shift; | 97 | unsigned int shift; |
98 | 98 | ||
99 | unsigned int entries; | 99 | unsigned int entries; |
100 | unsigned int max_shift; | 100 | unsigned int max_shift; |
101 | 101 | ||
102 | u32 rnd; | 102 | u32 rnd; |
103 | }; | 103 | }; |
104 | 104 | ||
105 | struct netlink_table { | 105 | struct netlink_table { |
106 | struct nl_pid_hash hash; | 106 | struct nl_pid_hash hash; |
107 | struct hlist_head mc_list; | 107 | struct hlist_head mc_list; |
108 | unsigned long *listeners; | 108 | unsigned long *listeners; |
109 | unsigned int nl_nonroot; | 109 | unsigned int nl_nonroot; |
110 | unsigned int groups; | 110 | unsigned int groups; |
111 | struct module *module; | 111 | struct module *module; |
112 | int registered; | 112 | int registered; |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static struct netlink_table *nl_table; | 115 | static struct netlink_table *nl_table; |
116 | 116 | ||
117 | static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); | 117 | static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); |
118 | 118 | ||
119 | static int netlink_dump(struct sock *sk); | 119 | static int netlink_dump(struct sock *sk); |
120 | static void netlink_destroy_callback(struct netlink_callback *cb); | 120 | static void netlink_destroy_callback(struct netlink_callback *cb); |
121 | 121 | ||
122 | static DEFINE_RWLOCK(nl_table_lock); | 122 | static DEFINE_RWLOCK(nl_table_lock); |
123 | static atomic_t nl_table_users = ATOMIC_INIT(0); | 123 | static atomic_t nl_table_users = ATOMIC_INIT(0); |
124 | 124 | ||
125 | static ATOMIC_NOTIFIER_HEAD(netlink_chain); | 125 | static ATOMIC_NOTIFIER_HEAD(netlink_chain); |
126 | 126 | ||
127 | static u32 netlink_group_mask(u32 group) | 127 | static u32 netlink_group_mask(u32 group) |
128 | { | 128 | { |
129 | return group ? 1 << (group - 1) : 0; | 129 | return group ? 1 << (group - 1) : 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) | 132 | static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) |
133 | { | 133 | { |
134 | return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; | 134 | return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; |
135 | } | 135 | } |
136 | 136 | ||
137 | static void netlink_sock_destruct(struct sock *sk) | 137 | static void netlink_sock_destruct(struct sock *sk) |
138 | { | 138 | { |
139 | skb_queue_purge(&sk->sk_receive_queue); | 139 | skb_queue_purge(&sk->sk_receive_queue); |
140 | 140 | ||
141 | if (!sock_flag(sk, SOCK_DEAD)) { | 141 | if (!sock_flag(sk, SOCK_DEAD)) { |
142 | printk("Freeing alive netlink socket %p\n", sk); | 142 | printk("Freeing alive netlink socket %p\n", sk); |
143 | return; | 143 | return; |
144 | } | 144 | } |
145 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); | 145 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); |
146 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); | 146 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); |
147 | BUG_TRAP(!nlk_sk(sk)->cb); | 147 | BUG_TRAP(!nlk_sk(sk)->cb); |
148 | BUG_TRAP(!nlk_sk(sk)->groups); | 148 | BUG_TRAP(!nlk_sk(sk)->groups); |
149 | } | 149 | } |
150 | 150 | ||
151 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. | 151 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. |
152 | * Look, when several writers sleep and reader wakes them up, all but one | 152 | * Look, when several writers sleep and reader wakes them up, all but one |
153 | * immediately hit write lock and grab all the cpus. Exclusive sleep solves | 153 | * immediately hit write lock and grab all the cpus. Exclusive sleep solves |
154 | * this, _but_ remember, it adds useless work on UP machines. | 154 | * this, _but_ remember, it adds useless work on UP machines. |
155 | */ | 155 | */ |
156 | 156 | ||
157 | static void netlink_table_grab(void) | 157 | static void netlink_table_grab(void) |
158 | { | 158 | { |
159 | write_lock_irq(&nl_table_lock); | 159 | write_lock_irq(&nl_table_lock); |
160 | 160 | ||
161 | if (atomic_read(&nl_table_users)) { | 161 | if (atomic_read(&nl_table_users)) { |
162 | DECLARE_WAITQUEUE(wait, current); | 162 | DECLARE_WAITQUEUE(wait, current); |
163 | 163 | ||
164 | add_wait_queue_exclusive(&nl_table_wait, &wait); | 164 | add_wait_queue_exclusive(&nl_table_wait, &wait); |
165 | for(;;) { | 165 | for(;;) { |
166 | set_current_state(TASK_UNINTERRUPTIBLE); | 166 | set_current_state(TASK_UNINTERRUPTIBLE); |
167 | if (atomic_read(&nl_table_users) == 0) | 167 | if (atomic_read(&nl_table_users) == 0) |
168 | break; | 168 | break; |
169 | write_unlock_irq(&nl_table_lock); | 169 | write_unlock_irq(&nl_table_lock); |
170 | schedule(); | 170 | schedule(); |
171 | write_lock_irq(&nl_table_lock); | 171 | write_lock_irq(&nl_table_lock); |
172 | } | 172 | } |
173 | 173 | ||
174 | __set_current_state(TASK_RUNNING); | 174 | __set_current_state(TASK_RUNNING); |
175 | remove_wait_queue(&nl_table_wait, &wait); | 175 | remove_wait_queue(&nl_table_wait, &wait); |
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | static __inline__ void netlink_table_ungrab(void) | 179 | static __inline__ void netlink_table_ungrab(void) |
180 | { | 180 | { |
181 | write_unlock_irq(&nl_table_lock); | 181 | write_unlock_irq(&nl_table_lock); |
182 | wake_up(&nl_table_wait); | 182 | wake_up(&nl_table_wait); |
183 | } | 183 | } |
184 | 184 | ||
185 | static __inline__ void | 185 | static __inline__ void |
186 | netlink_lock_table(void) | 186 | netlink_lock_table(void) |
187 | { | 187 | { |
188 | /* read_lock() synchronizes us to netlink_table_grab */ | 188 | /* read_lock() synchronizes us to netlink_table_grab */ |
189 | 189 | ||
190 | read_lock(&nl_table_lock); | 190 | read_lock(&nl_table_lock); |
191 | atomic_inc(&nl_table_users); | 191 | atomic_inc(&nl_table_users); |
192 | read_unlock(&nl_table_lock); | 192 | read_unlock(&nl_table_lock); |
193 | } | 193 | } |
194 | 194 | ||
195 | static __inline__ void | 195 | static __inline__ void |
196 | netlink_unlock_table(void) | 196 | netlink_unlock_table(void) |
197 | { | 197 | { |
198 | if (atomic_dec_and_test(&nl_table_users)) | 198 | if (atomic_dec_and_test(&nl_table_users)) |
199 | wake_up(&nl_table_wait); | 199 | wake_up(&nl_table_wait); |
200 | } | 200 | } |
201 | 201 | ||
202 | static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) | 202 | static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) |
203 | { | 203 | { |
204 | struct nl_pid_hash *hash = &nl_table[protocol].hash; | 204 | struct nl_pid_hash *hash = &nl_table[protocol].hash; |
205 | struct hlist_head *head; | 205 | struct hlist_head *head; |
206 | struct sock *sk; | 206 | struct sock *sk; |
207 | struct hlist_node *node; | 207 | struct hlist_node *node; |
208 | 208 | ||
209 | read_lock(&nl_table_lock); | 209 | read_lock(&nl_table_lock); |
210 | head = nl_pid_hashfn(hash, pid); | 210 | head = nl_pid_hashfn(hash, pid); |
211 | sk_for_each(sk, node, head) { | 211 | sk_for_each(sk, node, head) { |
212 | if (nlk_sk(sk)->pid == pid) { | 212 | if (nlk_sk(sk)->pid == pid) { |
213 | sock_hold(sk); | 213 | sock_hold(sk); |
214 | goto found; | 214 | goto found; |
215 | } | 215 | } |
216 | } | 216 | } |
217 | sk = NULL; | 217 | sk = NULL; |
218 | found: | 218 | found: |
219 | read_unlock(&nl_table_lock); | 219 | read_unlock(&nl_table_lock); |
220 | return sk; | 220 | return sk; |
221 | } | 221 | } |
222 | 222 | ||
223 | static inline struct hlist_head *nl_pid_hash_alloc(size_t size) | 223 | static inline struct hlist_head *nl_pid_hash_alloc(size_t size) |
224 | { | 224 | { |
225 | if (size <= PAGE_SIZE) | 225 | if (size <= PAGE_SIZE) |
226 | return kmalloc(size, GFP_ATOMIC); | 226 | return kmalloc(size, GFP_ATOMIC); |
227 | else | 227 | else |
228 | return (struct hlist_head *) | 228 | return (struct hlist_head *) |
229 | __get_free_pages(GFP_ATOMIC, get_order(size)); | 229 | __get_free_pages(GFP_ATOMIC, get_order(size)); |
230 | } | 230 | } |
231 | 231 | ||
232 | static inline void nl_pid_hash_free(struct hlist_head *table, size_t size) | 232 | static inline void nl_pid_hash_free(struct hlist_head *table, size_t size) |
233 | { | 233 | { |
234 | if (size <= PAGE_SIZE) | 234 | if (size <= PAGE_SIZE) |
235 | kfree(table); | 235 | kfree(table); |
236 | else | 236 | else |
237 | free_pages((unsigned long)table, get_order(size)); | 237 | free_pages((unsigned long)table, get_order(size)); |
238 | } | 238 | } |
239 | 239 | ||
240 | static int nl_pid_hash_rehash(struct nl_pid_hash *hash, int grow) | 240 | static int nl_pid_hash_rehash(struct nl_pid_hash *hash, int grow) |
241 | { | 241 | { |
242 | unsigned int omask, mask, shift; | 242 | unsigned int omask, mask, shift; |
243 | size_t osize, size; | 243 | size_t osize, size; |
244 | struct hlist_head *otable, *table; | 244 | struct hlist_head *otable, *table; |
245 | int i; | 245 | int i; |
246 | 246 | ||
247 | omask = mask = hash->mask; | 247 | omask = mask = hash->mask; |
248 | osize = size = (mask + 1) * sizeof(*table); | 248 | osize = size = (mask + 1) * sizeof(*table); |
249 | shift = hash->shift; | 249 | shift = hash->shift; |
250 | 250 | ||
251 | if (grow) { | 251 | if (grow) { |
252 | if (++shift > hash->max_shift) | 252 | if (++shift > hash->max_shift) |
253 | return 0; | 253 | return 0; |
254 | mask = mask * 2 + 1; | 254 | mask = mask * 2 + 1; |
255 | size *= 2; | 255 | size *= 2; |
256 | } | 256 | } |
257 | 257 | ||
258 | table = nl_pid_hash_alloc(size); | 258 | table = nl_pid_hash_alloc(size); |
259 | if (!table) | 259 | if (!table) |
260 | return 0; | 260 | return 0; |
261 | 261 | ||
262 | memset(table, 0, size); | 262 | memset(table, 0, size); |
263 | otable = hash->table; | 263 | otable = hash->table; |
264 | hash->table = table; | 264 | hash->table = table; |
265 | hash->mask = mask; | 265 | hash->mask = mask; |
266 | hash->shift = shift; | 266 | hash->shift = shift; |
267 | get_random_bytes(&hash->rnd, sizeof(hash->rnd)); | 267 | get_random_bytes(&hash->rnd, sizeof(hash->rnd)); |
268 | 268 | ||
269 | for (i = 0; i <= omask; i++) { | 269 | for (i = 0; i <= omask; i++) { |
270 | struct sock *sk; | 270 | struct sock *sk; |
271 | struct hlist_node *node, *tmp; | 271 | struct hlist_node *node, *tmp; |
272 | 272 | ||
273 | sk_for_each_safe(sk, node, tmp, &otable[i]) | 273 | sk_for_each_safe(sk, node, tmp, &otable[i]) |
274 | __sk_add_node(sk, nl_pid_hashfn(hash, nlk_sk(sk)->pid)); | 274 | __sk_add_node(sk, nl_pid_hashfn(hash, nlk_sk(sk)->pid)); |
275 | } | 275 | } |
276 | 276 | ||
277 | nl_pid_hash_free(otable, osize); | 277 | nl_pid_hash_free(otable, osize); |
278 | hash->rehash_time = jiffies + 10 * 60 * HZ; | 278 | hash->rehash_time = jiffies + 10 * 60 * HZ; |
279 | return 1; | 279 | return 1; |
280 | } | 280 | } |
281 | 281 | ||
282 | static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len) | 282 | static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len) |
283 | { | 283 | { |
284 | int avg = hash->entries >> hash->shift; | 284 | int avg = hash->entries >> hash->shift; |
285 | 285 | ||
286 | if (unlikely(avg > 1) && nl_pid_hash_rehash(hash, 1)) | 286 | if (unlikely(avg > 1) && nl_pid_hash_rehash(hash, 1)) |
287 | return 1; | 287 | return 1; |
288 | 288 | ||
289 | if (unlikely(len > avg) && time_after(jiffies, hash->rehash_time)) { | 289 | if (unlikely(len > avg) && time_after(jiffies, hash->rehash_time)) { |
290 | nl_pid_hash_rehash(hash, 0); | 290 | nl_pid_hash_rehash(hash, 0); |
291 | return 1; | 291 | return 1; |
292 | } | 292 | } |
293 | 293 | ||
294 | return 0; | 294 | return 0; |
295 | } | 295 | } |
296 | 296 | ||
297 | static const struct proto_ops netlink_ops; | 297 | static const struct proto_ops netlink_ops; |
298 | 298 | ||
299 | static void | 299 | static void |
300 | netlink_update_listeners(struct sock *sk) | 300 | netlink_update_listeners(struct sock *sk) |
301 | { | 301 | { |
302 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; | 302 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; |
303 | struct hlist_node *node; | 303 | struct hlist_node *node; |
304 | unsigned long mask; | 304 | unsigned long mask; |
305 | unsigned int i; | 305 | unsigned int i; |
306 | 306 | ||
307 | for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) { | 307 | for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) { |
308 | mask = 0; | 308 | mask = 0; |
309 | sk_for_each_bound(sk, node, &tbl->mc_list) | 309 | sk_for_each_bound(sk, node, &tbl->mc_list) |
310 | mask |= nlk_sk(sk)->groups[i]; | 310 | mask |= nlk_sk(sk)->groups[i]; |
311 | tbl->listeners[i] = mask; | 311 | tbl->listeners[i] = mask; |
312 | } | 312 | } |
313 | /* this function is only called with the netlink table "grabbed", which | 313 | /* this function is only called with the netlink table "grabbed", which |
314 | * makes sure updates are visible before bind or setsockopt return. */ | 314 | * makes sure updates are visible before bind or setsockopt return. */ |
315 | } | 315 | } |
316 | 316 | ||
317 | static int netlink_insert(struct sock *sk, u32 pid) | 317 | static int netlink_insert(struct sock *sk, u32 pid) |
318 | { | 318 | { |
319 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; | 319 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; |
320 | struct hlist_head *head; | 320 | struct hlist_head *head; |
321 | int err = -EADDRINUSE; | 321 | int err = -EADDRINUSE; |
322 | struct sock *osk; | 322 | struct sock *osk; |
323 | struct hlist_node *node; | 323 | struct hlist_node *node; |
324 | int len; | 324 | int len; |
325 | 325 | ||
326 | netlink_table_grab(); | 326 | netlink_table_grab(); |
327 | head = nl_pid_hashfn(hash, pid); | 327 | head = nl_pid_hashfn(hash, pid); |
328 | len = 0; | 328 | len = 0; |
329 | sk_for_each(osk, node, head) { | 329 | sk_for_each(osk, node, head) { |
330 | if (nlk_sk(osk)->pid == pid) | 330 | if (nlk_sk(osk)->pid == pid) |
331 | break; | 331 | break; |
332 | len++; | 332 | len++; |
333 | } | 333 | } |
334 | if (node) | 334 | if (node) |
335 | goto err; | 335 | goto err; |
336 | 336 | ||
337 | err = -EBUSY; | 337 | err = -EBUSY; |
338 | if (nlk_sk(sk)->pid) | 338 | if (nlk_sk(sk)->pid) |
339 | goto err; | 339 | goto err; |
340 | 340 | ||
341 | err = -ENOMEM; | 341 | err = -ENOMEM; |
342 | if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX)) | 342 | if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX)) |
343 | goto err; | 343 | goto err; |
344 | 344 | ||
345 | if (len && nl_pid_hash_dilute(hash, len)) | 345 | if (len && nl_pid_hash_dilute(hash, len)) |
346 | head = nl_pid_hashfn(hash, pid); | 346 | head = nl_pid_hashfn(hash, pid); |
347 | hash->entries++; | 347 | hash->entries++; |
348 | nlk_sk(sk)->pid = pid; | 348 | nlk_sk(sk)->pid = pid; |
349 | sk_add_node(sk, head); | 349 | sk_add_node(sk, head); |
350 | err = 0; | 350 | err = 0; |
351 | 351 | ||
352 | err: | 352 | err: |
353 | netlink_table_ungrab(); | 353 | netlink_table_ungrab(); |
354 | return err; | 354 | return err; |
355 | } | 355 | } |
356 | 356 | ||
357 | static void netlink_remove(struct sock *sk) | 357 | static void netlink_remove(struct sock *sk) |
358 | { | 358 | { |
359 | netlink_table_grab(); | 359 | netlink_table_grab(); |
360 | if (sk_del_node_init(sk)) | 360 | if (sk_del_node_init(sk)) |
361 | nl_table[sk->sk_protocol].hash.entries--; | 361 | nl_table[sk->sk_protocol].hash.entries--; |
362 | if (nlk_sk(sk)->subscriptions) | 362 | if (nlk_sk(sk)->subscriptions) |
363 | __sk_del_bind_node(sk); | 363 | __sk_del_bind_node(sk); |
364 | netlink_table_ungrab(); | 364 | netlink_table_ungrab(); |
365 | } | 365 | } |
366 | 366 | ||
367 | static struct proto netlink_proto = { | 367 | static struct proto netlink_proto = { |
368 | .name = "NETLINK", | 368 | .name = "NETLINK", |
369 | .owner = THIS_MODULE, | 369 | .owner = THIS_MODULE, |
370 | .obj_size = sizeof(struct netlink_sock), | 370 | .obj_size = sizeof(struct netlink_sock), |
371 | }; | 371 | }; |
372 | 372 | ||
373 | static int __netlink_create(struct socket *sock, int protocol) | 373 | static int __netlink_create(struct socket *sock, int protocol) |
374 | { | 374 | { |
375 | struct sock *sk; | 375 | struct sock *sk; |
376 | struct netlink_sock *nlk; | 376 | struct netlink_sock *nlk; |
377 | 377 | ||
378 | sock->ops = &netlink_ops; | 378 | sock->ops = &netlink_ops; |
379 | 379 | ||
380 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | 380 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); |
381 | if (!sk) | 381 | if (!sk) |
382 | return -ENOMEM; | 382 | return -ENOMEM; |
383 | 383 | ||
384 | sock_init_data(sock, sk); | 384 | sock_init_data(sock, sk); |
385 | 385 | ||
386 | nlk = nlk_sk(sk); | 386 | nlk = nlk_sk(sk); |
387 | spin_lock_init(&nlk->cb_lock); | 387 | spin_lock_init(&nlk->cb_lock); |
388 | init_waitqueue_head(&nlk->wait); | 388 | init_waitqueue_head(&nlk->wait); |
389 | 389 | ||
390 | sk->sk_destruct = netlink_sock_destruct; | 390 | sk->sk_destruct = netlink_sock_destruct; |
391 | sk->sk_protocol = protocol; | 391 | sk->sk_protocol = protocol; |
392 | return 0; | 392 | return 0; |
393 | } | 393 | } |
394 | 394 | ||
395 | static int netlink_create(struct socket *sock, int protocol) | 395 | static int netlink_create(struct socket *sock, int protocol) |
396 | { | 396 | { |
397 | struct module *module = NULL; | 397 | struct module *module = NULL; |
398 | struct netlink_sock *nlk; | 398 | struct netlink_sock *nlk; |
399 | unsigned int groups; | 399 | unsigned int groups; |
400 | int err = 0; | 400 | int err = 0; |
401 | 401 | ||
402 | sock->state = SS_UNCONNECTED; | 402 | sock->state = SS_UNCONNECTED; |
403 | 403 | ||
404 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | 404 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) |
405 | return -ESOCKTNOSUPPORT; | 405 | return -ESOCKTNOSUPPORT; |
406 | 406 | ||
407 | if (protocol<0 || protocol >= MAX_LINKS) | 407 | if (protocol<0 || protocol >= MAX_LINKS) |
408 | return -EPROTONOSUPPORT; | 408 | return -EPROTONOSUPPORT; |
409 | 409 | ||
410 | netlink_lock_table(); | 410 | netlink_lock_table(); |
411 | #ifdef CONFIG_KMOD | 411 | #ifdef CONFIG_KMOD |
412 | if (!nl_table[protocol].registered) { | 412 | if (!nl_table[protocol].registered) { |
413 | netlink_unlock_table(); | 413 | netlink_unlock_table(); |
414 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); | 414 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); |
415 | netlink_lock_table(); | 415 | netlink_lock_table(); |
416 | } | 416 | } |
417 | #endif | 417 | #endif |
418 | if (nl_table[protocol].registered && | 418 | if (nl_table[protocol].registered && |
419 | try_module_get(nl_table[protocol].module)) | 419 | try_module_get(nl_table[protocol].module)) |
420 | module = nl_table[protocol].module; | 420 | module = nl_table[protocol].module; |
421 | groups = nl_table[protocol].groups; | 421 | groups = nl_table[protocol].groups; |
422 | netlink_unlock_table(); | 422 | netlink_unlock_table(); |
423 | 423 | ||
424 | if ((err = __netlink_create(sock, protocol)) < 0) | 424 | if ((err = __netlink_create(sock, protocol)) < 0) |
425 | goto out_module; | 425 | goto out_module; |
426 | 426 | ||
427 | nlk = nlk_sk(sock->sk); | 427 | nlk = nlk_sk(sock->sk); |
428 | nlk->module = module; | 428 | nlk->module = module; |
429 | out: | 429 | out: |
430 | return err; | 430 | return err; |
431 | 431 | ||
432 | out_module: | 432 | out_module: |
433 | module_put(module); | 433 | module_put(module); |
434 | goto out; | 434 | goto out; |
435 | } | 435 | } |
436 | 436 | ||
437 | static int netlink_release(struct socket *sock) | 437 | static int netlink_release(struct socket *sock) |
438 | { | 438 | { |
439 | struct sock *sk = sock->sk; | 439 | struct sock *sk = sock->sk; |
440 | struct netlink_sock *nlk; | 440 | struct netlink_sock *nlk; |
441 | 441 | ||
442 | if (!sk) | 442 | if (!sk) |
443 | return 0; | 443 | return 0; |
444 | 444 | ||
445 | netlink_remove(sk); | 445 | netlink_remove(sk); |
446 | nlk = nlk_sk(sk); | 446 | nlk = nlk_sk(sk); |
447 | 447 | ||
448 | spin_lock(&nlk->cb_lock); | 448 | spin_lock(&nlk->cb_lock); |
449 | if (nlk->cb) { | 449 | if (nlk->cb) { |
450 | if (nlk->cb->done) | 450 | if (nlk->cb->done) |
451 | nlk->cb->done(nlk->cb); | 451 | nlk->cb->done(nlk->cb); |
452 | netlink_destroy_callback(nlk->cb); | 452 | netlink_destroy_callback(nlk->cb); |
453 | nlk->cb = NULL; | 453 | nlk->cb = NULL; |
454 | } | 454 | } |
455 | spin_unlock(&nlk->cb_lock); | 455 | spin_unlock(&nlk->cb_lock); |
456 | 456 | ||
457 | /* OK. Socket is unlinked, and, therefore, | 457 | /* OK. Socket is unlinked, and, therefore, |
458 | no new packets will arrive */ | 458 | no new packets will arrive */ |
459 | 459 | ||
460 | sock_orphan(sk); | 460 | sock_orphan(sk); |
461 | sock->sk = NULL; | 461 | sock->sk = NULL; |
462 | wake_up_interruptible_all(&nlk->wait); | 462 | wake_up_interruptible_all(&nlk->wait); |
463 | 463 | ||
464 | skb_queue_purge(&sk->sk_write_queue); | 464 | skb_queue_purge(&sk->sk_write_queue); |
465 | 465 | ||
466 | if (nlk->pid && !nlk->subscriptions) { | 466 | if (nlk->pid && !nlk->subscriptions) { |
467 | struct netlink_notify n = { | 467 | struct netlink_notify n = { |
468 | .protocol = sk->sk_protocol, | 468 | .protocol = sk->sk_protocol, |
469 | .pid = nlk->pid, | 469 | .pid = nlk->pid, |
470 | }; | 470 | }; |
471 | atomic_notifier_call_chain(&netlink_chain, | 471 | atomic_notifier_call_chain(&netlink_chain, |
472 | NETLINK_URELEASE, &n); | 472 | NETLINK_URELEASE, &n); |
473 | } | 473 | } |
474 | 474 | ||
475 | if (nlk->module) | 475 | if (nlk->module) |
476 | module_put(nlk->module); | 476 | module_put(nlk->module); |
477 | 477 | ||
478 | netlink_table_grab(); | 478 | netlink_table_grab(); |
479 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { | 479 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { |
480 | kfree(nl_table[sk->sk_protocol].listeners); | 480 | kfree(nl_table[sk->sk_protocol].listeners); |
481 | nl_table[sk->sk_protocol].module = NULL; | 481 | nl_table[sk->sk_protocol].module = NULL; |
482 | nl_table[sk->sk_protocol].registered = 0; | 482 | nl_table[sk->sk_protocol].registered = 0; |
483 | } else if (nlk->subscriptions) | 483 | } else if (nlk->subscriptions) |
484 | netlink_update_listeners(sk); | 484 | netlink_update_listeners(sk); |
485 | netlink_table_ungrab(); | 485 | netlink_table_ungrab(); |
486 | 486 | ||
487 | kfree(nlk->groups); | 487 | kfree(nlk->groups); |
488 | nlk->groups = NULL; | 488 | nlk->groups = NULL; |
489 | 489 | ||
490 | sock_put(sk); | 490 | sock_put(sk); |
491 | return 0; | 491 | return 0; |
492 | } | 492 | } |
493 | 493 | ||
494 | static int netlink_autobind(struct socket *sock) | 494 | static int netlink_autobind(struct socket *sock) |
495 | { | 495 | { |
496 | struct sock *sk = sock->sk; | 496 | struct sock *sk = sock->sk; |
497 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; | 497 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; |
498 | struct hlist_head *head; | 498 | struct hlist_head *head; |
499 | struct sock *osk; | 499 | struct sock *osk; |
500 | struct hlist_node *node; | 500 | struct hlist_node *node; |
501 | s32 pid = current->tgid; | 501 | s32 pid = current->tgid; |
502 | int err; | 502 | int err; |
503 | static s32 rover = -4097; | 503 | static s32 rover = -4097; |
504 | 504 | ||
505 | retry: | 505 | retry: |
506 | cond_resched(); | 506 | cond_resched(); |
507 | netlink_table_grab(); | 507 | netlink_table_grab(); |
508 | head = nl_pid_hashfn(hash, pid); | 508 | head = nl_pid_hashfn(hash, pid); |
509 | sk_for_each(osk, node, head) { | 509 | sk_for_each(osk, node, head) { |
510 | if (nlk_sk(osk)->pid == pid) { | 510 | if (nlk_sk(osk)->pid == pid) { |
511 | /* Bind collision, search negative pid values. */ | 511 | /* Bind collision, search negative pid values. */ |
512 | pid = rover--; | 512 | pid = rover--; |
513 | if (rover > -4097) | 513 | if (rover > -4097) |
514 | rover = -4097; | 514 | rover = -4097; |
515 | netlink_table_ungrab(); | 515 | netlink_table_ungrab(); |
516 | goto retry; | 516 | goto retry; |
517 | } | 517 | } |
518 | } | 518 | } |
519 | netlink_table_ungrab(); | 519 | netlink_table_ungrab(); |
520 | 520 | ||
521 | err = netlink_insert(sk, pid); | 521 | err = netlink_insert(sk, pid); |
522 | if (err == -EADDRINUSE) | 522 | if (err == -EADDRINUSE) |
523 | goto retry; | 523 | goto retry; |
524 | 524 | ||
525 | /* If 2 threads race to autobind, that is fine. */ | 525 | /* If 2 threads race to autobind, that is fine. */ |
526 | if (err == -EBUSY) | 526 | if (err == -EBUSY) |
527 | err = 0; | 527 | err = 0; |
528 | 528 | ||
529 | return err; | 529 | return err; |
530 | } | 530 | } |
531 | 531 | ||
532 | static inline int netlink_capable(struct socket *sock, unsigned int flag) | 532 | static inline int netlink_capable(struct socket *sock, unsigned int flag) |
533 | { | 533 | { |
534 | return (nl_table[sock->sk->sk_protocol].nl_nonroot & flag) || | 534 | return (nl_table[sock->sk->sk_protocol].nl_nonroot & flag) || |
535 | capable(CAP_NET_ADMIN); | 535 | capable(CAP_NET_ADMIN); |
536 | } | 536 | } |
537 | 537 | ||
538 | static void | 538 | static void |
539 | netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) | 539 | netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) |
540 | { | 540 | { |
541 | struct netlink_sock *nlk = nlk_sk(sk); | 541 | struct netlink_sock *nlk = nlk_sk(sk); |
542 | 542 | ||
543 | if (nlk->subscriptions && !subscriptions) | 543 | if (nlk->subscriptions && !subscriptions) |
544 | __sk_del_bind_node(sk); | 544 | __sk_del_bind_node(sk); |
545 | else if (!nlk->subscriptions && subscriptions) | 545 | else if (!nlk->subscriptions && subscriptions) |
546 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | 546 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); |
547 | nlk->subscriptions = subscriptions; | 547 | nlk->subscriptions = subscriptions; |
548 | } | 548 | } |
549 | 549 | ||
550 | static int netlink_alloc_groups(struct sock *sk) | 550 | static int netlink_alloc_groups(struct sock *sk) |
551 | { | 551 | { |
552 | struct netlink_sock *nlk = nlk_sk(sk); | 552 | struct netlink_sock *nlk = nlk_sk(sk); |
553 | unsigned int groups; | 553 | unsigned int groups; |
554 | int err = 0; | 554 | int err = 0; |
555 | 555 | ||
556 | netlink_lock_table(); | 556 | netlink_lock_table(); |
557 | groups = nl_table[sk->sk_protocol].groups; | 557 | groups = nl_table[sk->sk_protocol].groups; |
558 | if (!nl_table[sk->sk_protocol].registered) | 558 | if (!nl_table[sk->sk_protocol].registered) |
559 | err = -ENOENT; | 559 | err = -ENOENT; |
560 | netlink_unlock_table(); | 560 | netlink_unlock_table(); |
561 | 561 | ||
562 | if (err) | 562 | if (err) |
563 | return err; | 563 | return err; |
564 | 564 | ||
565 | nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL); | 565 | nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL); |
566 | if (nlk->groups == NULL) | 566 | if (nlk->groups == NULL) |
567 | return -ENOMEM; | 567 | return -ENOMEM; |
568 | nlk->ngroups = groups; | 568 | nlk->ngroups = groups; |
569 | return 0; | 569 | return 0; |
570 | } | 570 | } |
571 | 571 | ||
572 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 572 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
573 | { | 573 | { |
574 | struct sock *sk = sock->sk; | 574 | struct sock *sk = sock->sk; |
575 | struct netlink_sock *nlk = nlk_sk(sk); | 575 | struct netlink_sock *nlk = nlk_sk(sk); |
576 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 576 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
577 | int err; | 577 | int err; |
578 | 578 | ||
579 | if (nladdr->nl_family != AF_NETLINK) | 579 | if (nladdr->nl_family != AF_NETLINK) |
580 | return -EINVAL; | 580 | return -EINVAL; |
581 | 581 | ||
582 | /* Only superuser is allowed to listen multicasts */ | 582 | /* Only superuser is allowed to listen multicasts */ |
583 | if (nladdr->nl_groups) { | 583 | if (nladdr->nl_groups) { |
584 | if (!netlink_capable(sock, NL_NONROOT_RECV)) | 584 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
585 | return -EPERM; | 585 | return -EPERM; |
586 | if (nlk->groups == NULL) { | 586 | if (nlk->groups == NULL) { |
587 | err = netlink_alloc_groups(sk); | 587 | err = netlink_alloc_groups(sk); |
588 | if (err) | 588 | if (err) |
589 | return err; | 589 | return err; |
590 | } | 590 | } |
591 | } | 591 | } |
592 | 592 | ||
593 | if (nlk->pid) { | 593 | if (nlk->pid) { |
594 | if (nladdr->nl_pid != nlk->pid) | 594 | if (nladdr->nl_pid != nlk->pid) |
595 | return -EINVAL; | 595 | return -EINVAL; |
596 | } else { | 596 | } else { |
597 | err = nladdr->nl_pid ? | 597 | err = nladdr->nl_pid ? |
598 | netlink_insert(sk, nladdr->nl_pid) : | 598 | netlink_insert(sk, nladdr->nl_pid) : |
599 | netlink_autobind(sock); | 599 | netlink_autobind(sock); |
600 | if (err) | 600 | if (err) |
601 | return err; | 601 | return err; |
602 | } | 602 | } |
603 | 603 | ||
604 | if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) | 604 | if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) |
605 | return 0; | 605 | return 0; |
606 | 606 | ||
607 | netlink_table_grab(); | 607 | netlink_table_grab(); |
608 | netlink_update_subscriptions(sk, nlk->subscriptions + | 608 | netlink_update_subscriptions(sk, nlk->subscriptions + |
609 | hweight32(nladdr->nl_groups) - | 609 | hweight32(nladdr->nl_groups) - |
610 | hweight32(nlk->groups[0])); | 610 | hweight32(nlk->groups[0])); |
611 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; | 611 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; |
612 | netlink_update_listeners(sk); | 612 | netlink_update_listeners(sk); |
613 | netlink_table_ungrab(); | 613 | netlink_table_ungrab(); |
614 | 614 | ||
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | 617 | ||
618 | static int netlink_connect(struct socket *sock, struct sockaddr *addr, | 618 | static int netlink_connect(struct socket *sock, struct sockaddr *addr, |
619 | int alen, int flags) | 619 | int alen, int flags) |
620 | { | 620 | { |
621 | int err = 0; | 621 | int err = 0; |
622 | struct sock *sk = sock->sk; | 622 | struct sock *sk = sock->sk; |
623 | struct netlink_sock *nlk = nlk_sk(sk); | 623 | struct netlink_sock *nlk = nlk_sk(sk); |
624 | struct sockaddr_nl *nladdr=(struct sockaddr_nl*)addr; | 624 | struct sockaddr_nl *nladdr=(struct sockaddr_nl*)addr; |
625 | 625 | ||
626 | if (addr->sa_family == AF_UNSPEC) { | 626 | if (addr->sa_family == AF_UNSPEC) { |
627 | sk->sk_state = NETLINK_UNCONNECTED; | 627 | sk->sk_state = NETLINK_UNCONNECTED; |
628 | nlk->dst_pid = 0; | 628 | nlk->dst_pid = 0; |
629 | nlk->dst_group = 0; | 629 | nlk->dst_group = 0; |
630 | return 0; | 630 | return 0; |
631 | } | 631 | } |
632 | if (addr->sa_family != AF_NETLINK) | 632 | if (addr->sa_family != AF_NETLINK) |
633 | return -EINVAL; | 633 | return -EINVAL; |
634 | 634 | ||
635 | /* Only superuser is allowed to send multicasts */ | 635 | /* Only superuser is allowed to send multicasts */ |
636 | if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_SEND)) | 636 | if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_SEND)) |
637 | return -EPERM; | 637 | return -EPERM; |
638 | 638 | ||
639 | if (!nlk->pid) | 639 | if (!nlk->pid) |
640 | err = netlink_autobind(sock); | 640 | err = netlink_autobind(sock); |
641 | 641 | ||
642 | if (err == 0) { | 642 | if (err == 0) { |
643 | sk->sk_state = NETLINK_CONNECTED; | 643 | sk->sk_state = NETLINK_CONNECTED; |
644 | nlk->dst_pid = nladdr->nl_pid; | 644 | nlk->dst_pid = nladdr->nl_pid; |
645 | nlk->dst_group = ffs(nladdr->nl_groups); | 645 | nlk->dst_group = ffs(nladdr->nl_groups); |
646 | } | 646 | } |
647 | 647 | ||
648 | return err; | 648 | return err; |
649 | } | 649 | } |
650 | 650 | ||
651 | static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) | 651 | static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) |
652 | { | 652 | { |
653 | struct sock *sk = sock->sk; | 653 | struct sock *sk = sock->sk; |
654 | struct netlink_sock *nlk = nlk_sk(sk); | 654 | struct netlink_sock *nlk = nlk_sk(sk); |
655 | struct sockaddr_nl *nladdr=(struct sockaddr_nl *)addr; | 655 | struct sockaddr_nl *nladdr=(struct sockaddr_nl *)addr; |
656 | 656 | ||
657 | nladdr->nl_family = AF_NETLINK; | 657 | nladdr->nl_family = AF_NETLINK; |
658 | nladdr->nl_pad = 0; | 658 | nladdr->nl_pad = 0; |
659 | *addr_len = sizeof(*nladdr); | 659 | *addr_len = sizeof(*nladdr); |
660 | 660 | ||
661 | if (peer) { | 661 | if (peer) { |
662 | nladdr->nl_pid = nlk->dst_pid; | 662 | nladdr->nl_pid = nlk->dst_pid; |
663 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); | 663 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
664 | } else { | 664 | } else { |
665 | nladdr->nl_pid = nlk->pid; | 665 | nladdr->nl_pid = nlk->pid; |
666 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; | 666 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; |
667 | } | 667 | } |
668 | return 0; | 668 | return 0; |
669 | } | 669 | } |
670 | 670 | ||
671 | static void netlink_overrun(struct sock *sk) | 671 | static void netlink_overrun(struct sock *sk) |
672 | { | 672 | { |
673 | if (!test_and_set_bit(0, &nlk_sk(sk)->state)) { | 673 | if (!test_and_set_bit(0, &nlk_sk(sk)->state)) { |
674 | sk->sk_err = ENOBUFS; | 674 | sk->sk_err = ENOBUFS; |
675 | sk->sk_error_report(sk); | 675 | sk->sk_error_report(sk); |
676 | } | 676 | } |
677 | } | 677 | } |
678 | 678 | ||
679 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) | 679 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) |
680 | { | 680 | { |
681 | int protocol = ssk->sk_protocol; | 681 | int protocol = ssk->sk_protocol; |
682 | struct sock *sock; | 682 | struct sock *sock; |
683 | struct netlink_sock *nlk; | 683 | struct netlink_sock *nlk; |
684 | 684 | ||
685 | sock = netlink_lookup(protocol, pid); | 685 | sock = netlink_lookup(protocol, pid); |
686 | if (!sock) | 686 | if (!sock) |
687 | return ERR_PTR(-ECONNREFUSED); | 687 | return ERR_PTR(-ECONNREFUSED); |
688 | 688 | ||
689 | /* Don't bother queuing skb if kernel socket has no input function */ | 689 | /* Don't bother queuing skb if kernel socket has no input function */ |
690 | nlk = nlk_sk(sock); | 690 | nlk = nlk_sk(sock); |
691 | if ((nlk->pid == 0 && !nlk->data_ready) || | 691 | if ((nlk->pid == 0 && !nlk->data_ready) || |
692 | (sock->sk_state == NETLINK_CONNECTED && | 692 | (sock->sk_state == NETLINK_CONNECTED && |
693 | nlk->dst_pid != nlk_sk(ssk)->pid)) { | 693 | nlk->dst_pid != nlk_sk(ssk)->pid)) { |
694 | sock_put(sock); | 694 | sock_put(sock); |
695 | return ERR_PTR(-ECONNREFUSED); | 695 | return ERR_PTR(-ECONNREFUSED); |
696 | } | 696 | } |
697 | return sock; | 697 | return sock; |
698 | } | 698 | } |
699 | 699 | ||
700 | struct sock *netlink_getsockbyfilp(struct file *filp) | 700 | struct sock *netlink_getsockbyfilp(struct file *filp) |
701 | { | 701 | { |
702 | struct inode *inode = filp->f_dentry->d_inode; | 702 | struct inode *inode = filp->f_dentry->d_inode; |
703 | struct sock *sock; | 703 | struct sock *sock; |
704 | 704 | ||
705 | if (!S_ISSOCK(inode->i_mode)) | 705 | if (!S_ISSOCK(inode->i_mode)) |
706 | return ERR_PTR(-ENOTSOCK); | 706 | return ERR_PTR(-ENOTSOCK); |
707 | 707 | ||
708 | sock = SOCKET_I(inode)->sk; | 708 | sock = SOCKET_I(inode)->sk; |
709 | if (sock->sk_family != AF_NETLINK) | 709 | if (sock->sk_family != AF_NETLINK) |
710 | return ERR_PTR(-EINVAL); | 710 | return ERR_PTR(-EINVAL); |
711 | 711 | ||
712 | sock_hold(sock); | 712 | sock_hold(sock); |
713 | return sock; | 713 | return sock; |
714 | } | 714 | } |
715 | 715 | ||
716 | /* | 716 | /* |
717 | * Attach a skb to a netlink socket. | 717 | * Attach a skb to a netlink socket. |
718 | * The caller must hold a reference to the destination socket. On error, the | 718 | * The caller must hold a reference to the destination socket. On error, the |
719 | * reference is dropped. The skb is not send to the destination, just all | 719 | * reference is dropped. The skb is not send to the destination, just all |
720 | * all error checks are performed and memory in the queue is reserved. | 720 | * all error checks are performed and memory in the queue is reserved. |
721 | * Return values: | 721 | * Return values: |
722 | * < 0: error. skb freed, reference to sock dropped. | 722 | * < 0: error. skb freed, reference to sock dropped. |
723 | * 0: continue | 723 | * 0: continue |
724 | * 1: repeat lookup - reference dropped while waiting for socket memory. | 724 | * 1: repeat lookup - reference dropped while waiting for socket memory. |
725 | */ | 725 | */ |
726 | int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, | 726 | int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, |
727 | long timeo, struct sock *ssk) | 727 | long timeo, struct sock *ssk) |
728 | { | 728 | { |
729 | struct netlink_sock *nlk; | 729 | struct netlink_sock *nlk; |
730 | 730 | ||
731 | nlk = nlk_sk(sk); | 731 | nlk = nlk_sk(sk); |
732 | 732 | ||
733 | if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || | 733 | if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || |
734 | test_bit(0, &nlk->state)) { | 734 | test_bit(0, &nlk->state)) { |
735 | DECLARE_WAITQUEUE(wait, current); | 735 | DECLARE_WAITQUEUE(wait, current); |
736 | if (!timeo) { | 736 | if (!timeo) { |
737 | if (!ssk || nlk_sk(ssk)->pid == 0) | 737 | if (!ssk || nlk_sk(ssk)->pid == 0) |
738 | netlink_overrun(sk); | 738 | netlink_overrun(sk); |
739 | sock_put(sk); | 739 | sock_put(sk); |
740 | kfree_skb(skb); | 740 | kfree_skb(skb); |
741 | return -EAGAIN; | 741 | return -EAGAIN; |
742 | } | 742 | } |
743 | 743 | ||
744 | __set_current_state(TASK_INTERRUPTIBLE); | 744 | __set_current_state(TASK_INTERRUPTIBLE); |
745 | add_wait_queue(&nlk->wait, &wait); | 745 | add_wait_queue(&nlk->wait, &wait); |
746 | 746 | ||
747 | if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || | 747 | if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || |
748 | test_bit(0, &nlk->state)) && | 748 | test_bit(0, &nlk->state)) && |
749 | !sock_flag(sk, SOCK_DEAD)) | 749 | !sock_flag(sk, SOCK_DEAD)) |
750 | timeo = schedule_timeout(timeo); | 750 | timeo = schedule_timeout(timeo); |
751 | 751 | ||
752 | __set_current_state(TASK_RUNNING); | 752 | __set_current_state(TASK_RUNNING); |
753 | remove_wait_queue(&nlk->wait, &wait); | 753 | remove_wait_queue(&nlk->wait, &wait); |
754 | sock_put(sk); | 754 | sock_put(sk); |
755 | 755 | ||
756 | if (signal_pending(current)) { | 756 | if (signal_pending(current)) { |
757 | kfree_skb(skb); | 757 | kfree_skb(skb); |
758 | return sock_intr_errno(timeo); | 758 | return sock_intr_errno(timeo); |
759 | } | 759 | } |
760 | return 1; | 760 | return 1; |
761 | } | 761 | } |
762 | skb_set_owner_r(skb, sk); | 762 | skb_set_owner_r(skb, sk); |
763 | return 0; | 763 | return 0; |
764 | } | 764 | } |
765 | 765 | ||
766 | int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) | 766 | int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) |
767 | { | 767 | { |
768 | int len = skb->len; | 768 | int len = skb->len; |
769 | 769 | ||
770 | skb_queue_tail(&sk->sk_receive_queue, skb); | 770 | skb_queue_tail(&sk->sk_receive_queue, skb); |
771 | sk->sk_data_ready(sk, len); | 771 | sk->sk_data_ready(sk, len); |
772 | sock_put(sk); | 772 | sock_put(sk); |
773 | return len; | 773 | return len; |
774 | } | 774 | } |
775 | 775 | ||
776 | void netlink_detachskb(struct sock *sk, struct sk_buff *skb) | 776 | void netlink_detachskb(struct sock *sk, struct sk_buff *skb) |
777 | { | 777 | { |
778 | kfree_skb(skb); | 778 | kfree_skb(skb); |
779 | sock_put(sk); | 779 | sock_put(sk); |
780 | } | 780 | } |
781 | 781 | ||
782 | static inline struct sk_buff *netlink_trim(struct sk_buff *skb, | 782 | static inline struct sk_buff *netlink_trim(struct sk_buff *skb, |
783 | gfp_t allocation) | 783 | gfp_t allocation) |
784 | { | 784 | { |
785 | int delta; | 785 | int delta; |
786 | 786 | ||
787 | skb_orphan(skb); | 787 | skb_orphan(skb); |
788 | 788 | ||
789 | delta = skb->end - skb->tail; | 789 | delta = skb->end - skb->tail; |
790 | if (delta * 2 < skb->truesize) | 790 | if (delta * 2 < skb->truesize) |
791 | return skb; | 791 | return skb; |
792 | 792 | ||
793 | if (skb_shared(skb)) { | 793 | if (skb_shared(skb)) { |
794 | struct sk_buff *nskb = skb_clone(skb, allocation); | 794 | struct sk_buff *nskb = skb_clone(skb, allocation); |
795 | if (!nskb) | 795 | if (!nskb) |
796 | return skb; | 796 | return skb; |
797 | kfree_skb(skb); | 797 | kfree_skb(skb); |
798 | skb = nskb; | 798 | skb = nskb; |
799 | } | 799 | } |
800 | 800 | ||
801 | if (!pskb_expand_head(skb, 0, -delta, allocation)) | 801 | if (!pskb_expand_head(skb, 0, -delta, allocation)) |
802 | skb->truesize -= delta; | 802 | skb->truesize -= delta; |
803 | 803 | ||
804 | return skb; | 804 | return skb; |
805 | } | 805 | } |
806 | 806 | ||
807 | int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) | 807 | int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) |
808 | { | 808 | { |
809 | struct sock *sk; | 809 | struct sock *sk; |
810 | int err; | 810 | int err; |
811 | long timeo; | 811 | long timeo; |
812 | 812 | ||
813 | skb = netlink_trim(skb, gfp_any()); | 813 | skb = netlink_trim(skb, gfp_any()); |
814 | 814 | ||
815 | timeo = sock_sndtimeo(ssk, nonblock); | 815 | timeo = sock_sndtimeo(ssk, nonblock); |
816 | retry: | 816 | retry: |
817 | sk = netlink_getsockbypid(ssk, pid); | 817 | sk = netlink_getsockbypid(ssk, pid); |
818 | if (IS_ERR(sk)) { | 818 | if (IS_ERR(sk)) { |
819 | kfree_skb(skb); | 819 | kfree_skb(skb); |
820 | return PTR_ERR(sk); | 820 | return PTR_ERR(sk); |
821 | } | 821 | } |
822 | err = netlink_attachskb(sk, skb, nonblock, timeo, ssk); | 822 | err = netlink_attachskb(sk, skb, nonblock, timeo, ssk); |
823 | if (err == 1) | 823 | if (err == 1) |
824 | goto retry; | 824 | goto retry; |
825 | if (err) | 825 | if (err) |
826 | return err; | 826 | return err; |
827 | 827 | ||
828 | return netlink_sendskb(sk, skb, ssk->sk_protocol); | 828 | return netlink_sendskb(sk, skb, ssk->sk_protocol); |
829 | } | 829 | } |
830 | 830 | ||
831 | int netlink_has_listeners(struct sock *sk, unsigned int group) | 831 | int netlink_has_listeners(struct sock *sk, unsigned int group) |
832 | { | 832 | { |
833 | int res = 0; | 833 | int res = 0; |
834 | 834 | ||
835 | BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET)); | 835 | BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET)); |
836 | if (group - 1 < nl_table[sk->sk_protocol].groups) | 836 | if (group - 1 < nl_table[sk->sk_protocol].groups) |
837 | res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners); | 837 | res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners); |
838 | return res; | 838 | return res; |
839 | } | 839 | } |
840 | EXPORT_SYMBOL_GPL(netlink_has_listeners); | 840 | EXPORT_SYMBOL_GPL(netlink_has_listeners); |
841 | 841 | ||
842 | static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) | 842 | static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) |
843 | { | 843 | { |
844 | struct netlink_sock *nlk = nlk_sk(sk); | 844 | struct netlink_sock *nlk = nlk_sk(sk); |
845 | 845 | ||
846 | if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && | 846 | if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && |
847 | !test_bit(0, &nlk->state)) { | 847 | !test_bit(0, &nlk->state)) { |
848 | skb_set_owner_r(skb, sk); | 848 | skb_set_owner_r(skb, sk); |
849 | skb_queue_tail(&sk->sk_receive_queue, skb); | 849 | skb_queue_tail(&sk->sk_receive_queue, skb); |
850 | sk->sk_data_ready(sk, skb->len); | 850 | sk->sk_data_ready(sk, skb->len); |
851 | return atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf; | 851 | return atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf; |
852 | } | 852 | } |
853 | return -1; | 853 | return -1; |
854 | } | 854 | } |
855 | 855 | ||
856 | struct netlink_broadcast_data { | 856 | struct netlink_broadcast_data { |
857 | struct sock *exclude_sk; | 857 | struct sock *exclude_sk; |
858 | u32 pid; | 858 | u32 pid; |
859 | u32 group; | 859 | u32 group; |
860 | int failure; | 860 | int failure; |
861 | int congested; | 861 | int congested; |
862 | int delivered; | 862 | int delivered; |
863 | gfp_t allocation; | 863 | gfp_t allocation; |
864 | struct sk_buff *skb, *skb2; | 864 | struct sk_buff *skb, *skb2; |
865 | }; | 865 | }; |
866 | 866 | ||
867 | static inline int do_one_broadcast(struct sock *sk, | 867 | static inline int do_one_broadcast(struct sock *sk, |
868 | struct netlink_broadcast_data *p) | 868 | struct netlink_broadcast_data *p) |
869 | { | 869 | { |
870 | struct netlink_sock *nlk = nlk_sk(sk); | 870 | struct netlink_sock *nlk = nlk_sk(sk); |
871 | int val; | 871 | int val; |
872 | 872 | ||
873 | if (p->exclude_sk == sk) | 873 | if (p->exclude_sk == sk) |
874 | goto out; | 874 | goto out; |
875 | 875 | ||
876 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || | 876 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
877 | !test_bit(p->group - 1, nlk->groups)) | 877 | !test_bit(p->group - 1, nlk->groups)) |
878 | goto out; | 878 | goto out; |
879 | 879 | ||
880 | if (p->failure) { | 880 | if (p->failure) { |
881 | netlink_overrun(sk); | 881 | netlink_overrun(sk); |
882 | goto out; | 882 | goto out; |
883 | } | 883 | } |
884 | 884 | ||
885 | sock_hold(sk); | 885 | sock_hold(sk); |
886 | if (p->skb2 == NULL) { | 886 | if (p->skb2 == NULL) { |
887 | if (skb_shared(p->skb)) { | 887 | if (skb_shared(p->skb)) { |
888 | p->skb2 = skb_clone(p->skb, p->allocation); | 888 | p->skb2 = skb_clone(p->skb, p->allocation); |
889 | } else { | 889 | } else { |
890 | p->skb2 = skb_get(p->skb); | 890 | p->skb2 = skb_get(p->skb); |
891 | /* | 891 | /* |
892 | * skb ownership may have been set when | 892 | * skb ownership may have been set when |
893 | * delivered to a previous socket. | 893 | * delivered to a previous socket. |
894 | */ | 894 | */ |
895 | skb_orphan(p->skb2); | 895 | skb_orphan(p->skb2); |
896 | } | 896 | } |
897 | } | 897 | } |
898 | if (p->skb2 == NULL) { | 898 | if (p->skb2 == NULL) { |
899 | netlink_overrun(sk); | 899 | netlink_overrun(sk); |
900 | /* Clone failed. Notify ALL listeners. */ | 900 | /* Clone failed. Notify ALL listeners. */ |
901 | p->failure = 1; | 901 | p->failure = 1; |
902 | } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { | 902 | } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { |
903 | netlink_overrun(sk); | 903 | netlink_overrun(sk); |
904 | } else { | 904 | } else { |
905 | p->congested |= val; | 905 | p->congested |= val; |
906 | p->delivered = 1; | 906 | p->delivered = 1; |
907 | p->skb2 = NULL; | 907 | p->skb2 = NULL; |
908 | } | 908 | } |
909 | sock_put(sk); | 909 | sock_put(sk); |
910 | 910 | ||
911 | out: | 911 | out: |
912 | return 0; | 912 | return 0; |
913 | } | 913 | } |
914 | 914 | ||
915 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | 915 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, |
916 | u32 group, gfp_t allocation) | 916 | u32 group, gfp_t allocation) |
917 | { | 917 | { |
918 | struct netlink_broadcast_data info; | 918 | struct netlink_broadcast_data info; |
919 | struct hlist_node *node; | 919 | struct hlist_node *node; |
920 | struct sock *sk; | 920 | struct sock *sk; |
921 | 921 | ||
922 | skb = netlink_trim(skb, allocation); | 922 | skb = netlink_trim(skb, allocation); |
923 | 923 | ||
924 | info.exclude_sk = ssk; | 924 | info.exclude_sk = ssk; |
925 | info.pid = pid; | 925 | info.pid = pid; |
926 | info.group = group; | 926 | info.group = group; |
927 | info.failure = 0; | 927 | info.failure = 0; |
928 | info.congested = 0; | 928 | info.congested = 0; |
929 | info.delivered = 0; | 929 | info.delivered = 0; |
930 | info.allocation = allocation; | 930 | info.allocation = allocation; |
931 | info.skb = skb; | 931 | info.skb = skb; |
932 | info.skb2 = NULL; | 932 | info.skb2 = NULL; |
933 | 933 | ||
934 | /* While we sleep in clone, do not allow to change socket list */ | 934 | /* While we sleep in clone, do not allow to change socket list */ |
935 | 935 | ||
936 | netlink_lock_table(); | 936 | netlink_lock_table(); |
937 | 937 | ||
938 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) | 938 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) |
939 | do_one_broadcast(sk, &info); | 939 | do_one_broadcast(sk, &info); |
940 | 940 | ||
941 | kfree_skb(skb); | 941 | kfree_skb(skb); |
942 | 942 | ||
943 | netlink_unlock_table(); | 943 | netlink_unlock_table(); |
944 | 944 | ||
945 | if (info.skb2) | 945 | if (info.skb2) |
946 | kfree_skb(info.skb2); | 946 | kfree_skb(info.skb2); |
947 | 947 | ||
948 | if (info.delivered) { | 948 | if (info.delivered) { |
949 | if (info.congested && (allocation & __GFP_WAIT)) | 949 | if (info.congested && (allocation & __GFP_WAIT)) |
950 | yield(); | 950 | yield(); |
951 | return 0; | 951 | return 0; |
952 | } | 952 | } |
953 | if (info.failure) | 953 | if (info.failure) |
954 | return -ENOBUFS; | 954 | return -ENOBUFS; |
955 | return -ESRCH; | 955 | return -ESRCH; |
956 | } | 956 | } |
957 | 957 | ||
958 | struct netlink_set_err_data { | 958 | struct netlink_set_err_data { |
959 | struct sock *exclude_sk; | 959 | struct sock *exclude_sk; |
960 | u32 pid; | 960 | u32 pid; |
961 | u32 group; | 961 | u32 group; |
962 | int code; | 962 | int code; |
963 | }; | 963 | }; |
964 | 964 | ||
965 | static inline int do_one_set_err(struct sock *sk, | 965 | static inline int do_one_set_err(struct sock *sk, |
966 | struct netlink_set_err_data *p) | 966 | struct netlink_set_err_data *p) |
967 | { | 967 | { |
968 | struct netlink_sock *nlk = nlk_sk(sk); | 968 | struct netlink_sock *nlk = nlk_sk(sk); |
969 | 969 | ||
970 | if (sk == p->exclude_sk) | 970 | if (sk == p->exclude_sk) |
971 | goto out; | 971 | goto out; |
972 | 972 | ||
973 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || | 973 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
974 | !test_bit(p->group - 1, nlk->groups)) | 974 | !test_bit(p->group - 1, nlk->groups)) |
975 | goto out; | 975 | goto out; |
976 | 976 | ||
977 | sk->sk_err = p->code; | 977 | sk->sk_err = p->code; |
978 | sk->sk_error_report(sk); | 978 | sk->sk_error_report(sk); |
979 | out: | 979 | out: |
980 | return 0; | 980 | return 0; |
981 | } | 981 | } |
982 | 982 | ||
983 | void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | 983 | void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) |
984 | { | 984 | { |
985 | struct netlink_set_err_data info; | 985 | struct netlink_set_err_data info; |
986 | struct hlist_node *node; | 986 | struct hlist_node *node; |
987 | struct sock *sk; | 987 | struct sock *sk; |
988 | 988 | ||
989 | info.exclude_sk = ssk; | 989 | info.exclude_sk = ssk; |
990 | info.pid = pid; | 990 | info.pid = pid; |
991 | info.group = group; | 991 | info.group = group; |
992 | info.code = code; | 992 | info.code = code; |
993 | 993 | ||
994 | read_lock(&nl_table_lock); | 994 | read_lock(&nl_table_lock); |
995 | 995 | ||
996 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) | 996 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) |
997 | do_one_set_err(sk, &info); | 997 | do_one_set_err(sk, &info); |
998 | 998 | ||
999 | read_unlock(&nl_table_lock); | 999 | read_unlock(&nl_table_lock); |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | static int netlink_setsockopt(struct socket *sock, int level, int optname, | 1002 | static int netlink_setsockopt(struct socket *sock, int level, int optname, |
1003 | char __user *optval, int optlen) | 1003 | char __user *optval, int optlen) |
1004 | { | 1004 | { |
1005 | struct sock *sk = sock->sk; | 1005 | struct sock *sk = sock->sk; |
1006 | struct netlink_sock *nlk = nlk_sk(sk); | 1006 | struct netlink_sock *nlk = nlk_sk(sk); |
1007 | int val = 0, err; | 1007 | int val = 0, err; |
1008 | 1008 | ||
1009 | if (level != SOL_NETLINK) | 1009 | if (level != SOL_NETLINK) |
1010 | return -ENOPROTOOPT; | 1010 | return -ENOPROTOOPT; |
1011 | 1011 | ||
1012 | if (optlen >= sizeof(int) && | 1012 | if (optlen >= sizeof(int) && |
1013 | get_user(val, (int __user *)optval)) | 1013 | get_user(val, (int __user *)optval)) |
1014 | return -EFAULT; | 1014 | return -EFAULT; |
1015 | 1015 | ||
1016 | switch (optname) { | 1016 | switch (optname) { |
1017 | case NETLINK_PKTINFO: | 1017 | case NETLINK_PKTINFO: |
1018 | if (val) | 1018 | if (val) |
1019 | nlk->flags |= NETLINK_RECV_PKTINFO; | 1019 | nlk->flags |= NETLINK_RECV_PKTINFO; |
1020 | else | 1020 | else |
1021 | nlk->flags &= ~NETLINK_RECV_PKTINFO; | 1021 | nlk->flags &= ~NETLINK_RECV_PKTINFO; |
1022 | err = 0; | 1022 | err = 0; |
1023 | break; | 1023 | break; |
1024 | case NETLINK_ADD_MEMBERSHIP: | 1024 | case NETLINK_ADD_MEMBERSHIP: |
1025 | case NETLINK_DROP_MEMBERSHIP: { | 1025 | case NETLINK_DROP_MEMBERSHIP: { |
1026 | unsigned int subscriptions; | 1026 | unsigned int subscriptions; |
1027 | int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0; | 1027 | int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0; |
1028 | 1028 | ||
1029 | if (!netlink_capable(sock, NL_NONROOT_RECV)) | 1029 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
1030 | return -EPERM; | 1030 | return -EPERM; |
1031 | if (nlk->groups == NULL) { | 1031 | if (nlk->groups == NULL) { |
1032 | err = netlink_alloc_groups(sk); | 1032 | err = netlink_alloc_groups(sk); |
1033 | if (err) | 1033 | if (err) |
1034 | return err; | 1034 | return err; |
1035 | } | 1035 | } |
1036 | if (!val || val - 1 >= nlk->ngroups) | 1036 | if (!val || val - 1 >= nlk->ngroups) |
1037 | return -EINVAL; | 1037 | return -EINVAL; |
1038 | netlink_table_grab(); | 1038 | netlink_table_grab(); |
1039 | old = test_bit(val - 1, nlk->groups); | 1039 | old = test_bit(val - 1, nlk->groups); |
1040 | subscriptions = nlk->subscriptions - old + new; | 1040 | subscriptions = nlk->subscriptions - old + new; |
1041 | if (new) | 1041 | if (new) |
1042 | __set_bit(val - 1, nlk->groups); | 1042 | __set_bit(val - 1, nlk->groups); |
1043 | else | 1043 | else |
1044 | __clear_bit(val - 1, nlk->groups); | 1044 | __clear_bit(val - 1, nlk->groups); |
1045 | netlink_update_subscriptions(sk, subscriptions); | 1045 | netlink_update_subscriptions(sk, subscriptions); |
1046 | netlink_update_listeners(sk); | 1046 | netlink_update_listeners(sk); |
1047 | netlink_table_ungrab(); | 1047 | netlink_table_ungrab(); |
1048 | err = 0; | 1048 | err = 0; |
1049 | break; | 1049 | break; |
1050 | } | 1050 | } |
1051 | default: | 1051 | default: |
1052 | err = -ENOPROTOOPT; | 1052 | err = -ENOPROTOOPT; |
1053 | } | 1053 | } |
1054 | return err; | 1054 | return err; |
1055 | } | 1055 | } |
1056 | 1056 | ||
1057 | static int netlink_getsockopt(struct socket *sock, int level, int optname, | 1057 | static int netlink_getsockopt(struct socket *sock, int level, int optname, |
1058 | char __user *optval, int __user *optlen) | 1058 | char __user *optval, int __user *optlen) |
1059 | { | 1059 | { |
1060 | struct sock *sk = sock->sk; | 1060 | struct sock *sk = sock->sk; |
1061 | struct netlink_sock *nlk = nlk_sk(sk); | 1061 | struct netlink_sock *nlk = nlk_sk(sk); |
1062 | int len, val, err; | 1062 | int len, val, err; |
1063 | 1063 | ||
1064 | if (level != SOL_NETLINK) | 1064 | if (level != SOL_NETLINK) |
1065 | return -ENOPROTOOPT; | 1065 | return -ENOPROTOOPT; |
1066 | 1066 | ||
1067 | if (get_user(len, optlen)) | 1067 | if (get_user(len, optlen)) |
1068 | return -EFAULT; | 1068 | return -EFAULT; |
1069 | if (len < 0) | 1069 | if (len < 0) |
1070 | return -EINVAL; | 1070 | return -EINVAL; |
1071 | 1071 | ||
1072 | switch (optname) { | 1072 | switch (optname) { |
1073 | case NETLINK_PKTINFO: | 1073 | case NETLINK_PKTINFO: |
1074 | if (len < sizeof(int)) | 1074 | if (len < sizeof(int)) |
1075 | return -EINVAL; | 1075 | return -EINVAL; |
1076 | len = sizeof(int); | 1076 | len = sizeof(int); |
1077 | val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; | 1077 | val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; |
1078 | if (put_user(len, optlen) || | 1078 | if (put_user(len, optlen) || |
1079 | put_user(val, optval)) | 1079 | put_user(val, optval)) |
1080 | return -EFAULT; | 1080 | return -EFAULT; |
1081 | err = 0; | 1081 | err = 0; |
1082 | break; | 1082 | break; |
1083 | default: | 1083 | default: |
1084 | err = -ENOPROTOOPT; | 1084 | err = -ENOPROTOOPT; |
1085 | } | 1085 | } |
1086 | return err; | 1086 | return err; |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | 1089 | static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) |
1090 | { | 1090 | { |
1091 | struct nl_pktinfo info; | 1091 | struct nl_pktinfo info; |
1092 | 1092 | ||
1093 | info.group = NETLINK_CB(skb).dst_group; | 1093 | info.group = NETLINK_CB(skb).dst_group; |
1094 | put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); | 1094 | put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | static inline void netlink_rcv_wake(struct sock *sk) | 1097 | static inline void netlink_rcv_wake(struct sock *sk) |
1098 | { | 1098 | { |
1099 | struct netlink_sock *nlk = nlk_sk(sk); | 1099 | struct netlink_sock *nlk = nlk_sk(sk); |
1100 | 1100 | ||
1101 | if (skb_queue_empty(&sk->sk_receive_queue)) | 1101 | if (skb_queue_empty(&sk->sk_receive_queue)) |
1102 | clear_bit(0, &nlk->state); | 1102 | clear_bit(0, &nlk->state); |
1103 | if (!test_bit(0, &nlk->state)) | 1103 | if (!test_bit(0, &nlk->state)) |
1104 | wake_up_interruptible(&nlk->wait); | 1104 | wake_up_interruptible(&nlk->wait); |
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | 1107 | static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, |
1108 | struct msghdr *msg, size_t len) | 1108 | struct msghdr *msg, size_t len) |
1109 | { | 1109 | { |
1110 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); | 1110 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); |
1111 | struct sock *sk = sock->sk; | 1111 | struct sock *sk = sock->sk; |
1112 | struct netlink_sock *nlk = nlk_sk(sk); | 1112 | struct netlink_sock *nlk = nlk_sk(sk); |
1113 | struct sockaddr_nl *addr=msg->msg_name; | 1113 | struct sockaddr_nl *addr=msg->msg_name; |
1114 | u32 dst_pid; | 1114 | u32 dst_pid; |
1115 | u32 dst_group; | 1115 | u32 dst_group; |
1116 | struct sk_buff *skb; | 1116 | struct sk_buff *skb; |
1117 | int err; | 1117 | int err; |
1118 | struct scm_cookie scm; | 1118 | struct scm_cookie scm; |
1119 | 1119 | ||
1120 | if (msg->msg_flags&MSG_OOB) | 1120 | if (msg->msg_flags&MSG_OOB) |
1121 | return -EOPNOTSUPP; | 1121 | return -EOPNOTSUPP; |
1122 | 1122 | ||
1123 | if (NULL == siocb->scm) | 1123 | if (NULL == siocb->scm) |
1124 | siocb->scm = &scm; | 1124 | siocb->scm = &scm; |
1125 | err = scm_send(sock, msg, siocb->scm); | 1125 | err = scm_send(sock, msg, siocb->scm); |
1126 | if (err < 0) | 1126 | if (err < 0) |
1127 | return err; | 1127 | return err; |
1128 | 1128 | ||
1129 | if (msg->msg_namelen) { | 1129 | if (msg->msg_namelen) { |
1130 | if (addr->nl_family != AF_NETLINK) | 1130 | if (addr->nl_family != AF_NETLINK) |
1131 | return -EINVAL; | 1131 | return -EINVAL; |
1132 | dst_pid = addr->nl_pid; | 1132 | dst_pid = addr->nl_pid; |
1133 | dst_group = ffs(addr->nl_groups); | 1133 | dst_group = ffs(addr->nl_groups); |
1134 | if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) | 1134 | if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) |
1135 | return -EPERM; | 1135 | return -EPERM; |
1136 | } else { | 1136 | } else { |
1137 | dst_pid = nlk->dst_pid; | 1137 | dst_pid = nlk->dst_pid; |
1138 | dst_group = nlk->dst_group; | 1138 | dst_group = nlk->dst_group; |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | if (!nlk->pid) { | 1141 | if (!nlk->pid) { |
1142 | err = netlink_autobind(sock); | 1142 | err = netlink_autobind(sock); |
1143 | if (err) | 1143 | if (err) |
1144 | goto out; | 1144 | goto out; |
1145 | } | 1145 | } |
1146 | 1146 | ||
1147 | err = -EMSGSIZE; | 1147 | err = -EMSGSIZE; |
1148 | if (len > sk->sk_sndbuf - 32) | 1148 | if (len > sk->sk_sndbuf - 32) |
1149 | goto out; | 1149 | goto out; |
1150 | err = -ENOBUFS; | 1150 | err = -ENOBUFS; |
1151 | skb = alloc_skb(len, GFP_KERNEL); | 1151 | skb = alloc_skb(len, GFP_KERNEL); |
1152 | if (skb==NULL) | 1152 | if (skb==NULL) |
1153 | goto out; | 1153 | goto out; |
1154 | 1154 | ||
1155 | NETLINK_CB(skb).pid = nlk->pid; | 1155 | NETLINK_CB(skb).pid = nlk->pid; |
1156 | NETLINK_CB(skb).dst_pid = dst_pid; | ||
1157 | NETLINK_CB(skb).dst_group = dst_group; | 1156 | NETLINK_CB(skb).dst_group = dst_group; |
1158 | NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); | 1157 | NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); |
1159 | selinux_get_task_sid(current, &(NETLINK_CB(skb).sid)); | 1158 | selinux_get_task_sid(current, &(NETLINK_CB(skb).sid)); |
1160 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1159 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
1161 | 1160 | ||
1162 | /* What can I do? Netlink is asynchronous, so that | 1161 | /* What can I do? Netlink is asynchronous, so that |
1163 | we will have to save current capabilities to | 1162 | we will have to save current capabilities to |
1164 | check them, when this message will be delivered | 1163 | check them, when this message will be delivered |
1165 | to corresponding kernel module. --ANK (980802) | 1164 | to corresponding kernel module. --ANK (980802) |
1166 | */ | 1165 | */ |
1167 | 1166 | ||
1168 | err = -EFAULT; | 1167 | err = -EFAULT; |
1169 | if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) { | 1168 | if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) { |
1170 | kfree_skb(skb); | 1169 | kfree_skb(skb); |
1171 | goto out; | 1170 | goto out; |
1172 | } | 1171 | } |
1173 | 1172 | ||
1174 | err = security_netlink_send(sk, skb); | 1173 | err = security_netlink_send(sk, skb); |
1175 | if (err) { | 1174 | if (err) { |
1176 | kfree_skb(skb); | 1175 | kfree_skb(skb); |
1177 | goto out; | 1176 | goto out; |
1178 | } | 1177 | } |
1179 | 1178 | ||
1180 | if (dst_group) { | 1179 | if (dst_group) { |
1181 | atomic_inc(&skb->users); | 1180 | atomic_inc(&skb->users); |
1182 | netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL); | 1181 | netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL); |
1183 | } | 1182 | } |
1184 | err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); | 1183 | err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); |
1185 | 1184 | ||
1186 | out: | 1185 | out: |
1187 | return err; | 1186 | return err; |
1188 | } | 1187 | } |
1189 | 1188 | ||
1190 | static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | 1189 | static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, |
1191 | struct msghdr *msg, size_t len, | 1190 | struct msghdr *msg, size_t len, |
1192 | int flags) | 1191 | int flags) |
1193 | { | 1192 | { |
1194 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); | 1193 | struct sock_iocb *siocb = kiocb_to_siocb(kiocb); |
1195 | struct scm_cookie scm; | 1194 | struct scm_cookie scm; |
1196 | struct sock *sk = sock->sk; | 1195 | struct sock *sk = sock->sk; |
1197 | struct netlink_sock *nlk = nlk_sk(sk); | 1196 | struct netlink_sock *nlk = nlk_sk(sk); |
1198 | int noblock = flags&MSG_DONTWAIT; | 1197 | int noblock = flags&MSG_DONTWAIT; |
1199 | size_t copied; | 1198 | size_t copied; |
1200 | struct sk_buff *skb; | 1199 | struct sk_buff *skb; |
1201 | int err; | 1200 | int err; |
1202 | 1201 | ||
1203 | if (flags&MSG_OOB) | 1202 | if (flags&MSG_OOB) |
1204 | return -EOPNOTSUPP; | 1203 | return -EOPNOTSUPP; |
1205 | 1204 | ||
1206 | copied = 0; | 1205 | copied = 0; |
1207 | 1206 | ||
1208 | skb = skb_recv_datagram(sk,flags,noblock,&err); | 1207 | skb = skb_recv_datagram(sk,flags,noblock,&err); |
1209 | if (skb==NULL) | 1208 | if (skb==NULL) |
1210 | goto out; | 1209 | goto out; |
1211 | 1210 | ||
1212 | msg->msg_namelen = 0; | 1211 | msg->msg_namelen = 0; |
1213 | 1212 | ||
1214 | copied = skb->len; | 1213 | copied = skb->len; |
1215 | if (len < copied) { | 1214 | if (len < copied) { |
1216 | msg->msg_flags |= MSG_TRUNC; | 1215 | msg->msg_flags |= MSG_TRUNC; |
1217 | copied = len; | 1216 | copied = len; |
1218 | } | 1217 | } |
1219 | 1218 | ||
1220 | skb->h.raw = skb->data; | 1219 | skb->h.raw = skb->data; |
1221 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 1220 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
1222 | 1221 | ||
1223 | if (msg->msg_name) { | 1222 | if (msg->msg_name) { |
1224 | struct sockaddr_nl *addr = (struct sockaddr_nl*)msg->msg_name; | 1223 | struct sockaddr_nl *addr = (struct sockaddr_nl*)msg->msg_name; |
1225 | addr->nl_family = AF_NETLINK; | 1224 | addr->nl_family = AF_NETLINK; |
1226 | addr->nl_pad = 0; | 1225 | addr->nl_pad = 0; |
1227 | addr->nl_pid = NETLINK_CB(skb).pid; | 1226 | addr->nl_pid = NETLINK_CB(skb).pid; |
1228 | addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); | 1227 | addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); |
1229 | msg->msg_namelen = sizeof(*addr); | 1228 | msg->msg_namelen = sizeof(*addr); |
1230 | } | 1229 | } |
1231 | 1230 | ||
1232 | if (nlk->flags & NETLINK_RECV_PKTINFO) | 1231 | if (nlk->flags & NETLINK_RECV_PKTINFO) |
1233 | netlink_cmsg_recv_pktinfo(msg, skb); | 1232 | netlink_cmsg_recv_pktinfo(msg, skb); |
1234 | 1233 | ||
1235 | if (NULL == siocb->scm) { | 1234 | if (NULL == siocb->scm) { |
1236 | memset(&scm, 0, sizeof(scm)); | 1235 | memset(&scm, 0, sizeof(scm)); |
1237 | siocb->scm = &scm; | 1236 | siocb->scm = &scm; |
1238 | } | 1237 | } |
1239 | siocb->scm->creds = *NETLINK_CREDS(skb); | 1238 | siocb->scm->creds = *NETLINK_CREDS(skb); |
1240 | skb_free_datagram(sk, skb); | 1239 | skb_free_datagram(sk, skb); |
1241 | 1240 | ||
1242 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) | 1241 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) |
1243 | netlink_dump(sk); | 1242 | netlink_dump(sk); |
1244 | 1243 | ||
1245 | scm_recv(sock, msg, siocb->scm, flags); | 1244 | scm_recv(sock, msg, siocb->scm, flags); |
1246 | 1245 | ||
1247 | out: | 1246 | out: |
1248 | netlink_rcv_wake(sk); | 1247 | netlink_rcv_wake(sk); |
1249 | return err ? : copied; | 1248 | return err ? : copied; |
1250 | } | 1249 | } |
1251 | 1250 | ||
1252 | static void netlink_data_ready(struct sock *sk, int len) | 1251 | static void netlink_data_ready(struct sock *sk, int len) |
1253 | { | 1252 | { |
1254 | struct netlink_sock *nlk = nlk_sk(sk); | 1253 | struct netlink_sock *nlk = nlk_sk(sk); |
1255 | 1254 | ||
1256 | if (nlk->data_ready) | 1255 | if (nlk->data_ready) |
1257 | nlk->data_ready(sk, len); | 1256 | nlk->data_ready(sk, len); |
1258 | netlink_rcv_wake(sk); | 1257 | netlink_rcv_wake(sk); |
1259 | } | 1258 | } |
1260 | 1259 | ||
1261 | /* | 1260 | /* |
1262 | * We export these functions to other modules. They provide a | 1261 | * We export these functions to other modules. They provide a |
1263 | * complete set of kernel non-blocking support for message | 1262 | * complete set of kernel non-blocking support for message |
1264 | * queueing. | 1263 | * queueing. |
1265 | */ | 1264 | */ |
1266 | 1265 | ||
1267 | struct sock * | 1266 | struct sock * |
1268 | netlink_kernel_create(int unit, unsigned int groups, | 1267 | netlink_kernel_create(int unit, unsigned int groups, |
1269 | void (*input)(struct sock *sk, int len), | 1268 | void (*input)(struct sock *sk, int len), |
1270 | struct module *module) | 1269 | struct module *module) |
1271 | { | 1270 | { |
1272 | struct socket *sock; | 1271 | struct socket *sock; |
1273 | struct sock *sk; | 1272 | struct sock *sk; |
1274 | struct netlink_sock *nlk; | 1273 | struct netlink_sock *nlk; |
1275 | unsigned long *listeners = NULL; | 1274 | unsigned long *listeners = NULL; |
1276 | 1275 | ||
1277 | BUG_ON(!nl_table); | 1276 | BUG_ON(!nl_table); |
1278 | 1277 | ||
1279 | if (unit<0 || unit>=MAX_LINKS) | 1278 | if (unit<0 || unit>=MAX_LINKS) |
1280 | return NULL; | 1279 | return NULL; |
1281 | 1280 | ||
1282 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1281 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1283 | return NULL; | 1282 | return NULL; |
1284 | 1283 | ||
1285 | if (__netlink_create(sock, unit) < 0) | 1284 | if (__netlink_create(sock, unit) < 0) |
1286 | goto out_sock_release; | 1285 | goto out_sock_release; |
1287 | 1286 | ||
1288 | if (groups < 32) | 1287 | if (groups < 32) |
1289 | groups = 32; | 1288 | groups = 32; |
1290 | 1289 | ||
1291 | listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL); | 1290 | listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL); |
1292 | if (!listeners) | 1291 | if (!listeners) |
1293 | goto out_sock_release; | 1292 | goto out_sock_release; |
1294 | 1293 | ||
1295 | sk = sock->sk; | 1294 | sk = sock->sk; |
1296 | sk->sk_data_ready = netlink_data_ready; | 1295 | sk->sk_data_ready = netlink_data_ready; |
1297 | if (input) | 1296 | if (input) |
1298 | nlk_sk(sk)->data_ready = input; | 1297 | nlk_sk(sk)->data_ready = input; |
1299 | 1298 | ||
1300 | if (netlink_insert(sk, 0)) | 1299 | if (netlink_insert(sk, 0)) |
1301 | goto out_sock_release; | 1300 | goto out_sock_release; |
1302 | 1301 | ||
1303 | nlk = nlk_sk(sk); | 1302 | nlk = nlk_sk(sk); |
1304 | nlk->flags |= NETLINK_KERNEL_SOCKET; | 1303 | nlk->flags |= NETLINK_KERNEL_SOCKET; |
1305 | 1304 | ||
1306 | netlink_table_grab(); | 1305 | netlink_table_grab(); |
1307 | nl_table[unit].groups = groups; | 1306 | nl_table[unit].groups = groups; |
1308 | nl_table[unit].listeners = listeners; | 1307 | nl_table[unit].listeners = listeners; |
1309 | nl_table[unit].module = module; | 1308 | nl_table[unit].module = module; |
1310 | nl_table[unit].registered = 1; | 1309 | nl_table[unit].registered = 1; |
1311 | netlink_table_ungrab(); | 1310 | netlink_table_ungrab(); |
1312 | 1311 | ||
1313 | return sk; | 1312 | return sk; |
1314 | 1313 | ||
1315 | out_sock_release: | 1314 | out_sock_release: |
1316 | kfree(listeners); | 1315 | kfree(listeners); |
1317 | sock_release(sock); | 1316 | sock_release(sock); |
1318 | return NULL; | 1317 | return NULL; |
1319 | } | 1318 | } |
1320 | 1319 | ||
1321 | void netlink_set_nonroot(int protocol, unsigned int flags) | 1320 | void netlink_set_nonroot(int protocol, unsigned int flags) |
1322 | { | 1321 | { |
1323 | if ((unsigned int)protocol < MAX_LINKS) | 1322 | if ((unsigned int)protocol < MAX_LINKS) |
1324 | nl_table[protocol].nl_nonroot = flags; | 1323 | nl_table[protocol].nl_nonroot = flags; |
1325 | } | 1324 | } |
1326 | 1325 | ||
1327 | static void netlink_destroy_callback(struct netlink_callback *cb) | 1326 | static void netlink_destroy_callback(struct netlink_callback *cb) |
1328 | { | 1327 | { |
1329 | if (cb->skb) | 1328 | if (cb->skb) |
1330 | kfree_skb(cb->skb); | 1329 | kfree_skb(cb->skb); |
1331 | kfree(cb); | 1330 | kfree(cb); |
1332 | } | 1331 | } |
1333 | 1332 | ||
1334 | /* | 1333 | /* |
1335 | * It looks a bit ugly. | 1334 | * It looks a bit ugly. |
1336 | * It would be better to create kernel thread. | 1335 | * It would be better to create kernel thread. |
1337 | */ | 1336 | */ |
1338 | 1337 | ||
1339 | static int netlink_dump(struct sock *sk) | 1338 | static int netlink_dump(struct sock *sk) |
1340 | { | 1339 | { |
1341 | struct netlink_sock *nlk = nlk_sk(sk); | 1340 | struct netlink_sock *nlk = nlk_sk(sk); |
1342 | struct netlink_callback *cb; | 1341 | struct netlink_callback *cb; |
1343 | struct sk_buff *skb; | 1342 | struct sk_buff *skb; |
1344 | struct nlmsghdr *nlh; | 1343 | struct nlmsghdr *nlh; |
1345 | int len, err = -ENOBUFS; | 1344 | int len, err = -ENOBUFS; |
1346 | 1345 | ||
1347 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); | 1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); |
1348 | if (!skb) | 1347 | if (!skb) |
1349 | goto errout; | 1348 | goto errout; |
1350 | 1349 | ||
1351 | spin_lock(&nlk->cb_lock); | 1350 | spin_lock(&nlk->cb_lock); |
1352 | 1351 | ||
1353 | cb = nlk->cb; | 1352 | cb = nlk->cb; |
1354 | if (cb == NULL) { | 1353 | if (cb == NULL) { |
1355 | err = -EINVAL; | 1354 | err = -EINVAL; |
1356 | goto errout_skb; | 1355 | goto errout_skb; |
1357 | } | 1356 | } |
1358 | 1357 | ||
1359 | len = cb->dump(skb, cb); | 1358 | len = cb->dump(skb, cb); |
1360 | 1359 | ||
1361 | if (len > 0) { | 1360 | if (len > 0) { |
1362 | spin_unlock(&nlk->cb_lock); | 1361 | spin_unlock(&nlk->cb_lock); |
1363 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1362 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1364 | sk->sk_data_ready(sk, len); | 1363 | sk->sk_data_ready(sk, len); |
1365 | return 0; | 1364 | return 0; |
1366 | } | 1365 | } |
1367 | 1366 | ||
1368 | nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); | 1367 | nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); |
1369 | if (!nlh) | 1368 | if (!nlh) |
1370 | goto errout_skb; | 1369 | goto errout_skb; |
1371 | 1370 | ||
1372 | memcpy(nlmsg_data(nlh), &len, sizeof(len)); | 1371 | memcpy(nlmsg_data(nlh), &len, sizeof(len)); |
1373 | 1372 | ||
1374 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1373 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1375 | sk->sk_data_ready(sk, skb->len); | 1374 | sk->sk_data_ready(sk, skb->len); |
1376 | 1375 | ||
1377 | if (cb->done) | 1376 | if (cb->done) |
1378 | cb->done(cb); | 1377 | cb->done(cb); |
1379 | nlk->cb = NULL; | 1378 | nlk->cb = NULL; |
1380 | spin_unlock(&nlk->cb_lock); | 1379 | spin_unlock(&nlk->cb_lock); |
1381 | 1380 | ||
1382 | netlink_destroy_callback(cb); | 1381 | netlink_destroy_callback(cb); |
1383 | return 0; | 1382 | return 0; |
1384 | 1383 | ||
1385 | errout_skb: | 1384 | errout_skb: |
1386 | spin_unlock(&nlk->cb_lock); | 1385 | spin_unlock(&nlk->cb_lock); |
1387 | kfree_skb(skb); | 1386 | kfree_skb(skb); |
1388 | errout: | 1387 | errout: |
1389 | return err; | 1388 | return err; |
1390 | } | 1389 | } |
1391 | 1390 | ||
1392 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 1391 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
1393 | struct nlmsghdr *nlh, | 1392 | struct nlmsghdr *nlh, |
1394 | int (*dump)(struct sk_buff *skb, struct netlink_callback*), | 1393 | int (*dump)(struct sk_buff *skb, struct netlink_callback*), |
1395 | int (*done)(struct netlink_callback*)) | 1394 | int (*done)(struct netlink_callback*)) |
1396 | { | 1395 | { |
1397 | struct netlink_callback *cb; | 1396 | struct netlink_callback *cb; |
1398 | struct sock *sk; | 1397 | struct sock *sk; |
1399 | struct netlink_sock *nlk; | 1398 | struct netlink_sock *nlk; |
1400 | 1399 | ||
1401 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); | 1400 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); |
1402 | if (cb == NULL) | 1401 | if (cb == NULL) |
1403 | return -ENOBUFS; | 1402 | return -ENOBUFS; |
1404 | 1403 | ||
1405 | cb->dump = dump; | 1404 | cb->dump = dump; |
1406 | cb->done = done; | 1405 | cb->done = done; |
1407 | cb->nlh = nlh; | 1406 | cb->nlh = nlh; |
1408 | atomic_inc(&skb->users); | 1407 | atomic_inc(&skb->users); |
1409 | cb->skb = skb; | 1408 | cb->skb = skb; |
1410 | 1409 | ||
1411 | sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); | 1410 | sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); |
1412 | if (sk == NULL) { | 1411 | if (sk == NULL) { |
1413 | netlink_destroy_callback(cb); | 1412 | netlink_destroy_callback(cb); |
1414 | return -ECONNREFUSED; | 1413 | return -ECONNREFUSED; |
1415 | } | 1414 | } |
1416 | nlk = nlk_sk(sk); | 1415 | nlk = nlk_sk(sk); |
1417 | /* A dump is in progress... */ | 1416 | /* A dump is in progress... */ |
1418 | spin_lock(&nlk->cb_lock); | 1417 | spin_lock(&nlk->cb_lock); |
1419 | if (nlk->cb) { | 1418 | if (nlk->cb) { |
1420 | spin_unlock(&nlk->cb_lock); | 1419 | spin_unlock(&nlk->cb_lock); |
1421 | netlink_destroy_callback(cb); | 1420 | netlink_destroy_callback(cb); |
1422 | sock_put(sk); | 1421 | sock_put(sk); |
1423 | return -EBUSY; | 1422 | return -EBUSY; |
1424 | } | 1423 | } |
1425 | nlk->cb = cb; | 1424 | nlk->cb = cb; |
1426 | spin_unlock(&nlk->cb_lock); | 1425 | spin_unlock(&nlk->cb_lock); |
1427 | 1426 | ||
1428 | netlink_dump(sk); | 1427 | netlink_dump(sk); |
1429 | sock_put(sk); | 1428 | sock_put(sk); |
1430 | return 0; | 1429 | return 0; |
1431 | } | 1430 | } |
1432 | 1431 | ||
1433 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | 1432 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) |
1434 | { | 1433 | { |
1435 | struct sk_buff *skb; | 1434 | struct sk_buff *skb; |
1436 | struct nlmsghdr *rep; | 1435 | struct nlmsghdr *rep; |
1437 | struct nlmsgerr *errmsg; | 1436 | struct nlmsgerr *errmsg; |
1438 | size_t payload = sizeof(*errmsg); | 1437 | size_t payload = sizeof(*errmsg); |
1439 | 1438 | ||
1440 | /* error messages get the original request appened */ | 1439 | /* error messages get the original request appened */ |
1441 | if (err) | 1440 | if (err) |
1442 | payload += nlmsg_len(nlh); | 1441 | payload += nlmsg_len(nlh); |
1443 | 1442 | ||
1444 | skb = nlmsg_new(payload, GFP_KERNEL); | 1443 | skb = nlmsg_new(payload, GFP_KERNEL); |
1445 | if (!skb) { | 1444 | if (!skb) { |
1446 | struct sock *sk; | 1445 | struct sock *sk; |
1447 | 1446 | ||
1448 | sk = netlink_lookup(in_skb->sk->sk_protocol, | 1447 | sk = netlink_lookup(in_skb->sk->sk_protocol, |
1449 | NETLINK_CB(in_skb).pid); | 1448 | NETLINK_CB(in_skb).pid); |
1450 | if (sk) { | 1449 | if (sk) { |
1451 | sk->sk_err = ENOBUFS; | 1450 | sk->sk_err = ENOBUFS; |
1452 | sk->sk_error_report(sk); | 1451 | sk->sk_error_report(sk); |
1453 | sock_put(sk); | 1452 | sock_put(sk); |
1454 | } | 1453 | } |
1455 | return; | 1454 | return; |
1456 | } | 1455 | } |
1457 | 1456 | ||
1458 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 1457 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, |
1459 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); | 1458 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); |
1460 | errmsg = nlmsg_data(rep); | 1459 | errmsg = nlmsg_data(rep); |
1461 | errmsg->error = err; | 1460 | errmsg->error = err; |
1462 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); | 1461 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); |
1463 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 1462 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); |
1464 | } | 1463 | } |
1465 | 1464 | ||
1466 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | 1465 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, |
1467 | struct nlmsghdr *, int *)) | 1466 | struct nlmsghdr *, int *)) |
1468 | { | 1467 | { |
1469 | struct nlmsghdr *nlh; | 1468 | struct nlmsghdr *nlh; |
1470 | int err; | 1469 | int err; |
1471 | 1470 | ||
1472 | while (skb->len >= nlmsg_total_size(0)) { | 1471 | while (skb->len >= nlmsg_total_size(0)) { |
1473 | nlh = (struct nlmsghdr *) skb->data; | 1472 | nlh = (struct nlmsghdr *) skb->data; |
1474 | 1473 | ||
1475 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) | 1474 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) |
1476 | return 0; | 1475 | return 0; |
1477 | 1476 | ||
1478 | if (cb(skb, nlh, &err) < 0) { | 1477 | if (cb(skb, nlh, &err) < 0) { |
1479 | /* Not an error, but we have to interrupt processing | 1478 | /* Not an error, but we have to interrupt processing |
1480 | * here. Note: that in this case we do not pull | 1479 | * here. Note: that in this case we do not pull |
1481 | * message from skb, it will be processed later. | 1480 | * message from skb, it will be processed later. |
1482 | */ | 1481 | */ |
1483 | if (err == 0) | 1482 | if (err == 0) |
1484 | return -1; | 1483 | return -1; |
1485 | netlink_ack(skb, nlh, err); | 1484 | netlink_ack(skb, nlh, err); |
1486 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | 1485 | } else if (nlh->nlmsg_flags & NLM_F_ACK) |
1487 | netlink_ack(skb, nlh, 0); | 1486 | netlink_ack(skb, nlh, 0); |
1488 | 1487 | ||
1489 | netlink_queue_skip(nlh, skb); | 1488 | netlink_queue_skip(nlh, skb); |
1490 | } | 1489 | } |
1491 | 1490 | ||
1492 | return 0; | 1491 | return 0; |
1493 | } | 1492 | } |
1494 | 1493 | ||
1495 | /** | 1494 | /** |
1496 | * nelink_run_queue - Process netlink receive queue. | 1495 | * nelink_run_queue - Process netlink receive queue. |
1497 | * @sk: Netlink socket containing the queue | 1496 | * @sk: Netlink socket containing the queue |
1498 | * @qlen: Place to store queue length upon entry | 1497 | * @qlen: Place to store queue length upon entry |
1499 | * @cb: Callback function invoked for each netlink message found | 1498 | * @cb: Callback function invoked for each netlink message found |
1500 | * | 1499 | * |
1501 | * Processes as much as there was in the queue upon entry and invokes | 1500 | * Processes as much as there was in the queue upon entry and invokes |
1502 | * a callback function for each netlink message found. The callback | 1501 | * a callback function for each netlink message found. The callback |
1503 | * function may refuse a message by returning a negative error code | 1502 | * function may refuse a message by returning a negative error code |
1504 | * but setting the error pointer to 0 in which case this function | 1503 | * but setting the error pointer to 0 in which case this function |
1505 | * returns with a qlen != 0. | 1504 | * returns with a qlen != 0. |
1506 | * | 1505 | * |
1507 | * qlen must be initialized to 0 before the initial entry, afterwards | 1506 | * qlen must be initialized to 0 before the initial entry, afterwards |
1508 | * the function may be called repeatedly until qlen reaches 0. | 1507 | * the function may be called repeatedly until qlen reaches 0. |
1509 | */ | 1508 | */ |
1510 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, | 1509 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, |
1511 | int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) | 1510 | int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) |
1512 | { | 1511 | { |
1513 | struct sk_buff *skb; | 1512 | struct sk_buff *skb; |
1514 | 1513 | ||
1515 | if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue)) | 1514 | if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue)) |
1516 | *qlen = skb_queue_len(&sk->sk_receive_queue); | 1515 | *qlen = skb_queue_len(&sk->sk_receive_queue); |
1517 | 1516 | ||
1518 | for (; *qlen; (*qlen)--) { | 1517 | for (; *qlen; (*qlen)--) { |
1519 | skb = skb_dequeue(&sk->sk_receive_queue); | 1518 | skb = skb_dequeue(&sk->sk_receive_queue); |
1520 | if (netlink_rcv_skb(skb, cb)) { | 1519 | if (netlink_rcv_skb(skb, cb)) { |
1521 | if (skb->len) | 1520 | if (skb->len) |
1522 | skb_queue_head(&sk->sk_receive_queue, skb); | 1521 | skb_queue_head(&sk->sk_receive_queue, skb); |
1523 | else { | 1522 | else { |
1524 | kfree_skb(skb); | 1523 | kfree_skb(skb); |
1525 | (*qlen)--; | 1524 | (*qlen)--; |
1526 | } | 1525 | } |
1527 | break; | 1526 | break; |
1528 | } | 1527 | } |
1529 | 1528 | ||
1530 | kfree_skb(skb); | 1529 | kfree_skb(skb); |
1531 | } | 1530 | } |
1532 | } | 1531 | } |
1533 | 1532 | ||
1534 | /** | 1533 | /** |
1535 | * netlink_queue_skip - Skip netlink message while processing queue. | 1534 | * netlink_queue_skip - Skip netlink message while processing queue. |
1536 | * @nlh: Netlink message to be skipped | 1535 | * @nlh: Netlink message to be skipped |
1537 | * @skb: Socket buffer containing the netlink messages. | 1536 | * @skb: Socket buffer containing the netlink messages. |
1538 | * | 1537 | * |
1539 | * Pulls the given netlink message off the socket buffer so the next | 1538 | * Pulls the given netlink message off the socket buffer so the next |
1540 | * call to netlink_queue_run() will not reconsider the message. | 1539 | * call to netlink_queue_run() will not reconsider the message. |
1541 | */ | 1540 | */ |
1542 | void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | 1541 | void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) |
1543 | { | 1542 | { |
1544 | int msglen = NLMSG_ALIGN(nlh->nlmsg_len); | 1543 | int msglen = NLMSG_ALIGN(nlh->nlmsg_len); |
1545 | 1544 | ||
1546 | if (msglen > skb->len) | 1545 | if (msglen > skb->len) |
1547 | msglen = skb->len; | 1546 | msglen = skb->len; |
1548 | 1547 | ||
1549 | skb_pull(skb, msglen); | 1548 | skb_pull(skb, msglen); |
1550 | } | 1549 | } |
1551 | 1550 | ||
1552 | /** | 1551 | /** |
1553 | * nlmsg_notify - send a notification netlink message | 1552 | * nlmsg_notify - send a notification netlink message |
1554 | * @sk: netlink socket to use | 1553 | * @sk: netlink socket to use |
1555 | * @skb: notification message | 1554 | * @skb: notification message |
1556 | * @pid: destination netlink pid for reports or 0 | 1555 | * @pid: destination netlink pid for reports or 0 |
1557 | * @group: destination multicast group or 0 | 1556 | * @group: destination multicast group or 0 |
1558 | * @report: 1 to report back, 0 to disable | 1557 | * @report: 1 to report back, 0 to disable |
1559 | * @flags: allocation flags | 1558 | * @flags: allocation flags |
1560 | */ | 1559 | */ |
1561 | int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, | 1560 | int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, |
1562 | unsigned int group, int report, gfp_t flags) | 1561 | unsigned int group, int report, gfp_t flags) |
1563 | { | 1562 | { |
1564 | int err = 0; | 1563 | int err = 0; |
1565 | 1564 | ||
1566 | if (group) { | 1565 | if (group) { |
1567 | int exclude_pid = 0; | 1566 | int exclude_pid = 0; |
1568 | 1567 | ||
1569 | if (report) { | 1568 | if (report) { |
1570 | atomic_inc(&skb->users); | 1569 | atomic_inc(&skb->users); |
1571 | exclude_pid = pid; | 1570 | exclude_pid = pid; |
1572 | } | 1571 | } |
1573 | 1572 | ||
1574 | /* errors reported via destination sk->sk_err */ | 1573 | /* errors reported via destination sk->sk_err */ |
1575 | nlmsg_multicast(sk, skb, exclude_pid, group, flags); | 1574 | nlmsg_multicast(sk, skb, exclude_pid, group, flags); |
1576 | } | 1575 | } |
1577 | 1576 | ||
1578 | if (report) | 1577 | if (report) |
1579 | err = nlmsg_unicast(sk, skb, pid); | 1578 | err = nlmsg_unicast(sk, skb, pid); |
1580 | 1579 | ||
1581 | return err; | 1580 | return err; |
1582 | } | 1581 | } |
1583 | 1582 | ||
1584 | #ifdef CONFIG_PROC_FS | 1583 | #ifdef CONFIG_PROC_FS |
1585 | struct nl_seq_iter { | 1584 | struct nl_seq_iter { |
1586 | int link; | 1585 | int link; |
1587 | int hash_idx; | 1586 | int hash_idx; |
1588 | }; | 1587 | }; |
1589 | 1588 | ||
1590 | static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) | 1589 | static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) |
1591 | { | 1590 | { |
1592 | struct nl_seq_iter *iter = seq->private; | 1591 | struct nl_seq_iter *iter = seq->private; |
1593 | int i, j; | 1592 | int i, j; |
1594 | struct sock *s; | 1593 | struct sock *s; |
1595 | struct hlist_node *node; | 1594 | struct hlist_node *node; |
1596 | loff_t off = 0; | 1595 | loff_t off = 0; |
1597 | 1596 | ||
1598 | for (i=0; i<MAX_LINKS; i++) { | 1597 | for (i=0; i<MAX_LINKS; i++) { |
1599 | struct nl_pid_hash *hash = &nl_table[i].hash; | 1598 | struct nl_pid_hash *hash = &nl_table[i].hash; |
1600 | 1599 | ||
1601 | for (j = 0; j <= hash->mask; j++) { | 1600 | for (j = 0; j <= hash->mask; j++) { |
1602 | sk_for_each(s, node, &hash->table[j]) { | 1601 | sk_for_each(s, node, &hash->table[j]) { |
1603 | if (off == pos) { | 1602 | if (off == pos) { |
1604 | iter->link = i; | 1603 | iter->link = i; |
1605 | iter->hash_idx = j; | 1604 | iter->hash_idx = j; |
1606 | return s; | 1605 | return s; |
1607 | } | 1606 | } |
1608 | ++off; | 1607 | ++off; |
1609 | } | 1608 | } |
1610 | } | 1609 | } |
1611 | } | 1610 | } |
1612 | return NULL; | 1611 | return NULL; |
1613 | } | 1612 | } |
1614 | 1613 | ||
1615 | static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) | 1614 | static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) |
1616 | { | 1615 | { |
1617 | read_lock(&nl_table_lock); | 1616 | read_lock(&nl_table_lock); |
1618 | return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 1617 | return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
1619 | } | 1618 | } |
1620 | 1619 | ||
1621 | static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 1620 | static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
1622 | { | 1621 | { |
1623 | struct sock *s; | 1622 | struct sock *s; |
1624 | struct nl_seq_iter *iter; | 1623 | struct nl_seq_iter *iter; |
1625 | int i, j; | 1624 | int i, j; |
1626 | 1625 | ||
1627 | ++*pos; | 1626 | ++*pos; |
1628 | 1627 | ||
1629 | if (v == SEQ_START_TOKEN) | 1628 | if (v == SEQ_START_TOKEN) |
1630 | return netlink_seq_socket_idx(seq, 0); | 1629 | return netlink_seq_socket_idx(seq, 0); |
1631 | 1630 | ||
1632 | s = sk_next(v); | 1631 | s = sk_next(v); |
1633 | if (s) | 1632 | if (s) |
1634 | return s; | 1633 | return s; |
1635 | 1634 | ||
1636 | iter = seq->private; | 1635 | iter = seq->private; |
1637 | i = iter->link; | 1636 | i = iter->link; |
1638 | j = iter->hash_idx + 1; | 1637 | j = iter->hash_idx + 1; |
1639 | 1638 | ||
1640 | do { | 1639 | do { |
1641 | struct nl_pid_hash *hash = &nl_table[i].hash; | 1640 | struct nl_pid_hash *hash = &nl_table[i].hash; |
1642 | 1641 | ||
1643 | for (; j <= hash->mask; j++) { | 1642 | for (; j <= hash->mask; j++) { |
1644 | s = sk_head(&hash->table[j]); | 1643 | s = sk_head(&hash->table[j]); |
1645 | if (s) { | 1644 | if (s) { |
1646 | iter->link = i; | 1645 | iter->link = i; |
1647 | iter->hash_idx = j; | 1646 | iter->hash_idx = j; |
1648 | return s; | 1647 | return s; |
1649 | } | 1648 | } |
1650 | } | 1649 | } |
1651 | 1650 | ||
1652 | j = 0; | 1651 | j = 0; |
1653 | } while (++i < MAX_LINKS); | 1652 | } while (++i < MAX_LINKS); |
1654 | 1653 | ||
1655 | return NULL; | 1654 | return NULL; |
1656 | } | 1655 | } |
1657 | 1656 | ||
1658 | static void netlink_seq_stop(struct seq_file *seq, void *v) | 1657 | static void netlink_seq_stop(struct seq_file *seq, void *v) |
1659 | { | 1658 | { |
1660 | read_unlock(&nl_table_lock); | 1659 | read_unlock(&nl_table_lock); |
1661 | } | 1660 | } |
1662 | 1661 | ||
1663 | 1662 | ||
1664 | static int netlink_seq_show(struct seq_file *seq, void *v) | 1663 | static int netlink_seq_show(struct seq_file *seq, void *v) |
1665 | { | 1664 | { |
1666 | if (v == SEQ_START_TOKEN) | 1665 | if (v == SEQ_START_TOKEN) |
1667 | seq_puts(seq, | 1666 | seq_puts(seq, |
1668 | "sk Eth Pid Groups " | 1667 | "sk Eth Pid Groups " |
1669 | "Rmem Wmem Dump Locks\n"); | 1668 | "Rmem Wmem Dump Locks\n"); |
1670 | else { | 1669 | else { |
1671 | struct sock *s = v; | 1670 | struct sock *s = v; |
1672 | struct netlink_sock *nlk = nlk_sk(s); | 1671 | struct netlink_sock *nlk = nlk_sk(s); |
1673 | 1672 | ||
1674 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %d\n", | 1673 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %d\n", |
1675 | s, | 1674 | s, |
1676 | s->sk_protocol, | 1675 | s->sk_protocol, |
1677 | nlk->pid, | 1676 | nlk->pid, |
1678 | nlk->groups ? (u32)nlk->groups[0] : 0, | 1677 | nlk->groups ? (u32)nlk->groups[0] : 0, |
1679 | atomic_read(&s->sk_rmem_alloc), | 1678 | atomic_read(&s->sk_rmem_alloc), |
1680 | atomic_read(&s->sk_wmem_alloc), | 1679 | atomic_read(&s->sk_wmem_alloc), |
1681 | nlk->cb, | 1680 | nlk->cb, |
1682 | atomic_read(&s->sk_refcnt) | 1681 | atomic_read(&s->sk_refcnt) |
1683 | ); | 1682 | ); |
1684 | 1683 | ||
1685 | } | 1684 | } |
1686 | return 0; | 1685 | return 0; |
1687 | } | 1686 | } |
1688 | 1687 | ||
1689 | static struct seq_operations netlink_seq_ops = { | 1688 | static struct seq_operations netlink_seq_ops = { |
1690 | .start = netlink_seq_start, | 1689 | .start = netlink_seq_start, |
1691 | .next = netlink_seq_next, | 1690 | .next = netlink_seq_next, |
1692 | .stop = netlink_seq_stop, | 1691 | .stop = netlink_seq_stop, |
1693 | .show = netlink_seq_show, | 1692 | .show = netlink_seq_show, |
1694 | }; | 1693 | }; |
1695 | 1694 | ||
1696 | 1695 | ||
1697 | static int netlink_seq_open(struct inode *inode, struct file *file) | 1696 | static int netlink_seq_open(struct inode *inode, struct file *file) |
1698 | { | 1697 | { |
1699 | struct seq_file *seq; | 1698 | struct seq_file *seq; |
1700 | struct nl_seq_iter *iter; | 1699 | struct nl_seq_iter *iter; |
1701 | int err; | 1700 | int err; |
1702 | 1701 | ||
1703 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 1702 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); |
1704 | if (!iter) | 1703 | if (!iter) |
1705 | return -ENOMEM; | 1704 | return -ENOMEM; |
1706 | 1705 | ||
1707 | err = seq_open(file, &netlink_seq_ops); | 1706 | err = seq_open(file, &netlink_seq_ops); |
1708 | if (err) { | 1707 | if (err) { |
1709 | kfree(iter); | 1708 | kfree(iter); |
1710 | return err; | 1709 | return err; |
1711 | } | 1710 | } |
1712 | 1711 | ||
1713 | seq = file->private_data; | 1712 | seq = file->private_data; |
1714 | seq->private = iter; | 1713 | seq->private = iter; |
1715 | return 0; | 1714 | return 0; |
1716 | } | 1715 | } |
1717 | 1716 | ||
1718 | static struct file_operations netlink_seq_fops = { | 1717 | static struct file_operations netlink_seq_fops = { |
1719 | .owner = THIS_MODULE, | 1718 | .owner = THIS_MODULE, |
1720 | .open = netlink_seq_open, | 1719 | .open = netlink_seq_open, |
1721 | .read = seq_read, | 1720 | .read = seq_read, |
1722 | .llseek = seq_lseek, | 1721 | .llseek = seq_lseek, |
1723 | .release = seq_release_private, | 1722 | .release = seq_release_private, |
1724 | }; | 1723 | }; |
1725 | 1724 | ||
1726 | #endif | 1725 | #endif |
1727 | 1726 | ||
1728 | int netlink_register_notifier(struct notifier_block *nb) | 1727 | int netlink_register_notifier(struct notifier_block *nb) |
1729 | { | 1728 | { |
1730 | return atomic_notifier_chain_register(&netlink_chain, nb); | 1729 | return atomic_notifier_chain_register(&netlink_chain, nb); |
1731 | } | 1730 | } |
1732 | 1731 | ||
1733 | int netlink_unregister_notifier(struct notifier_block *nb) | 1732 | int netlink_unregister_notifier(struct notifier_block *nb) |
1734 | { | 1733 | { |
1735 | return atomic_notifier_chain_unregister(&netlink_chain, nb); | 1734 | return atomic_notifier_chain_unregister(&netlink_chain, nb); |
1736 | } | 1735 | } |
1737 | 1736 | ||
1738 | static const struct proto_ops netlink_ops = { | 1737 | static const struct proto_ops netlink_ops = { |
1739 | .family = PF_NETLINK, | 1738 | .family = PF_NETLINK, |
1740 | .owner = THIS_MODULE, | 1739 | .owner = THIS_MODULE, |
1741 | .release = netlink_release, | 1740 | .release = netlink_release, |
1742 | .bind = netlink_bind, | 1741 | .bind = netlink_bind, |
1743 | .connect = netlink_connect, | 1742 | .connect = netlink_connect, |
1744 | .socketpair = sock_no_socketpair, | 1743 | .socketpair = sock_no_socketpair, |
1745 | .accept = sock_no_accept, | 1744 | .accept = sock_no_accept, |
1746 | .getname = netlink_getname, | 1745 | .getname = netlink_getname, |
1747 | .poll = datagram_poll, | 1746 | .poll = datagram_poll, |
1748 | .ioctl = sock_no_ioctl, | 1747 | .ioctl = sock_no_ioctl, |
1749 | .listen = sock_no_listen, | 1748 | .listen = sock_no_listen, |
1750 | .shutdown = sock_no_shutdown, | 1749 | .shutdown = sock_no_shutdown, |
1751 | .setsockopt = netlink_setsockopt, | 1750 | .setsockopt = netlink_setsockopt, |
1752 | .getsockopt = netlink_getsockopt, | 1751 | .getsockopt = netlink_getsockopt, |
1753 | .sendmsg = netlink_sendmsg, | 1752 | .sendmsg = netlink_sendmsg, |
1754 | .recvmsg = netlink_recvmsg, | 1753 | .recvmsg = netlink_recvmsg, |
1755 | .mmap = sock_no_mmap, | 1754 | .mmap = sock_no_mmap, |
1756 | .sendpage = sock_no_sendpage, | 1755 | .sendpage = sock_no_sendpage, |
1757 | }; | 1756 | }; |
1758 | 1757 | ||
1759 | static struct net_proto_family netlink_family_ops = { | 1758 | static struct net_proto_family netlink_family_ops = { |
1760 | .family = PF_NETLINK, | 1759 | .family = PF_NETLINK, |
1761 | .create = netlink_create, | 1760 | .create = netlink_create, |
1762 | .owner = THIS_MODULE, /* for consistency 8) */ | 1761 | .owner = THIS_MODULE, /* for consistency 8) */ |
1763 | }; | 1762 | }; |
1764 | 1763 | ||
1765 | static int __init netlink_proto_init(void) | 1764 | static int __init netlink_proto_init(void) |
1766 | { | 1765 | { |
1767 | struct sk_buff *dummy_skb; | 1766 | struct sk_buff *dummy_skb; |
1768 | int i; | 1767 | int i; |
1769 | unsigned long max; | 1768 | unsigned long max; |
1770 | unsigned int order; | 1769 | unsigned int order; |
1771 | int err = proto_register(&netlink_proto, 0); | 1770 | int err = proto_register(&netlink_proto, 0); |
1772 | 1771 | ||
1773 | if (err != 0) | 1772 | if (err != 0) |
1774 | goto out; | 1773 | goto out; |
1775 | 1774 | ||
1776 | BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); | 1775 | BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); |
1777 | 1776 | ||
1778 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); | 1777 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
1779 | if (!nl_table) | 1778 | if (!nl_table) |
1780 | goto panic; | 1779 | goto panic; |
1781 | 1780 | ||
1782 | if (num_physpages >= (128 * 1024)) | 1781 | if (num_physpages >= (128 * 1024)) |
1783 | max = num_physpages >> (21 - PAGE_SHIFT); | 1782 | max = num_physpages >> (21 - PAGE_SHIFT); |
1784 | else | 1783 | else |
1785 | max = num_physpages >> (23 - PAGE_SHIFT); | 1784 | max = num_physpages >> (23 - PAGE_SHIFT); |
1786 | 1785 | ||
1787 | order = get_bitmask_order(max) - 1 + PAGE_SHIFT; | 1786 | order = get_bitmask_order(max) - 1 + PAGE_SHIFT; |
1788 | max = (1UL << order) / sizeof(struct hlist_head); | 1787 | max = (1UL << order) / sizeof(struct hlist_head); |
1789 | order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1; | 1788 | order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1; |
1790 | 1789 | ||
1791 | for (i = 0; i < MAX_LINKS; i++) { | 1790 | for (i = 0; i < MAX_LINKS; i++) { |
1792 | struct nl_pid_hash *hash = &nl_table[i].hash; | 1791 | struct nl_pid_hash *hash = &nl_table[i].hash; |
1793 | 1792 | ||
1794 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); | 1793 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); |
1795 | if (!hash->table) { | 1794 | if (!hash->table) { |
1796 | while (i-- > 0) | 1795 | while (i-- > 0) |
1797 | nl_pid_hash_free(nl_table[i].hash.table, | 1796 | nl_pid_hash_free(nl_table[i].hash.table, |
1798 | 1 * sizeof(*hash->table)); | 1797 | 1 * sizeof(*hash->table)); |
1799 | kfree(nl_table); | 1798 | kfree(nl_table); |
1800 | goto panic; | 1799 | goto panic; |
1801 | } | 1800 | } |
1802 | memset(hash->table, 0, 1 * sizeof(*hash->table)); | 1801 | memset(hash->table, 0, 1 * sizeof(*hash->table)); |
1803 | hash->max_shift = order; | 1802 | hash->max_shift = order; |
1804 | hash->shift = 0; | 1803 | hash->shift = 0; |
1805 | hash->mask = 0; | 1804 | hash->mask = 0; |
1806 | hash->rehash_time = jiffies; | 1805 | hash->rehash_time = jiffies; |
1807 | } | 1806 | } |
1808 | 1807 | ||
1809 | sock_register(&netlink_family_ops); | 1808 | sock_register(&netlink_family_ops); |
1810 | #ifdef CONFIG_PROC_FS | 1809 | #ifdef CONFIG_PROC_FS |
1811 | proc_net_fops_create("netlink", 0, &netlink_seq_fops); | 1810 | proc_net_fops_create("netlink", 0, &netlink_seq_fops); |
1812 | #endif | 1811 | #endif |
1813 | /* The netlink device handler may be needed early. */ | 1812 | /* The netlink device handler may be needed early. */ |
1814 | rtnetlink_init(); | 1813 | rtnetlink_init(); |
1815 | out: | 1814 | out: |
1816 | return err; | 1815 | return err; |
1817 | panic: | 1816 | panic: |
1818 | panic("netlink_init: Cannot allocate nl_table\n"); | 1817 | panic("netlink_init: Cannot allocate nl_table\n"); |
1819 | } | 1818 | } |
1820 | 1819 | ||
1821 | core_initcall(netlink_proto_init); | 1820 | core_initcall(netlink_proto_init); |
1822 | 1821 | ||
1823 | EXPORT_SYMBOL(netlink_ack); | 1822 | EXPORT_SYMBOL(netlink_ack); |
1824 | EXPORT_SYMBOL(netlink_run_queue); | 1823 | EXPORT_SYMBOL(netlink_run_queue); |
1825 | EXPORT_SYMBOL(netlink_queue_skip); | 1824 | EXPORT_SYMBOL(netlink_queue_skip); |
1826 | EXPORT_SYMBOL(netlink_broadcast); | 1825 | EXPORT_SYMBOL(netlink_broadcast); |
1827 | EXPORT_SYMBOL(netlink_dump_start); | 1826 | EXPORT_SYMBOL(netlink_dump_start); |
1828 | EXPORT_SYMBOL(netlink_kernel_create); | 1827 | EXPORT_SYMBOL(netlink_kernel_create); |
1829 | EXPORT_SYMBOL(netlink_register_notifier); | 1828 | EXPORT_SYMBOL(netlink_register_notifier); |
1830 | EXPORT_SYMBOL(netlink_set_err); | 1829 | EXPORT_SYMBOL(netlink_set_err); |
1831 | EXPORT_SYMBOL(netlink_set_nonroot); | 1830 | EXPORT_SYMBOL(netlink_set_nonroot); |
1832 | EXPORT_SYMBOL(netlink_unicast); | 1831 | EXPORT_SYMBOL(netlink_unicast); |
1833 | EXPORT_SYMBOL(netlink_unregister_notifier); | 1832 | EXPORT_SYMBOL(netlink_unregister_notifier); |
1834 | EXPORT_SYMBOL(nlmsg_notify); | 1833 | EXPORT_SYMBOL(nlmsg_notify); |
1835 | 1834 |
net/xfrm/xfrm_user.c
1 | /* xfrm_user.c: User interface to configure xfrm engine. | 1 | /* xfrm_user.c: User interface to configure xfrm engine. |
2 | * | 2 | * |
3 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) |
4 | * | 4 | * |
5 | * Changes: | 5 | * Changes: |
6 | * Mitsuru KANDA @USAGI | 6 | * Mitsuru KANDA @USAGI |
7 | * Kazunori MIYAZAWA @USAGI | 7 | * Kazunori MIYAZAWA @USAGI |
8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
9 | * IPv6 support | 9 | * IPv6 support |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/crypto.h> | 13 | #include <linux/crypto.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/socket.h> | 18 | #include <linux/socket.h> |
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/net.h> | 20 | #include <linux/net.h> |
21 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/pfkeyv2.h> | 23 | #include <linux/pfkeyv2.h> |
24 | #include <linux/ipsec.h> | 24 | #include <linux/ipsec.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/security.h> | 26 | #include <linux/security.h> |
27 | #include <net/sock.h> | 27 | #include <net/sock.h> |
28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
29 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
32 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 35 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
36 | { | 36 | { |
37 | struct rtattr *rt = xfrma[type - 1]; | 37 | struct rtattr *rt = xfrma[type - 1]; |
38 | struct xfrm_algo *algp; | 38 | struct xfrm_algo *algp; |
39 | int len; | 39 | int len; |
40 | 40 | ||
41 | if (!rt) | 41 | if (!rt) |
42 | return 0; | 42 | return 0; |
43 | 43 | ||
44 | len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp); | 44 | len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp); |
45 | if (len < 0) | 45 | if (len < 0) |
46 | return -EINVAL; | 46 | return -EINVAL; |
47 | 47 | ||
48 | algp = RTA_DATA(rt); | 48 | algp = RTA_DATA(rt); |
49 | 49 | ||
50 | len -= (algp->alg_key_len + 7U) / 8; | 50 | len -= (algp->alg_key_len + 7U) / 8; |
51 | if (len < 0) | 51 | if (len < 0) |
52 | return -EINVAL; | 52 | return -EINVAL; |
53 | 53 | ||
54 | switch (type) { | 54 | switch (type) { |
55 | case XFRMA_ALG_AUTH: | 55 | case XFRMA_ALG_AUTH: |
56 | if (!algp->alg_key_len && | 56 | if (!algp->alg_key_len && |
57 | strcmp(algp->alg_name, "digest_null") != 0) | 57 | strcmp(algp->alg_name, "digest_null") != 0) |
58 | return -EINVAL; | 58 | return -EINVAL; |
59 | break; | 59 | break; |
60 | 60 | ||
61 | case XFRMA_ALG_CRYPT: | 61 | case XFRMA_ALG_CRYPT: |
62 | if (!algp->alg_key_len && | 62 | if (!algp->alg_key_len && |
63 | strcmp(algp->alg_name, "cipher_null") != 0) | 63 | strcmp(algp->alg_name, "cipher_null") != 0) |
64 | return -EINVAL; | 64 | return -EINVAL; |
65 | break; | 65 | break; |
66 | 66 | ||
67 | case XFRMA_ALG_COMP: | 67 | case XFRMA_ALG_COMP: |
68 | /* Zero length keys are legal. */ | 68 | /* Zero length keys are legal. */ |
69 | break; | 69 | break; |
70 | 70 | ||
71 | default: | 71 | default: |
72 | return -EINVAL; | 72 | return -EINVAL; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; | 75 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; |
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | static int verify_encap_tmpl(struct rtattr **xfrma) | 79 | static int verify_encap_tmpl(struct rtattr **xfrma) |
80 | { | 80 | { |
81 | struct rtattr *rt = xfrma[XFRMA_ENCAP - 1]; | 81 | struct rtattr *rt = xfrma[XFRMA_ENCAP - 1]; |
82 | struct xfrm_encap_tmpl *encap; | 82 | struct xfrm_encap_tmpl *encap; |
83 | 83 | ||
84 | if (!rt) | 84 | if (!rt) |
85 | return 0; | 85 | return 0; |
86 | 86 | ||
87 | if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap)) | 87 | if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap)) |
88 | return -EINVAL; | 88 | return -EINVAL; |
89 | 89 | ||
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, | 93 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, |
94 | xfrm_address_t **addrp) | 94 | xfrm_address_t **addrp) |
95 | { | 95 | { |
96 | struct rtattr *rt = xfrma[type - 1]; | 96 | struct rtattr *rt = xfrma[type - 1]; |
97 | 97 | ||
98 | if (!rt) | 98 | if (!rt) |
99 | return 0; | 99 | return 0; |
100 | 100 | ||
101 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) | 101 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) |
102 | return -EINVAL; | 102 | return -EINVAL; |
103 | 103 | ||
104 | if (addrp) | 104 | if (addrp) |
105 | *addrp = RTA_DATA(rt); | 105 | *addrp = RTA_DATA(rt); |
106 | 106 | ||
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
111 | { | 111 | { |
112 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; | 112 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; |
113 | struct xfrm_user_sec_ctx *uctx; | 113 | struct xfrm_user_sec_ctx *uctx; |
114 | int len = 0; | 114 | int len = 0; |
115 | 115 | ||
116 | if (!rt) | 116 | if (!rt) |
117 | return 0; | 117 | return 0; |
118 | 118 | ||
119 | if (rt->rta_len < sizeof(*uctx)) | 119 | if (rt->rta_len < sizeof(*uctx)) |
120 | return -EINVAL; | 120 | return -EINVAL; |
121 | 121 | ||
122 | uctx = RTA_DATA(rt); | 122 | uctx = RTA_DATA(rt); |
123 | 123 | ||
124 | len += sizeof(struct xfrm_user_sec_ctx); | 124 | len += sizeof(struct xfrm_user_sec_ctx); |
125 | len += uctx->ctx_len; | 125 | len += uctx->ctx_len; |
126 | 126 | ||
127 | if (uctx->len != len) | 127 | if (uctx->len != len) |
128 | return -EINVAL; | 128 | return -EINVAL; |
129 | 129 | ||
130 | return 0; | 130 | return 0; |
131 | } | 131 | } |
132 | 132 | ||
133 | 133 | ||
134 | static int verify_newsa_info(struct xfrm_usersa_info *p, | 134 | static int verify_newsa_info(struct xfrm_usersa_info *p, |
135 | struct rtattr **xfrma) | 135 | struct rtattr **xfrma) |
136 | { | 136 | { |
137 | int err; | 137 | int err; |
138 | 138 | ||
139 | err = -EINVAL; | 139 | err = -EINVAL; |
140 | switch (p->family) { | 140 | switch (p->family) { |
141 | case AF_INET: | 141 | case AF_INET: |
142 | break; | 142 | break; |
143 | 143 | ||
144 | case AF_INET6: | 144 | case AF_INET6: |
145 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 145 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
146 | break; | 146 | break; |
147 | #else | 147 | #else |
148 | err = -EAFNOSUPPORT; | 148 | err = -EAFNOSUPPORT; |
149 | goto out; | 149 | goto out; |
150 | #endif | 150 | #endif |
151 | 151 | ||
152 | default: | 152 | default: |
153 | goto out; | 153 | goto out; |
154 | }; | 154 | }; |
155 | 155 | ||
156 | err = -EINVAL; | 156 | err = -EINVAL; |
157 | switch (p->id.proto) { | 157 | switch (p->id.proto) { |
158 | case IPPROTO_AH: | 158 | case IPPROTO_AH: |
159 | if (!xfrma[XFRMA_ALG_AUTH-1] || | 159 | if (!xfrma[XFRMA_ALG_AUTH-1] || |
160 | xfrma[XFRMA_ALG_CRYPT-1] || | 160 | xfrma[XFRMA_ALG_CRYPT-1] || |
161 | xfrma[XFRMA_ALG_COMP-1]) | 161 | xfrma[XFRMA_ALG_COMP-1]) |
162 | goto out; | 162 | goto out; |
163 | break; | 163 | break; |
164 | 164 | ||
165 | case IPPROTO_ESP: | 165 | case IPPROTO_ESP: |
166 | if ((!xfrma[XFRMA_ALG_AUTH-1] && | 166 | if ((!xfrma[XFRMA_ALG_AUTH-1] && |
167 | !xfrma[XFRMA_ALG_CRYPT-1]) || | 167 | !xfrma[XFRMA_ALG_CRYPT-1]) || |
168 | xfrma[XFRMA_ALG_COMP-1]) | 168 | xfrma[XFRMA_ALG_COMP-1]) |
169 | goto out; | 169 | goto out; |
170 | break; | 170 | break; |
171 | 171 | ||
172 | case IPPROTO_COMP: | 172 | case IPPROTO_COMP: |
173 | if (!xfrma[XFRMA_ALG_COMP-1] || | 173 | if (!xfrma[XFRMA_ALG_COMP-1] || |
174 | xfrma[XFRMA_ALG_AUTH-1] || | 174 | xfrma[XFRMA_ALG_AUTH-1] || |
175 | xfrma[XFRMA_ALG_CRYPT-1]) | 175 | xfrma[XFRMA_ALG_CRYPT-1]) |
176 | goto out; | 176 | goto out; |
177 | break; | 177 | break; |
178 | 178 | ||
179 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 179 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
180 | case IPPROTO_DSTOPTS: | 180 | case IPPROTO_DSTOPTS: |
181 | case IPPROTO_ROUTING: | 181 | case IPPROTO_ROUTING: |
182 | if (xfrma[XFRMA_ALG_COMP-1] || | 182 | if (xfrma[XFRMA_ALG_COMP-1] || |
183 | xfrma[XFRMA_ALG_AUTH-1] || | 183 | xfrma[XFRMA_ALG_AUTH-1] || |
184 | xfrma[XFRMA_ALG_CRYPT-1] || | 184 | xfrma[XFRMA_ALG_CRYPT-1] || |
185 | xfrma[XFRMA_ENCAP-1] || | 185 | xfrma[XFRMA_ENCAP-1] || |
186 | xfrma[XFRMA_SEC_CTX-1] || | 186 | xfrma[XFRMA_SEC_CTX-1] || |
187 | !xfrma[XFRMA_COADDR-1]) | 187 | !xfrma[XFRMA_COADDR-1]) |
188 | goto out; | 188 | goto out; |
189 | break; | 189 | break; |
190 | #endif | 190 | #endif |
191 | 191 | ||
192 | default: | 192 | default: |
193 | goto out; | 193 | goto out; |
194 | }; | 194 | }; |
195 | 195 | ||
196 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH))) | 196 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH))) |
197 | goto out; | 197 | goto out; |
198 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT))) | 198 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT))) |
199 | goto out; | 199 | goto out; |
200 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP))) | 200 | if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP))) |
201 | goto out; | 201 | goto out; |
202 | if ((err = verify_encap_tmpl(xfrma))) | 202 | if ((err = verify_encap_tmpl(xfrma))) |
203 | goto out; | 203 | goto out; |
204 | if ((err = verify_sec_ctx_len(xfrma))) | 204 | if ((err = verify_sec_ctx_len(xfrma))) |
205 | goto out; | 205 | goto out; |
206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) | 206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) |
207 | goto out; | 207 | goto out; |
208 | 208 | ||
209 | err = -EINVAL; | 209 | err = -EINVAL; |
210 | switch (p->mode) { | 210 | switch (p->mode) { |
211 | case XFRM_MODE_TRANSPORT: | 211 | case XFRM_MODE_TRANSPORT: |
212 | case XFRM_MODE_TUNNEL: | 212 | case XFRM_MODE_TUNNEL: |
213 | case XFRM_MODE_ROUTEOPTIMIZATION: | 213 | case XFRM_MODE_ROUTEOPTIMIZATION: |
214 | case XFRM_MODE_BEET: | 214 | case XFRM_MODE_BEET: |
215 | break; | 215 | break; |
216 | 216 | ||
217 | default: | 217 | default: |
218 | goto out; | 218 | goto out; |
219 | }; | 219 | }; |
220 | 220 | ||
221 | err = 0; | 221 | err = 0; |
222 | 222 | ||
223 | out: | 223 | out: |
224 | return err; | 224 | return err; |
225 | } | 225 | } |
226 | 226 | ||
227 | static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | 227 | static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, |
228 | struct xfrm_algo_desc *(*get_byname)(char *, int), | 228 | struct xfrm_algo_desc *(*get_byname)(char *, int), |
229 | struct rtattr *u_arg) | 229 | struct rtattr *u_arg) |
230 | { | 230 | { |
231 | struct rtattr *rta = u_arg; | 231 | struct rtattr *rta = u_arg; |
232 | struct xfrm_algo *p, *ualg; | 232 | struct xfrm_algo *p, *ualg; |
233 | struct xfrm_algo_desc *algo; | 233 | struct xfrm_algo_desc *algo; |
234 | int len; | 234 | int len; |
235 | 235 | ||
236 | if (!rta) | 236 | if (!rta) |
237 | return 0; | 237 | return 0; |
238 | 238 | ||
239 | ualg = RTA_DATA(rta); | 239 | ualg = RTA_DATA(rta); |
240 | 240 | ||
241 | algo = get_byname(ualg->alg_name, 1); | 241 | algo = get_byname(ualg->alg_name, 1); |
242 | if (!algo) | 242 | if (!algo) |
243 | return -ENOSYS; | 243 | return -ENOSYS; |
244 | *props = algo->desc.sadb_alg_id; | 244 | *props = algo->desc.sadb_alg_id; |
245 | 245 | ||
246 | len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8; | 246 | len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8; |
247 | p = kmemdup(ualg, len, GFP_KERNEL); | 247 | p = kmemdup(ualg, len, GFP_KERNEL); |
248 | if (!p) | 248 | if (!p) |
249 | return -ENOMEM; | 249 | return -ENOMEM; |
250 | 250 | ||
251 | strcpy(p->alg_name, algo->name); | 251 | strcpy(p->alg_name, algo->name); |
252 | *algpp = p; | 252 | *algpp = p; |
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_arg) | 256 | static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_arg) |
257 | { | 257 | { |
258 | struct rtattr *rta = u_arg; | 258 | struct rtattr *rta = u_arg; |
259 | struct xfrm_encap_tmpl *p, *uencap; | 259 | struct xfrm_encap_tmpl *p, *uencap; |
260 | 260 | ||
261 | if (!rta) | 261 | if (!rta) |
262 | return 0; | 262 | return 0; |
263 | 263 | ||
264 | uencap = RTA_DATA(rta); | 264 | uencap = RTA_DATA(rta); |
265 | p = kmemdup(uencap, sizeof(*p), GFP_KERNEL); | 265 | p = kmemdup(uencap, sizeof(*p), GFP_KERNEL); |
266 | if (!p) | 266 | if (!p) |
267 | return -ENOMEM; | 267 | return -ENOMEM; |
268 | 268 | ||
269 | *encapp = p; | 269 | *encapp = p; |
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | 272 | ||
273 | 273 | ||
274 | static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) | 274 | static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) |
275 | { | 275 | { |
276 | struct xfrm_sec_ctx *xfrm_ctx = xp->security; | 276 | struct xfrm_sec_ctx *xfrm_ctx = xp->security; |
277 | int len = 0; | 277 | int len = 0; |
278 | 278 | ||
279 | if (xfrm_ctx) { | 279 | if (xfrm_ctx) { |
280 | len += sizeof(struct xfrm_user_sec_ctx); | 280 | len += sizeof(struct xfrm_user_sec_ctx); |
281 | len += xfrm_ctx->ctx_len; | 281 | len += xfrm_ctx->ctx_len; |
282 | } | 282 | } |
283 | return len; | 283 | return len; |
284 | } | 284 | } |
285 | 285 | ||
286 | static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | 286 | static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) |
287 | { | 287 | { |
288 | struct xfrm_user_sec_ctx *uctx; | 288 | struct xfrm_user_sec_ctx *uctx; |
289 | 289 | ||
290 | if (!u_arg) | 290 | if (!u_arg) |
291 | return 0; | 291 | return 0; |
292 | 292 | ||
293 | uctx = RTA_DATA(u_arg); | 293 | uctx = RTA_DATA(u_arg); |
294 | return security_xfrm_state_alloc(x, uctx); | 294 | return security_xfrm_state_alloc(x, uctx); |
295 | } | 295 | } |
296 | 296 | ||
297 | static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) | 297 | static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) |
298 | { | 298 | { |
299 | struct rtattr *rta = u_arg; | 299 | struct rtattr *rta = u_arg; |
300 | xfrm_address_t *p, *uaddrp; | 300 | xfrm_address_t *p, *uaddrp; |
301 | 301 | ||
302 | if (!rta) | 302 | if (!rta) |
303 | return 0; | 303 | return 0; |
304 | 304 | ||
305 | uaddrp = RTA_DATA(rta); | 305 | uaddrp = RTA_DATA(rta); |
306 | p = kmemdup(uaddrp, sizeof(*p), GFP_KERNEL); | 306 | p = kmemdup(uaddrp, sizeof(*p), GFP_KERNEL); |
307 | if (!p) | 307 | if (!p) |
308 | return -ENOMEM; | 308 | return -ENOMEM; |
309 | 309 | ||
310 | *addrpp = p; | 310 | *addrpp = p; |
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 314 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
315 | { | 315 | { |
316 | memcpy(&x->id, &p->id, sizeof(x->id)); | 316 | memcpy(&x->id, &p->id, sizeof(x->id)); |
317 | memcpy(&x->sel, &p->sel, sizeof(x->sel)); | 317 | memcpy(&x->sel, &p->sel, sizeof(x->sel)); |
318 | memcpy(&x->lft, &p->lft, sizeof(x->lft)); | 318 | memcpy(&x->lft, &p->lft, sizeof(x->lft)); |
319 | x->props.mode = p->mode; | 319 | x->props.mode = p->mode; |
320 | x->props.replay_window = p->replay_window; | 320 | x->props.replay_window = p->replay_window; |
321 | x->props.reqid = p->reqid; | 321 | x->props.reqid = p->reqid; |
322 | x->props.family = p->family; | 322 | x->props.family = p->family; |
323 | memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); | 323 | memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); |
324 | x->props.flags = p->flags; | 324 | x->props.flags = p->flags; |
325 | } | 325 | } |
326 | 326 | ||
327 | /* | 327 | /* |
328 | * someday when pfkey also has support, we could have the code | 328 | * someday when pfkey also has support, we could have the code |
329 | * somehow made shareable and move it to xfrm_state.c - JHS | 329 | * somehow made shareable and move it to xfrm_state.c - JHS |
330 | * | 330 | * |
331 | */ | 331 | */ |
332 | static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) | 332 | static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) |
333 | { | 333 | { |
334 | int err = - EINVAL; | 334 | int err = - EINVAL; |
335 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | 335 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; |
336 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | 336 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; |
337 | struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; | 337 | struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; |
338 | struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; | 338 | struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; |
339 | 339 | ||
340 | if (rp) { | 340 | if (rp) { |
341 | struct xfrm_replay_state *replay; | 341 | struct xfrm_replay_state *replay; |
342 | if (RTA_PAYLOAD(rp) < sizeof(*replay)) | 342 | if (RTA_PAYLOAD(rp) < sizeof(*replay)) |
343 | goto error; | 343 | goto error; |
344 | replay = RTA_DATA(rp); | 344 | replay = RTA_DATA(rp); |
345 | memcpy(&x->replay, replay, sizeof(*replay)); | 345 | memcpy(&x->replay, replay, sizeof(*replay)); |
346 | memcpy(&x->preplay, replay, sizeof(*replay)); | 346 | memcpy(&x->preplay, replay, sizeof(*replay)); |
347 | } | 347 | } |
348 | 348 | ||
349 | if (lt) { | 349 | if (lt) { |
350 | struct xfrm_lifetime_cur *ltime; | 350 | struct xfrm_lifetime_cur *ltime; |
351 | if (RTA_PAYLOAD(lt) < sizeof(*ltime)) | 351 | if (RTA_PAYLOAD(lt) < sizeof(*ltime)) |
352 | goto error; | 352 | goto error; |
353 | ltime = RTA_DATA(lt); | 353 | ltime = RTA_DATA(lt); |
354 | x->curlft.bytes = ltime->bytes; | 354 | x->curlft.bytes = ltime->bytes; |
355 | x->curlft.packets = ltime->packets; | 355 | x->curlft.packets = ltime->packets; |
356 | x->curlft.add_time = ltime->add_time; | 356 | x->curlft.add_time = ltime->add_time; |
357 | x->curlft.use_time = ltime->use_time; | 357 | x->curlft.use_time = ltime->use_time; |
358 | } | 358 | } |
359 | 359 | ||
360 | if (et) { | 360 | if (et) { |
361 | if (RTA_PAYLOAD(et) < sizeof(u32)) | 361 | if (RTA_PAYLOAD(et) < sizeof(u32)) |
362 | goto error; | 362 | goto error; |
363 | x->replay_maxage = *(u32*)RTA_DATA(et); | 363 | x->replay_maxage = *(u32*)RTA_DATA(et); |
364 | } | 364 | } |
365 | 365 | ||
366 | if (rt) { | 366 | if (rt) { |
367 | if (RTA_PAYLOAD(rt) < sizeof(u32)) | 367 | if (RTA_PAYLOAD(rt) < sizeof(u32)) |
368 | goto error; | 368 | goto error; |
369 | x->replay_maxdiff = *(u32*)RTA_DATA(rt); | 369 | x->replay_maxdiff = *(u32*)RTA_DATA(rt); |
370 | } | 370 | } |
371 | 371 | ||
372 | return 0; | 372 | return 0; |
373 | error: | 373 | error: |
374 | return err; | 374 | return err; |
375 | } | 375 | } |
376 | 376 | ||
377 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | 377 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, |
378 | struct rtattr **xfrma, | 378 | struct rtattr **xfrma, |
379 | int *errp) | 379 | int *errp) |
380 | { | 380 | { |
381 | struct xfrm_state *x = xfrm_state_alloc(); | 381 | struct xfrm_state *x = xfrm_state_alloc(); |
382 | int err = -ENOMEM; | 382 | int err = -ENOMEM; |
383 | 383 | ||
384 | if (!x) | 384 | if (!x) |
385 | goto error_no_put; | 385 | goto error_no_put; |
386 | 386 | ||
387 | copy_from_user_state(x, p); | 387 | copy_from_user_state(x, p); |
388 | 388 | ||
389 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, | 389 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, |
390 | xfrm_aalg_get_byname, | 390 | xfrm_aalg_get_byname, |
391 | xfrma[XFRMA_ALG_AUTH-1]))) | 391 | xfrma[XFRMA_ALG_AUTH-1]))) |
392 | goto error; | 392 | goto error; |
393 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, | 393 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, |
394 | xfrm_ealg_get_byname, | 394 | xfrm_ealg_get_byname, |
395 | xfrma[XFRMA_ALG_CRYPT-1]))) | 395 | xfrma[XFRMA_ALG_CRYPT-1]))) |
396 | goto error; | 396 | goto error; |
397 | if ((err = attach_one_algo(&x->calg, &x->props.calgo, | 397 | if ((err = attach_one_algo(&x->calg, &x->props.calgo, |
398 | xfrm_calg_get_byname, | 398 | xfrm_calg_get_byname, |
399 | xfrma[XFRMA_ALG_COMP-1]))) | 399 | xfrma[XFRMA_ALG_COMP-1]))) |
400 | goto error; | 400 | goto error; |
401 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) | 401 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) |
402 | goto error; | 402 | goto error; |
403 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) | 403 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) |
404 | goto error; | 404 | goto error; |
405 | err = xfrm_init_state(x); | 405 | err = xfrm_init_state(x); |
406 | if (err) | 406 | if (err) |
407 | goto error; | 407 | goto error; |
408 | 408 | ||
409 | if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) | 409 | if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) |
410 | goto error; | 410 | goto error; |
411 | 411 | ||
412 | x->km.seq = p->seq; | 412 | x->km.seq = p->seq; |
413 | x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; | 413 | x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; |
414 | /* sysctl_xfrm_aevent_etime is in 100ms units */ | 414 | /* sysctl_xfrm_aevent_etime is in 100ms units */ |
415 | x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; | 415 | x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; |
416 | x->preplay.bitmap = 0; | 416 | x->preplay.bitmap = 0; |
417 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; | 417 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; |
418 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; | 418 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; |
419 | 419 | ||
420 | /* override default values from above */ | 420 | /* override default values from above */ |
421 | 421 | ||
422 | err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); | 422 | err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); |
423 | if (err < 0) | 423 | if (err < 0) |
424 | goto error; | 424 | goto error; |
425 | 425 | ||
426 | return x; | 426 | return x; |
427 | 427 | ||
428 | error: | 428 | error: |
429 | x->km.state = XFRM_STATE_DEAD; | 429 | x->km.state = XFRM_STATE_DEAD; |
430 | xfrm_state_put(x); | 430 | xfrm_state_put(x); |
431 | error_no_put: | 431 | error_no_put: |
432 | *errp = err; | 432 | *errp = err; |
433 | return NULL; | 433 | return NULL; |
434 | } | 434 | } |
435 | 435 | ||
436 | static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 436 | static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
437 | { | 437 | { |
438 | struct xfrm_usersa_info *p = NLMSG_DATA(nlh); | 438 | struct xfrm_usersa_info *p = NLMSG_DATA(nlh); |
439 | struct xfrm_state *x; | 439 | struct xfrm_state *x; |
440 | int err; | 440 | int err; |
441 | struct km_event c; | 441 | struct km_event c; |
442 | 442 | ||
443 | err = verify_newsa_info(p, (struct rtattr **)xfrma); | 443 | err = verify_newsa_info(p, (struct rtattr **)xfrma); |
444 | if (err) | 444 | if (err) |
445 | return err; | 445 | return err; |
446 | 446 | ||
447 | x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err); | 447 | x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err); |
448 | if (!x) | 448 | if (!x) |
449 | return err; | 449 | return err; |
450 | 450 | ||
451 | xfrm_state_hold(x); | 451 | xfrm_state_hold(x); |
452 | if (nlh->nlmsg_type == XFRM_MSG_NEWSA) | 452 | if (nlh->nlmsg_type == XFRM_MSG_NEWSA) |
453 | err = xfrm_state_add(x); | 453 | err = xfrm_state_add(x); |
454 | else | 454 | else |
455 | err = xfrm_state_update(x); | 455 | err = xfrm_state_update(x); |
456 | 456 | ||
457 | if (err < 0) { | 457 | if (err < 0) { |
458 | x->km.state = XFRM_STATE_DEAD; | 458 | x->km.state = XFRM_STATE_DEAD; |
459 | __xfrm_state_put(x); | 459 | __xfrm_state_put(x); |
460 | goto out; | 460 | goto out; |
461 | } | 461 | } |
462 | 462 | ||
463 | c.seq = nlh->nlmsg_seq; | 463 | c.seq = nlh->nlmsg_seq; |
464 | c.pid = nlh->nlmsg_pid; | 464 | c.pid = nlh->nlmsg_pid; |
465 | c.event = nlh->nlmsg_type; | 465 | c.event = nlh->nlmsg_type; |
466 | 466 | ||
467 | km_state_notify(x, &c); | 467 | km_state_notify(x, &c); |
468 | out: | 468 | out: |
469 | xfrm_state_put(x); | 469 | xfrm_state_put(x); |
470 | return err; | 470 | return err; |
471 | } | 471 | } |
472 | 472 | ||
473 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, | 473 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, |
474 | struct rtattr **xfrma, | 474 | struct rtattr **xfrma, |
475 | int *errp) | 475 | int *errp) |
476 | { | 476 | { |
477 | struct xfrm_state *x = NULL; | 477 | struct xfrm_state *x = NULL; |
478 | int err; | 478 | int err; |
479 | 479 | ||
480 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | 480 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { |
481 | err = -ESRCH; | 481 | err = -ESRCH; |
482 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 482 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); |
483 | } else { | 483 | } else { |
484 | xfrm_address_t *saddr = NULL; | 484 | xfrm_address_t *saddr = NULL; |
485 | 485 | ||
486 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); | 486 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); |
487 | if (err) | 487 | if (err) |
488 | goto out; | 488 | goto out; |
489 | 489 | ||
490 | if (!saddr) { | 490 | if (!saddr) { |
491 | err = -EINVAL; | 491 | err = -EINVAL; |
492 | goto out; | 492 | goto out; |
493 | } | 493 | } |
494 | 494 | ||
495 | err = -ESRCH; | 495 | err = -ESRCH; |
496 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, | 496 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, |
497 | p->family); | 497 | p->family); |
498 | } | 498 | } |
499 | 499 | ||
500 | out: | 500 | out: |
501 | if (!x && errp) | 501 | if (!x && errp) |
502 | *errp = err; | 502 | *errp = err; |
503 | return x; | 503 | return x; |
504 | } | 504 | } |
505 | 505 | ||
506 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 506 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
507 | { | 507 | { |
508 | struct xfrm_state *x; | 508 | struct xfrm_state *x; |
509 | int err = -ESRCH; | 509 | int err = -ESRCH; |
510 | struct km_event c; | 510 | struct km_event c; |
511 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 511 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
512 | 512 | ||
513 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); | 513 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
514 | if (x == NULL) | 514 | if (x == NULL) |
515 | return err; | 515 | return err; |
516 | 516 | ||
517 | if ((err = security_xfrm_state_delete(x)) != 0) | 517 | if ((err = security_xfrm_state_delete(x)) != 0) |
518 | goto out; | 518 | goto out; |
519 | 519 | ||
520 | if (xfrm_state_kern(x)) { | 520 | if (xfrm_state_kern(x)) { |
521 | err = -EPERM; | 521 | err = -EPERM; |
522 | goto out; | 522 | goto out; |
523 | } | 523 | } |
524 | 524 | ||
525 | err = xfrm_state_delete(x); | 525 | err = xfrm_state_delete(x); |
526 | if (err < 0) | 526 | if (err < 0) |
527 | goto out; | 527 | goto out; |
528 | 528 | ||
529 | c.seq = nlh->nlmsg_seq; | 529 | c.seq = nlh->nlmsg_seq; |
530 | c.pid = nlh->nlmsg_pid; | 530 | c.pid = nlh->nlmsg_pid; |
531 | c.event = nlh->nlmsg_type; | 531 | c.event = nlh->nlmsg_type; |
532 | km_state_notify(x, &c); | 532 | km_state_notify(x, &c); |
533 | 533 | ||
534 | out: | 534 | out: |
535 | xfrm_state_put(x); | 535 | xfrm_state_put(x); |
536 | return err; | 536 | return err; |
537 | } | 537 | } |
538 | 538 | ||
539 | static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 539 | static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
540 | { | 540 | { |
541 | memcpy(&p->id, &x->id, sizeof(p->id)); | 541 | memcpy(&p->id, &x->id, sizeof(p->id)); |
542 | memcpy(&p->sel, &x->sel, sizeof(p->sel)); | 542 | memcpy(&p->sel, &x->sel, sizeof(p->sel)); |
543 | memcpy(&p->lft, &x->lft, sizeof(p->lft)); | 543 | memcpy(&p->lft, &x->lft, sizeof(p->lft)); |
544 | memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); | 544 | memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); |
545 | memcpy(&p->stats, &x->stats, sizeof(p->stats)); | 545 | memcpy(&p->stats, &x->stats, sizeof(p->stats)); |
546 | memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); | 546 | memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); |
547 | p->mode = x->props.mode; | 547 | p->mode = x->props.mode; |
548 | p->replay_window = x->props.replay_window; | 548 | p->replay_window = x->props.replay_window; |
549 | p->reqid = x->props.reqid; | 549 | p->reqid = x->props.reqid; |
550 | p->family = x->props.family; | 550 | p->family = x->props.family; |
551 | p->flags = x->props.flags; | 551 | p->flags = x->props.flags; |
552 | p->seq = x->km.seq; | 552 | p->seq = x->km.seq; |
553 | } | 553 | } |
554 | 554 | ||
555 | struct xfrm_dump_info { | 555 | struct xfrm_dump_info { |
556 | struct sk_buff *in_skb; | 556 | struct sk_buff *in_skb; |
557 | struct sk_buff *out_skb; | 557 | struct sk_buff *out_skb; |
558 | u32 nlmsg_seq; | 558 | u32 nlmsg_seq; |
559 | u16 nlmsg_flags; | 559 | u16 nlmsg_flags; |
560 | int start_idx; | 560 | int start_idx; |
561 | int this_idx; | 561 | int this_idx; |
562 | }; | 562 | }; |
563 | 563 | ||
564 | static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | 564 | static int dump_one_state(struct xfrm_state *x, int count, void *ptr) |
565 | { | 565 | { |
566 | struct xfrm_dump_info *sp = ptr; | 566 | struct xfrm_dump_info *sp = ptr; |
567 | struct sk_buff *in_skb = sp->in_skb; | 567 | struct sk_buff *in_skb = sp->in_skb; |
568 | struct sk_buff *skb = sp->out_skb; | 568 | struct sk_buff *skb = sp->out_skb; |
569 | struct xfrm_usersa_info *p; | 569 | struct xfrm_usersa_info *p; |
570 | struct nlmsghdr *nlh; | 570 | struct nlmsghdr *nlh; |
571 | unsigned char *b = skb->tail; | 571 | unsigned char *b = skb->tail; |
572 | 572 | ||
573 | if (sp->this_idx < sp->start_idx) | 573 | if (sp->this_idx < sp->start_idx) |
574 | goto out; | 574 | goto out; |
575 | 575 | ||
576 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, | 576 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, |
577 | sp->nlmsg_seq, | 577 | sp->nlmsg_seq, |
578 | XFRM_MSG_NEWSA, sizeof(*p)); | 578 | XFRM_MSG_NEWSA, sizeof(*p)); |
579 | nlh->nlmsg_flags = sp->nlmsg_flags; | 579 | nlh->nlmsg_flags = sp->nlmsg_flags; |
580 | 580 | ||
581 | p = NLMSG_DATA(nlh); | 581 | p = NLMSG_DATA(nlh); |
582 | copy_to_user_state(x, p); | 582 | copy_to_user_state(x, p); |
583 | 583 | ||
584 | if (x->aalg) | 584 | if (x->aalg) |
585 | RTA_PUT(skb, XFRMA_ALG_AUTH, | 585 | RTA_PUT(skb, XFRMA_ALG_AUTH, |
586 | sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); | 586 | sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); |
587 | if (x->ealg) | 587 | if (x->ealg) |
588 | RTA_PUT(skb, XFRMA_ALG_CRYPT, | 588 | RTA_PUT(skb, XFRMA_ALG_CRYPT, |
589 | sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); | 589 | sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); |
590 | if (x->calg) | 590 | if (x->calg) |
591 | RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); | 591 | RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); |
592 | 592 | ||
593 | if (x->encap) | 593 | if (x->encap) |
594 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 594 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
595 | 595 | ||
596 | if (x->security) { | 596 | if (x->security) { |
597 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | 597 | int ctx_size = sizeof(struct xfrm_sec_ctx) + |
598 | x->security->ctx_len; | 598 | x->security->ctx_len; |
599 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 599 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
600 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 600 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
601 | 601 | ||
602 | uctx->exttype = XFRMA_SEC_CTX; | 602 | uctx->exttype = XFRMA_SEC_CTX; |
603 | uctx->len = ctx_size; | 603 | uctx->len = ctx_size; |
604 | uctx->ctx_doi = x->security->ctx_doi; | 604 | uctx->ctx_doi = x->security->ctx_doi; |
605 | uctx->ctx_alg = x->security->ctx_alg; | 605 | uctx->ctx_alg = x->security->ctx_alg; |
606 | uctx->ctx_len = x->security->ctx_len; | 606 | uctx->ctx_len = x->security->ctx_len; |
607 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | 607 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); |
608 | } | 608 | } |
609 | 609 | ||
610 | if (x->coaddr) | 610 | if (x->coaddr) |
611 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | 611 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); |
612 | 612 | ||
613 | if (x->lastused) | 613 | if (x->lastused) |
614 | RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); | 614 | RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); |
615 | 615 | ||
616 | nlh->nlmsg_len = skb->tail - b; | 616 | nlh->nlmsg_len = skb->tail - b; |
617 | out: | 617 | out: |
618 | sp->this_idx++; | 618 | sp->this_idx++; |
619 | return 0; | 619 | return 0; |
620 | 620 | ||
621 | nlmsg_failure: | 621 | nlmsg_failure: |
622 | rtattr_failure: | 622 | rtattr_failure: |
623 | skb_trim(skb, b - skb->data); | 623 | skb_trim(skb, b - skb->data); |
624 | return -1; | 624 | return -1; |
625 | } | 625 | } |
626 | 626 | ||
627 | static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | 627 | static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) |
628 | { | 628 | { |
629 | struct xfrm_dump_info info; | 629 | struct xfrm_dump_info info; |
630 | 630 | ||
631 | info.in_skb = cb->skb; | 631 | info.in_skb = cb->skb; |
632 | info.out_skb = skb; | 632 | info.out_skb = skb; |
633 | info.nlmsg_seq = cb->nlh->nlmsg_seq; | 633 | info.nlmsg_seq = cb->nlh->nlmsg_seq; |
634 | info.nlmsg_flags = NLM_F_MULTI; | 634 | info.nlmsg_flags = NLM_F_MULTI; |
635 | info.this_idx = 0; | 635 | info.this_idx = 0; |
636 | info.start_idx = cb->args[0]; | 636 | info.start_idx = cb->args[0]; |
637 | (void) xfrm_state_walk(0, dump_one_state, &info); | 637 | (void) xfrm_state_walk(0, dump_one_state, &info); |
638 | cb->args[0] = info.this_idx; | 638 | cb->args[0] = info.this_idx; |
639 | 639 | ||
640 | return skb->len; | 640 | return skb->len; |
641 | } | 641 | } |
642 | 642 | ||
643 | static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, | 643 | static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, |
644 | struct xfrm_state *x, u32 seq) | 644 | struct xfrm_state *x, u32 seq) |
645 | { | 645 | { |
646 | struct xfrm_dump_info info; | 646 | struct xfrm_dump_info info; |
647 | struct sk_buff *skb; | 647 | struct sk_buff *skb; |
648 | 648 | ||
649 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 649 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
650 | if (!skb) | 650 | if (!skb) |
651 | return ERR_PTR(-ENOMEM); | 651 | return ERR_PTR(-ENOMEM); |
652 | 652 | ||
653 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
654 | info.in_skb = in_skb; | 653 | info.in_skb = in_skb; |
655 | info.out_skb = skb; | 654 | info.out_skb = skb; |
656 | info.nlmsg_seq = seq; | 655 | info.nlmsg_seq = seq; |
657 | info.nlmsg_flags = 0; | 656 | info.nlmsg_flags = 0; |
658 | info.this_idx = info.start_idx = 0; | 657 | info.this_idx = info.start_idx = 0; |
659 | 658 | ||
660 | if (dump_one_state(x, 0, &info)) { | 659 | if (dump_one_state(x, 0, &info)) { |
661 | kfree_skb(skb); | 660 | kfree_skb(skb); |
662 | return NULL; | 661 | return NULL; |
663 | } | 662 | } |
664 | 663 | ||
665 | return skb; | 664 | return skb; |
666 | } | 665 | } |
667 | 666 | ||
668 | static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 667 | static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
669 | { | 668 | { |
670 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 669 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
671 | struct xfrm_state *x; | 670 | struct xfrm_state *x; |
672 | struct sk_buff *resp_skb; | 671 | struct sk_buff *resp_skb; |
673 | int err = -ESRCH; | 672 | int err = -ESRCH; |
674 | 673 | ||
675 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); | 674 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
676 | if (x == NULL) | 675 | if (x == NULL) |
677 | goto out_noput; | 676 | goto out_noput; |
678 | 677 | ||
679 | resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); | 678 | resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); |
680 | if (IS_ERR(resp_skb)) { | 679 | if (IS_ERR(resp_skb)) { |
681 | err = PTR_ERR(resp_skb); | 680 | err = PTR_ERR(resp_skb); |
682 | } else { | 681 | } else { |
683 | err = netlink_unicast(xfrm_nl, resp_skb, | 682 | err = netlink_unicast(xfrm_nl, resp_skb, |
684 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | 683 | NETLINK_CB(skb).pid, MSG_DONTWAIT); |
685 | } | 684 | } |
686 | xfrm_state_put(x); | 685 | xfrm_state_put(x); |
687 | out_noput: | 686 | out_noput: |
688 | return err; | 687 | return err; |
689 | } | 688 | } |
690 | 689 | ||
691 | static int verify_userspi_info(struct xfrm_userspi_info *p) | 690 | static int verify_userspi_info(struct xfrm_userspi_info *p) |
692 | { | 691 | { |
693 | switch (p->info.id.proto) { | 692 | switch (p->info.id.proto) { |
694 | case IPPROTO_AH: | 693 | case IPPROTO_AH: |
695 | case IPPROTO_ESP: | 694 | case IPPROTO_ESP: |
696 | break; | 695 | break; |
697 | 696 | ||
698 | case IPPROTO_COMP: | 697 | case IPPROTO_COMP: |
699 | /* IPCOMP spi is 16-bits. */ | 698 | /* IPCOMP spi is 16-bits. */ |
700 | if (p->max >= 0x10000) | 699 | if (p->max >= 0x10000) |
701 | return -EINVAL; | 700 | return -EINVAL; |
702 | break; | 701 | break; |
703 | 702 | ||
704 | default: | 703 | default: |
705 | return -EINVAL; | 704 | return -EINVAL; |
706 | }; | 705 | }; |
707 | 706 | ||
708 | if (p->min > p->max) | 707 | if (p->min > p->max) |
709 | return -EINVAL; | 708 | return -EINVAL; |
710 | 709 | ||
711 | return 0; | 710 | return 0; |
712 | } | 711 | } |
713 | 712 | ||
714 | static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 713 | static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
715 | { | 714 | { |
716 | struct xfrm_state *x; | 715 | struct xfrm_state *x; |
717 | struct xfrm_userspi_info *p; | 716 | struct xfrm_userspi_info *p; |
718 | struct sk_buff *resp_skb; | 717 | struct sk_buff *resp_skb; |
719 | xfrm_address_t *daddr; | 718 | xfrm_address_t *daddr; |
720 | int family; | 719 | int family; |
721 | int err; | 720 | int err; |
722 | 721 | ||
723 | p = NLMSG_DATA(nlh); | 722 | p = NLMSG_DATA(nlh); |
724 | err = verify_userspi_info(p); | 723 | err = verify_userspi_info(p); |
725 | if (err) | 724 | if (err) |
726 | goto out_noput; | 725 | goto out_noput; |
727 | 726 | ||
728 | family = p->info.family; | 727 | family = p->info.family; |
729 | daddr = &p->info.id.daddr; | 728 | daddr = &p->info.id.daddr; |
730 | 729 | ||
731 | x = NULL; | 730 | x = NULL; |
732 | if (p->info.seq) { | 731 | if (p->info.seq) { |
733 | x = xfrm_find_acq_byseq(p->info.seq); | 732 | x = xfrm_find_acq_byseq(p->info.seq); |
734 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { | 733 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { |
735 | xfrm_state_put(x); | 734 | xfrm_state_put(x); |
736 | x = NULL; | 735 | x = NULL; |
737 | } | 736 | } |
738 | } | 737 | } |
739 | 738 | ||
740 | if (!x) | 739 | if (!x) |
741 | x = xfrm_find_acq(p->info.mode, p->info.reqid, | 740 | x = xfrm_find_acq(p->info.mode, p->info.reqid, |
742 | p->info.id.proto, daddr, | 741 | p->info.id.proto, daddr, |
743 | &p->info.saddr, 1, | 742 | &p->info.saddr, 1, |
744 | family); | 743 | family); |
745 | err = -ENOENT; | 744 | err = -ENOENT; |
746 | if (x == NULL) | 745 | if (x == NULL) |
747 | goto out_noput; | 746 | goto out_noput; |
748 | 747 | ||
749 | resp_skb = ERR_PTR(-ENOENT); | 748 | resp_skb = ERR_PTR(-ENOENT); |
750 | 749 | ||
751 | spin_lock_bh(&x->lock); | 750 | spin_lock_bh(&x->lock); |
752 | if (x->km.state != XFRM_STATE_DEAD) { | 751 | if (x->km.state != XFRM_STATE_DEAD) { |
753 | xfrm_alloc_spi(x, htonl(p->min), htonl(p->max)); | 752 | xfrm_alloc_spi(x, htonl(p->min), htonl(p->max)); |
754 | if (x->id.spi) | 753 | if (x->id.spi) |
755 | resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); | 754 | resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); |
756 | } | 755 | } |
757 | spin_unlock_bh(&x->lock); | 756 | spin_unlock_bh(&x->lock); |
758 | 757 | ||
759 | if (IS_ERR(resp_skb)) { | 758 | if (IS_ERR(resp_skb)) { |
760 | err = PTR_ERR(resp_skb); | 759 | err = PTR_ERR(resp_skb); |
761 | goto out; | 760 | goto out; |
762 | } | 761 | } |
763 | 762 | ||
764 | err = netlink_unicast(xfrm_nl, resp_skb, | 763 | err = netlink_unicast(xfrm_nl, resp_skb, |
765 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | 764 | NETLINK_CB(skb).pid, MSG_DONTWAIT); |
766 | 765 | ||
767 | out: | 766 | out: |
768 | xfrm_state_put(x); | 767 | xfrm_state_put(x); |
769 | out_noput: | 768 | out_noput: |
770 | return err; | 769 | return err; |
771 | } | 770 | } |
772 | 771 | ||
773 | static int verify_policy_dir(__u8 dir) | 772 | static int verify_policy_dir(__u8 dir) |
774 | { | 773 | { |
775 | switch (dir) { | 774 | switch (dir) { |
776 | case XFRM_POLICY_IN: | 775 | case XFRM_POLICY_IN: |
777 | case XFRM_POLICY_OUT: | 776 | case XFRM_POLICY_OUT: |
778 | case XFRM_POLICY_FWD: | 777 | case XFRM_POLICY_FWD: |
779 | break; | 778 | break; |
780 | 779 | ||
781 | default: | 780 | default: |
782 | return -EINVAL; | 781 | return -EINVAL; |
783 | }; | 782 | }; |
784 | 783 | ||
785 | return 0; | 784 | return 0; |
786 | } | 785 | } |
787 | 786 | ||
788 | static int verify_policy_type(__u8 type) | 787 | static int verify_policy_type(__u8 type) |
789 | { | 788 | { |
790 | switch (type) { | 789 | switch (type) { |
791 | case XFRM_POLICY_TYPE_MAIN: | 790 | case XFRM_POLICY_TYPE_MAIN: |
792 | #ifdef CONFIG_XFRM_SUB_POLICY | 791 | #ifdef CONFIG_XFRM_SUB_POLICY |
793 | case XFRM_POLICY_TYPE_SUB: | 792 | case XFRM_POLICY_TYPE_SUB: |
794 | #endif | 793 | #endif |
795 | break; | 794 | break; |
796 | 795 | ||
797 | default: | 796 | default: |
798 | return -EINVAL; | 797 | return -EINVAL; |
799 | }; | 798 | }; |
800 | 799 | ||
801 | return 0; | 800 | return 0; |
802 | } | 801 | } |
803 | 802 | ||
804 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 803 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
805 | { | 804 | { |
806 | switch (p->share) { | 805 | switch (p->share) { |
807 | case XFRM_SHARE_ANY: | 806 | case XFRM_SHARE_ANY: |
808 | case XFRM_SHARE_SESSION: | 807 | case XFRM_SHARE_SESSION: |
809 | case XFRM_SHARE_USER: | 808 | case XFRM_SHARE_USER: |
810 | case XFRM_SHARE_UNIQUE: | 809 | case XFRM_SHARE_UNIQUE: |
811 | break; | 810 | break; |
812 | 811 | ||
813 | default: | 812 | default: |
814 | return -EINVAL; | 813 | return -EINVAL; |
815 | }; | 814 | }; |
816 | 815 | ||
817 | switch (p->action) { | 816 | switch (p->action) { |
818 | case XFRM_POLICY_ALLOW: | 817 | case XFRM_POLICY_ALLOW: |
819 | case XFRM_POLICY_BLOCK: | 818 | case XFRM_POLICY_BLOCK: |
820 | break; | 819 | break; |
821 | 820 | ||
822 | default: | 821 | default: |
823 | return -EINVAL; | 822 | return -EINVAL; |
824 | }; | 823 | }; |
825 | 824 | ||
826 | switch (p->sel.family) { | 825 | switch (p->sel.family) { |
827 | case AF_INET: | 826 | case AF_INET: |
828 | break; | 827 | break; |
829 | 828 | ||
830 | case AF_INET6: | 829 | case AF_INET6: |
831 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 830 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
832 | break; | 831 | break; |
833 | #else | 832 | #else |
834 | return -EAFNOSUPPORT; | 833 | return -EAFNOSUPPORT; |
835 | #endif | 834 | #endif |
836 | 835 | ||
837 | default: | 836 | default: |
838 | return -EINVAL; | 837 | return -EINVAL; |
839 | }; | 838 | }; |
840 | 839 | ||
841 | return verify_policy_dir(p->dir); | 840 | return verify_policy_dir(p->dir); |
842 | } | 841 | } |
843 | 842 | ||
844 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) | 843 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) |
845 | { | 844 | { |
846 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; | 845 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; |
847 | struct xfrm_user_sec_ctx *uctx; | 846 | struct xfrm_user_sec_ctx *uctx; |
848 | 847 | ||
849 | if (!rt) | 848 | if (!rt) |
850 | return 0; | 849 | return 0; |
851 | 850 | ||
852 | uctx = RTA_DATA(rt); | 851 | uctx = RTA_DATA(rt); |
853 | return security_xfrm_policy_alloc(pol, uctx); | 852 | return security_xfrm_policy_alloc(pol, uctx); |
854 | } | 853 | } |
855 | 854 | ||
856 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | 855 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, |
857 | int nr) | 856 | int nr) |
858 | { | 857 | { |
859 | int i; | 858 | int i; |
860 | 859 | ||
861 | xp->xfrm_nr = nr; | 860 | xp->xfrm_nr = nr; |
862 | for (i = 0; i < nr; i++, ut++) { | 861 | for (i = 0; i < nr; i++, ut++) { |
863 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | 862 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; |
864 | 863 | ||
865 | memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); | 864 | memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); |
866 | memcpy(&t->saddr, &ut->saddr, | 865 | memcpy(&t->saddr, &ut->saddr, |
867 | sizeof(xfrm_address_t)); | 866 | sizeof(xfrm_address_t)); |
868 | t->reqid = ut->reqid; | 867 | t->reqid = ut->reqid; |
869 | t->mode = ut->mode; | 868 | t->mode = ut->mode; |
870 | t->share = ut->share; | 869 | t->share = ut->share; |
871 | t->optional = ut->optional; | 870 | t->optional = ut->optional; |
872 | t->aalgos = ut->aalgos; | 871 | t->aalgos = ut->aalgos; |
873 | t->ealgos = ut->ealgos; | 872 | t->ealgos = ut->ealgos; |
874 | t->calgos = ut->calgos; | 873 | t->calgos = ut->calgos; |
875 | } | 874 | } |
876 | } | 875 | } |
877 | 876 | ||
878 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | 877 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) |
879 | { | 878 | { |
880 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | 879 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; |
881 | struct xfrm_user_tmpl *utmpl; | 880 | struct xfrm_user_tmpl *utmpl; |
882 | int nr; | 881 | int nr; |
883 | 882 | ||
884 | if (!rt) { | 883 | if (!rt) { |
885 | pol->xfrm_nr = 0; | 884 | pol->xfrm_nr = 0; |
886 | } else { | 885 | } else { |
887 | nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); | 886 | nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); |
888 | 887 | ||
889 | if (nr > XFRM_MAX_DEPTH) | 888 | if (nr > XFRM_MAX_DEPTH) |
890 | return -EINVAL; | 889 | return -EINVAL; |
891 | 890 | ||
892 | copy_templates(pol, RTA_DATA(rt), nr); | 891 | copy_templates(pol, RTA_DATA(rt), nr); |
893 | } | 892 | } |
894 | return 0; | 893 | return 0; |
895 | } | 894 | } |
896 | 895 | ||
897 | static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) | 896 | static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) |
898 | { | 897 | { |
899 | struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; | 898 | struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; |
900 | struct xfrm_userpolicy_type *upt; | 899 | struct xfrm_userpolicy_type *upt; |
901 | __u8 type = XFRM_POLICY_TYPE_MAIN; | 900 | __u8 type = XFRM_POLICY_TYPE_MAIN; |
902 | int err; | 901 | int err; |
903 | 902 | ||
904 | if (rt) { | 903 | if (rt) { |
905 | if (rt->rta_len < sizeof(*upt)) | 904 | if (rt->rta_len < sizeof(*upt)) |
906 | return -EINVAL; | 905 | return -EINVAL; |
907 | 906 | ||
908 | upt = RTA_DATA(rt); | 907 | upt = RTA_DATA(rt); |
909 | type = upt->type; | 908 | type = upt->type; |
910 | } | 909 | } |
911 | 910 | ||
912 | err = verify_policy_type(type); | 911 | err = verify_policy_type(type); |
913 | if (err) | 912 | if (err) |
914 | return err; | 913 | return err; |
915 | 914 | ||
916 | *tp = type; | 915 | *tp = type; |
917 | return 0; | 916 | return 0; |
918 | } | 917 | } |
919 | 918 | ||
920 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) | 919 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) |
921 | { | 920 | { |
922 | xp->priority = p->priority; | 921 | xp->priority = p->priority; |
923 | xp->index = p->index; | 922 | xp->index = p->index; |
924 | memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); | 923 | memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); |
925 | memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); | 924 | memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); |
926 | xp->action = p->action; | 925 | xp->action = p->action; |
927 | xp->flags = p->flags; | 926 | xp->flags = p->flags; |
928 | xp->family = p->sel.family; | 927 | xp->family = p->sel.family; |
929 | /* XXX xp->share = p->share; */ | 928 | /* XXX xp->share = p->share; */ |
930 | } | 929 | } |
931 | 930 | ||
932 | static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) | 931 | static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) |
933 | { | 932 | { |
934 | memcpy(&p->sel, &xp->selector, sizeof(p->sel)); | 933 | memcpy(&p->sel, &xp->selector, sizeof(p->sel)); |
935 | memcpy(&p->lft, &xp->lft, sizeof(p->lft)); | 934 | memcpy(&p->lft, &xp->lft, sizeof(p->lft)); |
936 | memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); | 935 | memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); |
937 | p->priority = xp->priority; | 936 | p->priority = xp->priority; |
938 | p->index = xp->index; | 937 | p->index = xp->index; |
939 | p->sel.family = xp->family; | 938 | p->sel.family = xp->family; |
940 | p->dir = dir; | 939 | p->dir = dir; |
941 | p->action = xp->action; | 940 | p->action = xp->action; |
942 | p->flags = xp->flags; | 941 | p->flags = xp->flags; |
943 | p->share = XFRM_SHARE_ANY; /* XXX xp->share */ | 942 | p->share = XFRM_SHARE_ANY; /* XXX xp->share */ |
944 | } | 943 | } |
945 | 944 | ||
946 | static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) | 945 | static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) |
947 | { | 946 | { |
948 | struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); | 947 | struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); |
949 | int err; | 948 | int err; |
950 | 949 | ||
951 | if (!xp) { | 950 | if (!xp) { |
952 | *errp = -ENOMEM; | 951 | *errp = -ENOMEM; |
953 | return NULL; | 952 | return NULL; |
954 | } | 953 | } |
955 | 954 | ||
956 | copy_from_user_policy(xp, p); | 955 | copy_from_user_policy(xp, p); |
957 | 956 | ||
958 | err = copy_from_user_policy_type(&xp->type, xfrma); | 957 | err = copy_from_user_policy_type(&xp->type, xfrma); |
959 | if (err) | 958 | if (err) |
960 | goto error; | 959 | goto error; |
961 | 960 | ||
962 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 961 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
963 | err = copy_from_user_sec_ctx(xp, xfrma); | 962 | err = copy_from_user_sec_ctx(xp, xfrma); |
964 | if (err) | 963 | if (err) |
965 | goto error; | 964 | goto error; |
966 | 965 | ||
967 | return xp; | 966 | return xp; |
968 | error: | 967 | error: |
969 | *errp = err; | 968 | *errp = err; |
970 | kfree(xp); | 969 | kfree(xp); |
971 | return NULL; | 970 | return NULL; |
972 | } | 971 | } |
973 | 972 | ||
974 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 973 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
975 | { | 974 | { |
976 | struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); | 975 | struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); |
977 | struct xfrm_policy *xp; | 976 | struct xfrm_policy *xp; |
978 | struct km_event c; | 977 | struct km_event c; |
979 | int err; | 978 | int err; |
980 | int excl; | 979 | int excl; |
981 | 980 | ||
982 | err = verify_newpolicy_info(p); | 981 | err = verify_newpolicy_info(p); |
983 | if (err) | 982 | if (err) |
984 | return err; | 983 | return err; |
985 | err = verify_sec_ctx_len((struct rtattr **)xfrma); | 984 | err = verify_sec_ctx_len((struct rtattr **)xfrma); |
986 | if (err) | 985 | if (err) |
987 | return err; | 986 | return err; |
988 | 987 | ||
989 | xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err); | 988 | xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err); |
990 | if (!xp) | 989 | if (!xp) |
991 | return err; | 990 | return err; |
992 | 991 | ||
993 | /* shouldnt excl be based on nlh flags?? | 992 | /* shouldnt excl be based on nlh flags?? |
994 | * Aha! this is anti-netlink really i.e more pfkey derived | 993 | * Aha! this is anti-netlink really i.e more pfkey derived |
995 | * in netlink excl is a flag and you wouldnt need | 994 | * in netlink excl is a flag and you wouldnt need |
996 | * a type XFRM_MSG_UPDPOLICY - JHS */ | 995 | * a type XFRM_MSG_UPDPOLICY - JHS */ |
997 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; | 996 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; |
998 | err = xfrm_policy_insert(p->dir, xp, excl); | 997 | err = xfrm_policy_insert(p->dir, xp, excl); |
999 | if (err) { | 998 | if (err) { |
1000 | security_xfrm_policy_free(xp); | 999 | security_xfrm_policy_free(xp); |
1001 | kfree(xp); | 1000 | kfree(xp); |
1002 | return err; | 1001 | return err; |
1003 | } | 1002 | } |
1004 | 1003 | ||
1005 | c.event = nlh->nlmsg_type; | 1004 | c.event = nlh->nlmsg_type; |
1006 | c.seq = nlh->nlmsg_seq; | 1005 | c.seq = nlh->nlmsg_seq; |
1007 | c.pid = nlh->nlmsg_pid; | 1006 | c.pid = nlh->nlmsg_pid; |
1008 | km_policy_notify(xp, p->dir, &c); | 1007 | km_policy_notify(xp, p->dir, &c); |
1009 | 1008 | ||
1010 | xfrm_pol_put(xp); | 1009 | xfrm_pol_put(xp); |
1011 | 1010 | ||
1012 | return 0; | 1011 | return 0; |
1013 | } | 1012 | } |
1014 | 1013 | ||
1015 | static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) | 1014 | static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) |
1016 | { | 1015 | { |
1017 | struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; | 1016 | struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; |
1018 | int i; | 1017 | int i; |
1019 | 1018 | ||
1020 | if (xp->xfrm_nr == 0) | 1019 | if (xp->xfrm_nr == 0) |
1021 | return 0; | 1020 | return 0; |
1022 | 1021 | ||
1023 | for (i = 0; i < xp->xfrm_nr; i++) { | 1022 | for (i = 0; i < xp->xfrm_nr; i++) { |
1024 | struct xfrm_user_tmpl *up = &vec[i]; | 1023 | struct xfrm_user_tmpl *up = &vec[i]; |
1025 | struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; | 1024 | struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; |
1026 | 1025 | ||
1027 | memcpy(&up->id, &kp->id, sizeof(up->id)); | 1026 | memcpy(&up->id, &kp->id, sizeof(up->id)); |
1028 | up->family = xp->family; | 1027 | up->family = xp->family; |
1029 | memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); | 1028 | memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); |
1030 | up->reqid = kp->reqid; | 1029 | up->reqid = kp->reqid; |
1031 | up->mode = kp->mode; | 1030 | up->mode = kp->mode; |
1032 | up->share = kp->share; | 1031 | up->share = kp->share; |
1033 | up->optional = kp->optional; | 1032 | up->optional = kp->optional; |
1034 | up->aalgos = kp->aalgos; | 1033 | up->aalgos = kp->aalgos; |
1035 | up->ealgos = kp->ealgos; | 1034 | up->ealgos = kp->ealgos; |
1036 | up->calgos = kp->calgos; | 1035 | up->calgos = kp->calgos; |
1037 | } | 1036 | } |
1038 | RTA_PUT(skb, XFRMA_TMPL, | 1037 | RTA_PUT(skb, XFRMA_TMPL, |
1039 | (sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr), | 1038 | (sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr), |
1040 | vec); | 1039 | vec); |
1041 | 1040 | ||
1042 | return 0; | 1041 | return 0; |
1043 | 1042 | ||
1044 | rtattr_failure: | 1043 | rtattr_failure: |
1045 | return -1; | 1044 | return -1; |
1046 | } | 1045 | } |
1047 | 1046 | ||
1048 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | 1047 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) |
1049 | { | 1048 | { |
1050 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; | 1049 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; |
1051 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 1050 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
1052 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1051 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
1053 | 1052 | ||
1054 | uctx->exttype = XFRMA_SEC_CTX; | 1053 | uctx->exttype = XFRMA_SEC_CTX; |
1055 | uctx->len = ctx_size; | 1054 | uctx->len = ctx_size; |
1056 | uctx->ctx_doi = s->ctx_doi; | 1055 | uctx->ctx_doi = s->ctx_doi; |
1057 | uctx->ctx_alg = s->ctx_alg; | 1056 | uctx->ctx_alg = s->ctx_alg; |
1058 | uctx->ctx_len = s->ctx_len; | 1057 | uctx->ctx_len = s->ctx_len; |
1059 | memcpy(uctx + 1, s->ctx_str, s->ctx_len); | 1058 | memcpy(uctx + 1, s->ctx_str, s->ctx_len); |
1060 | return 0; | 1059 | return 0; |
1061 | 1060 | ||
1062 | rtattr_failure: | 1061 | rtattr_failure: |
1063 | return -1; | 1062 | return -1; |
1064 | } | 1063 | } |
1065 | 1064 | ||
1066 | static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) | 1065 | static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) |
1067 | { | 1066 | { |
1068 | if (x->security) { | 1067 | if (x->security) { |
1069 | return copy_sec_ctx(x->security, skb); | 1068 | return copy_sec_ctx(x->security, skb); |
1070 | } | 1069 | } |
1071 | return 0; | 1070 | return 0; |
1072 | } | 1071 | } |
1073 | 1072 | ||
1074 | static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | 1073 | static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) |
1075 | { | 1074 | { |
1076 | if (xp->security) { | 1075 | if (xp->security) { |
1077 | return copy_sec_ctx(xp->security, skb); | 1076 | return copy_sec_ctx(xp->security, skb); |
1078 | } | 1077 | } |
1079 | return 0; | 1078 | return 0; |
1080 | } | 1079 | } |
1081 | 1080 | ||
1082 | #ifdef CONFIG_XFRM_SUB_POLICY | 1081 | #ifdef CONFIG_XFRM_SUB_POLICY |
1083 | static int copy_to_user_policy_type(__u8 type, struct sk_buff *skb) | 1082 | static int copy_to_user_policy_type(__u8 type, struct sk_buff *skb) |
1084 | { | 1083 | { |
1085 | struct xfrm_userpolicy_type upt; | 1084 | struct xfrm_userpolicy_type upt; |
1086 | 1085 | ||
1087 | memset(&upt, 0, sizeof(upt)); | 1086 | memset(&upt, 0, sizeof(upt)); |
1088 | upt.type = type; | 1087 | upt.type = type; |
1089 | 1088 | ||
1090 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | 1089 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); |
1091 | 1090 | ||
1092 | return 0; | 1091 | return 0; |
1093 | 1092 | ||
1094 | rtattr_failure: | 1093 | rtattr_failure: |
1095 | return -1; | 1094 | return -1; |
1096 | } | 1095 | } |
1097 | 1096 | ||
1098 | #else | 1097 | #else |
1099 | static inline int copy_to_user_policy_type(__u8 type, struct sk_buff *skb) | 1098 | static inline int copy_to_user_policy_type(__u8 type, struct sk_buff *skb) |
1100 | { | 1099 | { |
1101 | return 0; | 1100 | return 0; |
1102 | } | 1101 | } |
1103 | #endif | 1102 | #endif |
1104 | 1103 | ||
1105 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 1104 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
1106 | { | 1105 | { |
1107 | struct xfrm_dump_info *sp = ptr; | 1106 | struct xfrm_dump_info *sp = ptr; |
1108 | struct xfrm_userpolicy_info *p; | 1107 | struct xfrm_userpolicy_info *p; |
1109 | struct sk_buff *in_skb = sp->in_skb; | 1108 | struct sk_buff *in_skb = sp->in_skb; |
1110 | struct sk_buff *skb = sp->out_skb; | 1109 | struct sk_buff *skb = sp->out_skb; |
1111 | struct nlmsghdr *nlh; | 1110 | struct nlmsghdr *nlh; |
1112 | unsigned char *b = skb->tail; | 1111 | unsigned char *b = skb->tail; |
1113 | 1112 | ||
1114 | if (sp->this_idx < sp->start_idx) | 1113 | if (sp->this_idx < sp->start_idx) |
1115 | goto out; | 1114 | goto out; |
1116 | 1115 | ||
1117 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, | 1116 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, |
1118 | sp->nlmsg_seq, | 1117 | sp->nlmsg_seq, |
1119 | XFRM_MSG_NEWPOLICY, sizeof(*p)); | 1118 | XFRM_MSG_NEWPOLICY, sizeof(*p)); |
1120 | p = NLMSG_DATA(nlh); | 1119 | p = NLMSG_DATA(nlh); |
1121 | nlh->nlmsg_flags = sp->nlmsg_flags; | 1120 | nlh->nlmsg_flags = sp->nlmsg_flags; |
1122 | 1121 | ||
1123 | copy_to_user_policy(xp, p, dir); | 1122 | copy_to_user_policy(xp, p, dir); |
1124 | if (copy_to_user_tmpl(xp, skb) < 0) | 1123 | if (copy_to_user_tmpl(xp, skb) < 0) |
1125 | goto nlmsg_failure; | 1124 | goto nlmsg_failure; |
1126 | if (copy_to_user_sec_ctx(xp, skb)) | 1125 | if (copy_to_user_sec_ctx(xp, skb)) |
1127 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
1128 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 1127 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
1129 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
1130 | 1129 | ||
1131 | nlh->nlmsg_len = skb->tail - b; | 1130 | nlh->nlmsg_len = skb->tail - b; |
1132 | out: | 1131 | out: |
1133 | sp->this_idx++; | 1132 | sp->this_idx++; |
1134 | return 0; | 1133 | return 0; |
1135 | 1134 | ||
1136 | nlmsg_failure: | 1135 | nlmsg_failure: |
1137 | skb_trim(skb, b - skb->data); | 1136 | skb_trim(skb, b - skb->data); |
1138 | return -1; | 1137 | return -1; |
1139 | } | 1138 | } |
1140 | 1139 | ||
1141 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | 1140 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) |
1142 | { | 1141 | { |
1143 | struct xfrm_dump_info info; | 1142 | struct xfrm_dump_info info; |
1144 | 1143 | ||
1145 | info.in_skb = cb->skb; | 1144 | info.in_skb = cb->skb; |
1146 | info.out_skb = skb; | 1145 | info.out_skb = skb; |
1147 | info.nlmsg_seq = cb->nlh->nlmsg_seq; | 1146 | info.nlmsg_seq = cb->nlh->nlmsg_seq; |
1148 | info.nlmsg_flags = NLM_F_MULTI; | 1147 | info.nlmsg_flags = NLM_F_MULTI; |
1149 | info.this_idx = 0; | 1148 | info.this_idx = 0; |
1150 | info.start_idx = cb->args[0]; | 1149 | info.start_idx = cb->args[0]; |
1151 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); | 1150 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); |
1152 | #ifdef CONFIG_XFRM_SUB_POLICY | 1151 | #ifdef CONFIG_XFRM_SUB_POLICY |
1153 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); | 1152 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); |
1154 | #endif | 1153 | #endif |
1155 | cb->args[0] = info.this_idx; | 1154 | cb->args[0] = info.this_idx; |
1156 | 1155 | ||
1157 | return skb->len; | 1156 | return skb->len; |
1158 | } | 1157 | } |
1159 | 1158 | ||
1160 | static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, | 1159 | static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, |
1161 | struct xfrm_policy *xp, | 1160 | struct xfrm_policy *xp, |
1162 | int dir, u32 seq) | 1161 | int dir, u32 seq) |
1163 | { | 1162 | { |
1164 | struct xfrm_dump_info info; | 1163 | struct xfrm_dump_info info; |
1165 | struct sk_buff *skb; | 1164 | struct sk_buff *skb; |
1166 | 1165 | ||
1167 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 1166 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1168 | if (!skb) | 1167 | if (!skb) |
1169 | return ERR_PTR(-ENOMEM); | 1168 | return ERR_PTR(-ENOMEM); |
1170 | 1169 | ||
1171 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
1172 | info.in_skb = in_skb; | 1170 | info.in_skb = in_skb; |
1173 | info.out_skb = skb; | 1171 | info.out_skb = skb; |
1174 | info.nlmsg_seq = seq; | 1172 | info.nlmsg_seq = seq; |
1175 | info.nlmsg_flags = 0; | 1173 | info.nlmsg_flags = 0; |
1176 | info.this_idx = info.start_idx = 0; | 1174 | info.this_idx = info.start_idx = 0; |
1177 | 1175 | ||
1178 | if (dump_one_policy(xp, dir, 0, &info) < 0) { | 1176 | if (dump_one_policy(xp, dir, 0, &info) < 0) { |
1179 | kfree_skb(skb); | 1177 | kfree_skb(skb); |
1180 | return NULL; | 1178 | return NULL; |
1181 | } | 1179 | } |
1182 | 1180 | ||
1183 | return skb; | 1181 | return skb; |
1184 | } | 1182 | } |
1185 | 1183 | ||
1186 | static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1184 | static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1187 | { | 1185 | { |
1188 | struct xfrm_policy *xp; | 1186 | struct xfrm_policy *xp; |
1189 | struct xfrm_userpolicy_id *p; | 1187 | struct xfrm_userpolicy_id *p; |
1190 | __u8 type = XFRM_POLICY_TYPE_MAIN; | 1188 | __u8 type = XFRM_POLICY_TYPE_MAIN; |
1191 | int err; | 1189 | int err; |
1192 | struct km_event c; | 1190 | struct km_event c; |
1193 | int delete; | 1191 | int delete; |
1194 | 1192 | ||
1195 | p = NLMSG_DATA(nlh); | 1193 | p = NLMSG_DATA(nlh); |
1196 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1194 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
1197 | 1195 | ||
1198 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | 1196 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); |
1199 | if (err) | 1197 | if (err) |
1200 | return err; | 1198 | return err; |
1201 | 1199 | ||
1202 | err = verify_policy_dir(p->dir); | 1200 | err = verify_policy_dir(p->dir); |
1203 | if (err) | 1201 | if (err) |
1204 | return err; | 1202 | return err; |
1205 | 1203 | ||
1206 | if (p->index) | 1204 | if (p->index) |
1207 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); | 1205 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
1208 | else { | 1206 | else { |
1209 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1207 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1210 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1208 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
1211 | struct xfrm_policy tmp; | 1209 | struct xfrm_policy tmp; |
1212 | 1210 | ||
1213 | err = verify_sec_ctx_len(rtattrs); | 1211 | err = verify_sec_ctx_len(rtattrs); |
1214 | if (err) | 1212 | if (err) |
1215 | return err; | 1213 | return err; |
1216 | 1214 | ||
1217 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | 1215 | memset(&tmp, 0, sizeof(struct xfrm_policy)); |
1218 | if (rt) { | 1216 | if (rt) { |
1219 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1217 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
1220 | 1218 | ||
1221 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1219 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1222 | return err; | 1220 | return err; |
1223 | } | 1221 | } |
1224 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); | 1222 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); |
1225 | security_xfrm_policy_free(&tmp); | 1223 | security_xfrm_policy_free(&tmp); |
1226 | } | 1224 | } |
1227 | if (xp == NULL) | 1225 | if (xp == NULL) |
1228 | return -ENOENT; | 1226 | return -ENOENT; |
1229 | 1227 | ||
1230 | if (!delete) { | 1228 | if (!delete) { |
1231 | struct sk_buff *resp_skb; | 1229 | struct sk_buff *resp_skb; |
1232 | 1230 | ||
1233 | resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); | 1231 | resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); |
1234 | if (IS_ERR(resp_skb)) { | 1232 | if (IS_ERR(resp_skb)) { |
1235 | err = PTR_ERR(resp_skb); | 1233 | err = PTR_ERR(resp_skb); |
1236 | } else { | 1234 | } else { |
1237 | err = netlink_unicast(xfrm_nl, resp_skb, | 1235 | err = netlink_unicast(xfrm_nl, resp_skb, |
1238 | NETLINK_CB(skb).pid, | 1236 | NETLINK_CB(skb).pid, |
1239 | MSG_DONTWAIT); | 1237 | MSG_DONTWAIT); |
1240 | } | 1238 | } |
1241 | } else { | 1239 | } else { |
1242 | if ((err = security_xfrm_policy_delete(xp)) != 0) | 1240 | if ((err = security_xfrm_policy_delete(xp)) != 0) |
1243 | goto out; | 1241 | goto out; |
1244 | c.data.byid = p->index; | 1242 | c.data.byid = p->index; |
1245 | c.event = nlh->nlmsg_type; | 1243 | c.event = nlh->nlmsg_type; |
1246 | c.seq = nlh->nlmsg_seq; | 1244 | c.seq = nlh->nlmsg_seq; |
1247 | c.pid = nlh->nlmsg_pid; | 1245 | c.pid = nlh->nlmsg_pid; |
1248 | km_policy_notify(xp, p->dir, &c); | 1246 | km_policy_notify(xp, p->dir, &c); |
1249 | } | 1247 | } |
1250 | 1248 | ||
1251 | xfrm_pol_put(xp); | 1249 | xfrm_pol_put(xp); |
1252 | 1250 | ||
1253 | out: | 1251 | out: |
1254 | return err; | 1252 | return err; |
1255 | } | 1253 | } |
1256 | 1254 | ||
1257 | static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1255 | static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1258 | { | 1256 | { |
1259 | struct km_event c; | 1257 | struct km_event c; |
1260 | struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); | 1258 | struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); |
1261 | 1259 | ||
1262 | xfrm_state_flush(p->proto); | 1260 | xfrm_state_flush(p->proto); |
1263 | c.data.proto = p->proto; | 1261 | c.data.proto = p->proto; |
1264 | c.event = nlh->nlmsg_type; | 1262 | c.event = nlh->nlmsg_type; |
1265 | c.seq = nlh->nlmsg_seq; | 1263 | c.seq = nlh->nlmsg_seq; |
1266 | c.pid = nlh->nlmsg_pid; | 1264 | c.pid = nlh->nlmsg_pid; |
1267 | km_state_notify(NULL, &c); | 1265 | km_state_notify(NULL, &c); |
1268 | 1266 | ||
1269 | return 0; | 1267 | return 0; |
1270 | } | 1268 | } |
1271 | 1269 | ||
1272 | 1270 | ||
1273 | static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | 1271 | static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
1274 | { | 1272 | { |
1275 | struct xfrm_aevent_id *id; | 1273 | struct xfrm_aevent_id *id; |
1276 | struct nlmsghdr *nlh; | 1274 | struct nlmsghdr *nlh; |
1277 | struct xfrm_lifetime_cur ltime; | 1275 | struct xfrm_lifetime_cur ltime; |
1278 | unsigned char *b = skb->tail; | 1276 | unsigned char *b = skb->tail; |
1279 | 1277 | ||
1280 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); | 1278 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); |
1281 | id = NLMSG_DATA(nlh); | 1279 | id = NLMSG_DATA(nlh); |
1282 | nlh->nlmsg_flags = 0; | 1280 | nlh->nlmsg_flags = 0; |
1283 | 1281 | ||
1284 | id->sa_id.daddr = x->id.daddr; | 1282 | id->sa_id.daddr = x->id.daddr; |
1285 | id->sa_id.spi = x->id.spi; | 1283 | id->sa_id.spi = x->id.spi; |
1286 | id->sa_id.family = x->props.family; | 1284 | id->sa_id.family = x->props.family; |
1287 | id->sa_id.proto = x->id.proto; | 1285 | id->sa_id.proto = x->id.proto; |
1288 | id->flags = c->data.aevent; | 1286 | id->flags = c->data.aevent; |
1289 | 1287 | ||
1290 | RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | 1288 | RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); |
1291 | 1289 | ||
1292 | ltime.bytes = x->curlft.bytes; | 1290 | ltime.bytes = x->curlft.bytes; |
1293 | ltime.packets = x->curlft.packets; | 1291 | ltime.packets = x->curlft.packets; |
1294 | ltime.add_time = x->curlft.add_time; | 1292 | ltime.add_time = x->curlft.add_time; |
1295 | ltime.use_time = x->curlft.use_time; | 1293 | ltime.use_time = x->curlft.use_time; |
1296 | 1294 | ||
1297 | RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); | 1295 | RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); |
1298 | 1296 | ||
1299 | if (id->flags&XFRM_AE_RTHR) { | 1297 | if (id->flags&XFRM_AE_RTHR) { |
1300 | RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); | 1298 | RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); |
1301 | } | 1299 | } |
1302 | 1300 | ||
1303 | if (id->flags&XFRM_AE_ETHR) { | 1301 | if (id->flags&XFRM_AE_ETHR) { |
1304 | u32 etimer = x->replay_maxage*10/HZ; | 1302 | u32 etimer = x->replay_maxage*10/HZ; |
1305 | RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); | 1303 | RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); |
1306 | } | 1304 | } |
1307 | 1305 | ||
1308 | nlh->nlmsg_len = skb->tail - b; | 1306 | nlh->nlmsg_len = skb->tail - b; |
1309 | return skb->len; | 1307 | return skb->len; |
1310 | 1308 | ||
1311 | rtattr_failure: | 1309 | rtattr_failure: |
1312 | nlmsg_failure: | 1310 | nlmsg_failure: |
1313 | skb_trim(skb, b - skb->data); | 1311 | skb_trim(skb, b - skb->data); |
1314 | return -1; | 1312 | return -1; |
1315 | } | 1313 | } |
1316 | 1314 | ||
1317 | static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1315 | static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1318 | { | 1316 | { |
1319 | struct xfrm_state *x; | 1317 | struct xfrm_state *x; |
1320 | struct sk_buff *r_skb; | 1318 | struct sk_buff *r_skb; |
1321 | int err; | 1319 | int err; |
1322 | struct km_event c; | 1320 | struct km_event c; |
1323 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | 1321 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); |
1324 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | 1322 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); |
1325 | struct xfrm_usersa_id *id = &p->sa_id; | 1323 | struct xfrm_usersa_id *id = &p->sa_id; |
1326 | 1324 | ||
1327 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | 1325 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); |
1328 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | 1326 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); |
1329 | 1327 | ||
1330 | if (p->flags&XFRM_AE_RTHR) | 1328 | if (p->flags&XFRM_AE_RTHR) |
1331 | len+=RTA_SPACE(sizeof(u32)); | 1329 | len+=RTA_SPACE(sizeof(u32)); |
1332 | 1330 | ||
1333 | if (p->flags&XFRM_AE_ETHR) | 1331 | if (p->flags&XFRM_AE_ETHR) |
1334 | len+=RTA_SPACE(sizeof(u32)); | 1332 | len+=RTA_SPACE(sizeof(u32)); |
1335 | 1333 | ||
1336 | r_skb = alloc_skb(len, GFP_ATOMIC); | 1334 | r_skb = alloc_skb(len, GFP_ATOMIC); |
1337 | if (r_skb == NULL) | 1335 | if (r_skb == NULL) |
1338 | return -ENOMEM; | 1336 | return -ENOMEM; |
1339 | 1337 | ||
1340 | x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); | 1338 | x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); |
1341 | if (x == NULL) { | 1339 | if (x == NULL) { |
1342 | kfree(r_skb); | 1340 | kfree(r_skb); |
1343 | return -ESRCH; | 1341 | return -ESRCH; |
1344 | } | 1342 | } |
1345 | 1343 | ||
1346 | /* | 1344 | /* |
1347 | * XXX: is this lock really needed - none of the other | 1345 | * XXX: is this lock really needed - none of the other |
1348 | * gets lock (the concern is things getting updated | 1346 | * gets lock (the concern is things getting updated |
1349 | * while we are still reading) - jhs | 1347 | * while we are still reading) - jhs |
1350 | */ | 1348 | */ |
1351 | spin_lock_bh(&x->lock); | 1349 | spin_lock_bh(&x->lock); |
1352 | c.data.aevent = p->flags; | 1350 | c.data.aevent = p->flags; |
1353 | c.seq = nlh->nlmsg_seq; | 1351 | c.seq = nlh->nlmsg_seq; |
1354 | c.pid = nlh->nlmsg_pid; | 1352 | c.pid = nlh->nlmsg_pid; |
1355 | 1353 | ||
1356 | if (build_aevent(r_skb, x, &c) < 0) | 1354 | if (build_aevent(r_skb, x, &c) < 0) |
1357 | BUG(); | 1355 | BUG(); |
1358 | err = netlink_unicast(xfrm_nl, r_skb, | 1356 | err = netlink_unicast(xfrm_nl, r_skb, |
1359 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | 1357 | NETLINK_CB(skb).pid, MSG_DONTWAIT); |
1360 | spin_unlock_bh(&x->lock); | 1358 | spin_unlock_bh(&x->lock); |
1361 | xfrm_state_put(x); | 1359 | xfrm_state_put(x); |
1362 | return err; | 1360 | return err; |
1363 | } | 1361 | } |
1364 | 1362 | ||
1365 | static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1363 | static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1366 | { | 1364 | { |
1367 | struct xfrm_state *x; | 1365 | struct xfrm_state *x; |
1368 | struct km_event c; | 1366 | struct km_event c; |
1369 | int err = - EINVAL; | 1367 | int err = - EINVAL; |
1370 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | 1368 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); |
1371 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | 1369 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; |
1372 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | 1370 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; |
1373 | 1371 | ||
1374 | if (!lt && !rp) | 1372 | if (!lt && !rp) |
1375 | return err; | 1373 | return err; |
1376 | 1374 | ||
1377 | /* pedantic mode - thou shalt sayeth replaceth */ | 1375 | /* pedantic mode - thou shalt sayeth replaceth */ |
1378 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | 1376 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) |
1379 | return err; | 1377 | return err; |
1380 | 1378 | ||
1381 | x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | 1379 | x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); |
1382 | if (x == NULL) | 1380 | if (x == NULL) |
1383 | return -ESRCH; | 1381 | return -ESRCH; |
1384 | 1382 | ||
1385 | if (x->km.state != XFRM_STATE_VALID) | 1383 | if (x->km.state != XFRM_STATE_VALID) |
1386 | goto out; | 1384 | goto out; |
1387 | 1385 | ||
1388 | spin_lock_bh(&x->lock); | 1386 | spin_lock_bh(&x->lock); |
1389 | err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); | 1387 | err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); |
1390 | spin_unlock_bh(&x->lock); | 1388 | spin_unlock_bh(&x->lock); |
1391 | if (err < 0) | 1389 | if (err < 0) |
1392 | goto out; | 1390 | goto out; |
1393 | 1391 | ||
1394 | c.event = nlh->nlmsg_type; | 1392 | c.event = nlh->nlmsg_type; |
1395 | c.seq = nlh->nlmsg_seq; | 1393 | c.seq = nlh->nlmsg_seq; |
1396 | c.pid = nlh->nlmsg_pid; | 1394 | c.pid = nlh->nlmsg_pid; |
1397 | c.data.aevent = XFRM_AE_CU; | 1395 | c.data.aevent = XFRM_AE_CU; |
1398 | km_state_notify(x, &c); | 1396 | km_state_notify(x, &c); |
1399 | err = 0; | 1397 | err = 0; |
1400 | out: | 1398 | out: |
1401 | xfrm_state_put(x); | 1399 | xfrm_state_put(x); |
1402 | return err; | 1400 | return err; |
1403 | } | 1401 | } |
1404 | 1402 | ||
1405 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1403 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1406 | { | 1404 | { |
1407 | struct km_event c; | 1405 | struct km_event c; |
1408 | __u8 type = XFRM_POLICY_TYPE_MAIN; | 1406 | __u8 type = XFRM_POLICY_TYPE_MAIN; |
1409 | int err; | 1407 | int err; |
1410 | 1408 | ||
1411 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | 1409 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); |
1412 | if (err) | 1410 | if (err) |
1413 | return err; | 1411 | return err; |
1414 | 1412 | ||
1415 | xfrm_policy_flush(type); | 1413 | xfrm_policy_flush(type); |
1416 | c.data.type = type; | 1414 | c.data.type = type; |
1417 | c.event = nlh->nlmsg_type; | 1415 | c.event = nlh->nlmsg_type; |
1418 | c.seq = nlh->nlmsg_seq; | 1416 | c.seq = nlh->nlmsg_seq; |
1419 | c.pid = nlh->nlmsg_pid; | 1417 | c.pid = nlh->nlmsg_pid; |
1420 | km_policy_notify(NULL, 0, &c); | 1418 | km_policy_notify(NULL, 0, &c); |
1421 | return 0; | 1419 | return 0; |
1422 | } | 1420 | } |
1423 | 1421 | ||
1424 | static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1422 | static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1425 | { | 1423 | { |
1426 | struct xfrm_policy *xp; | 1424 | struct xfrm_policy *xp; |
1427 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1425 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
1428 | struct xfrm_userpolicy_info *p = &up->pol; | 1426 | struct xfrm_userpolicy_info *p = &up->pol; |
1429 | __u8 type = XFRM_POLICY_TYPE_MAIN; | 1427 | __u8 type = XFRM_POLICY_TYPE_MAIN; |
1430 | int err = -ENOENT; | 1428 | int err = -ENOENT; |
1431 | 1429 | ||
1432 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | 1430 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); |
1433 | if (err) | 1431 | if (err) |
1434 | return err; | 1432 | return err; |
1435 | 1433 | ||
1436 | if (p->index) | 1434 | if (p->index) |
1437 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); | 1435 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
1438 | else { | 1436 | else { |
1439 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1437 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1440 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1438 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
1441 | struct xfrm_policy tmp; | 1439 | struct xfrm_policy tmp; |
1442 | 1440 | ||
1443 | err = verify_sec_ctx_len(rtattrs); | 1441 | err = verify_sec_ctx_len(rtattrs); |
1444 | if (err) | 1442 | if (err) |
1445 | return err; | 1443 | return err; |
1446 | 1444 | ||
1447 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | 1445 | memset(&tmp, 0, sizeof(struct xfrm_policy)); |
1448 | if (rt) { | 1446 | if (rt) { |
1449 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1447 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
1450 | 1448 | ||
1451 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1449 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1452 | return err; | 1450 | return err; |
1453 | } | 1451 | } |
1454 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); | 1452 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); |
1455 | security_xfrm_policy_free(&tmp); | 1453 | security_xfrm_policy_free(&tmp); |
1456 | } | 1454 | } |
1457 | 1455 | ||
1458 | if (xp == NULL) | 1456 | if (xp == NULL) |
1459 | return err; | 1457 | return err; |
1460 | read_lock(&xp->lock); | 1458 | read_lock(&xp->lock); |
1461 | if (xp->dead) { | 1459 | if (xp->dead) { |
1462 | read_unlock(&xp->lock); | 1460 | read_unlock(&xp->lock); |
1463 | goto out; | 1461 | goto out; |
1464 | } | 1462 | } |
1465 | 1463 | ||
1466 | read_unlock(&xp->lock); | 1464 | read_unlock(&xp->lock); |
1467 | err = 0; | 1465 | err = 0; |
1468 | if (up->hard) { | 1466 | if (up->hard) { |
1469 | xfrm_policy_delete(xp, p->dir); | 1467 | xfrm_policy_delete(xp, p->dir); |
1470 | } else { | 1468 | } else { |
1471 | // reset the timers here? | 1469 | // reset the timers here? |
1472 | printk("Dont know what to do with soft policy expire\n"); | 1470 | printk("Dont know what to do with soft policy expire\n"); |
1473 | } | 1471 | } |
1474 | km_policy_expired(xp, p->dir, up->hard, current->pid); | 1472 | km_policy_expired(xp, p->dir, up->hard, current->pid); |
1475 | 1473 | ||
1476 | out: | 1474 | out: |
1477 | xfrm_pol_put(xp); | 1475 | xfrm_pol_put(xp); |
1478 | return err; | 1476 | return err; |
1479 | } | 1477 | } |
1480 | 1478 | ||
1481 | static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1479 | static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1482 | { | 1480 | { |
1483 | struct xfrm_state *x; | 1481 | struct xfrm_state *x; |
1484 | int err; | 1482 | int err; |
1485 | struct xfrm_user_expire *ue = NLMSG_DATA(nlh); | 1483 | struct xfrm_user_expire *ue = NLMSG_DATA(nlh); |
1486 | struct xfrm_usersa_info *p = &ue->state; | 1484 | struct xfrm_usersa_info *p = &ue->state; |
1487 | 1485 | ||
1488 | x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); | 1486 | x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); |
1489 | err = -ENOENT; | 1487 | err = -ENOENT; |
1490 | 1488 | ||
1491 | if (x == NULL) | 1489 | if (x == NULL) |
1492 | return err; | 1490 | return err; |
1493 | 1491 | ||
1494 | err = -EINVAL; | 1492 | err = -EINVAL; |
1495 | 1493 | ||
1496 | spin_lock_bh(&x->lock); | 1494 | spin_lock_bh(&x->lock); |
1497 | if (x->km.state != XFRM_STATE_VALID) | 1495 | if (x->km.state != XFRM_STATE_VALID) |
1498 | goto out; | 1496 | goto out; |
1499 | km_state_expired(x, ue->hard, current->pid); | 1497 | km_state_expired(x, ue->hard, current->pid); |
1500 | 1498 | ||
1501 | if (ue->hard) | 1499 | if (ue->hard) |
1502 | __xfrm_state_delete(x); | 1500 | __xfrm_state_delete(x); |
1503 | out: | 1501 | out: |
1504 | spin_unlock_bh(&x->lock); | 1502 | spin_unlock_bh(&x->lock); |
1505 | xfrm_state_put(x); | 1503 | xfrm_state_put(x); |
1506 | return err; | 1504 | return err; |
1507 | } | 1505 | } |
1508 | 1506 | ||
1509 | static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1507 | static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1510 | { | 1508 | { |
1511 | struct xfrm_policy *xp; | 1509 | struct xfrm_policy *xp; |
1512 | struct xfrm_user_tmpl *ut; | 1510 | struct xfrm_user_tmpl *ut; |
1513 | int i; | 1511 | int i; |
1514 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | 1512 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; |
1515 | 1513 | ||
1516 | struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); | 1514 | struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); |
1517 | struct xfrm_state *x = xfrm_state_alloc(); | 1515 | struct xfrm_state *x = xfrm_state_alloc(); |
1518 | int err = -ENOMEM; | 1516 | int err = -ENOMEM; |
1519 | 1517 | ||
1520 | if (!x) | 1518 | if (!x) |
1521 | return err; | 1519 | return err; |
1522 | 1520 | ||
1523 | err = verify_newpolicy_info(&ua->policy); | 1521 | err = verify_newpolicy_info(&ua->policy); |
1524 | if (err) { | 1522 | if (err) { |
1525 | printk("BAD policy passed\n"); | 1523 | printk("BAD policy passed\n"); |
1526 | kfree(x); | 1524 | kfree(x); |
1527 | return err; | 1525 | return err; |
1528 | } | 1526 | } |
1529 | 1527 | ||
1530 | /* build an XP */ | 1528 | /* build an XP */ |
1531 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | 1529 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { |
1532 | kfree(x); | 1530 | kfree(x); |
1533 | return err; | 1531 | return err; |
1534 | } | 1532 | } |
1535 | 1533 | ||
1536 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | 1534 | memcpy(&x->id, &ua->id, sizeof(ua->id)); |
1537 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | 1535 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); |
1538 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | 1536 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); |
1539 | 1537 | ||
1540 | ut = RTA_DATA(rt); | 1538 | ut = RTA_DATA(rt); |
1541 | /* extract the templates and for each call km_key */ | 1539 | /* extract the templates and for each call km_key */ |
1542 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | 1540 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { |
1543 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | 1541 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; |
1544 | memcpy(&x->id, &t->id, sizeof(x->id)); | 1542 | memcpy(&x->id, &t->id, sizeof(x->id)); |
1545 | x->props.mode = t->mode; | 1543 | x->props.mode = t->mode; |
1546 | x->props.reqid = t->reqid; | 1544 | x->props.reqid = t->reqid; |
1547 | x->props.family = ut->family; | 1545 | x->props.family = ut->family; |
1548 | t->aalgos = ua->aalgos; | 1546 | t->aalgos = ua->aalgos; |
1549 | t->ealgos = ua->ealgos; | 1547 | t->ealgos = ua->ealgos; |
1550 | t->calgos = ua->calgos; | 1548 | t->calgos = ua->calgos; |
1551 | err = km_query(x, t, xp); | 1549 | err = km_query(x, t, xp); |
1552 | 1550 | ||
1553 | } | 1551 | } |
1554 | 1552 | ||
1555 | kfree(x); | 1553 | kfree(x); |
1556 | kfree(xp); | 1554 | kfree(xp); |
1557 | 1555 | ||
1558 | return 0; | 1556 | return 0; |
1559 | } | 1557 | } |
1560 | 1558 | ||
1561 | 1559 | ||
1562 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) | 1560 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) |
1563 | 1561 | ||
1564 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | 1562 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { |
1565 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), | 1563 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), |
1566 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), | 1564 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), |
1567 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), | 1565 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), |
1568 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), | 1566 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), |
1569 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), | 1567 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), |
1570 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), | 1568 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), |
1571 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), | 1569 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), |
1572 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), | 1570 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), |
1573 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), | 1571 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), |
1574 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), | 1572 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), |
1575 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), | 1573 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), |
1576 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), | 1574 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), |
1577 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), | 1575 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), |
1578 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1576 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1579 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1577 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1580 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1578 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1581 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), | 1579 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), |
1582 | }; | 1580 | }; |
1583 | 1581 | ||
1584 | #undef XMSGSIZE | 1582 | #undef XMSGSIZE |
1585 | 1583 | ||
1586 | static struct xfrm_link { | 1584 | static struct xfrm_link { |
1587 | int (*doit)(struct sk_buff *, struct nlmsghdr *, void **); | 1585 | int (*doit)(struct sk_buff *, struct nlmsghdr *, void **); |
1588 | int (*dump)(struct sk_buff *, struct netlink_callback *); | 1586 | int (*dump)(struct sk_buff *, struct netlink_callback *); |
1589 | } xfrm_dispatch[XFRM_NR_MSGTYPES] = { | 1587 | } xfrm_dispatch[XFRM_NR_MSGTYPES] = { |
1590 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1588 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1591 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, | 1589 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, |
1592 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, | 1590 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, |
1593 | .dump = xfrm_dump_sa }, | 1591 | .dump = xfrm_dump_sa }, |
1594 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1592 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1595 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, | 1593 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, |
1596 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 1594 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
1597 | .dump = xfrm_dump_policy }, | 1595 | .dump = xfrm_dump_policy }, |
1598 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 1596 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
1599 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, | 1597 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, |
1600 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, | 1598 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, |
1601 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1599 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1602 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1600 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1603 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, | 1601 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, |
1604 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, | 1602 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, |
1605 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 1603 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
1606 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, | 1604 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, |
1607 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, | 1605 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, |
1608 | }; | 1606 | }; |
1609 | 1607 | ||
1610 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1608 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
1611 | { | 1609 | { |
1612 | struct rtattr *xfrma[XFRMA_MAX]; | 1610 | struct rtattr *xfrma[XFRMA_MAX]; |
1613 | struct xfrm_link *link; | 1611 | struct xfrm_link *link; |
1614 | int type, min_len; | 1612 | int type, min_len; |
1615 | 1613 | ||
1616 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) | 1614 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) |
1617 | return 0; | 1615 | return 0; |
1618 | 1616 | ||
1619 | type = nlh->nlmsg_type; | 1617 | type = nlh->nlmsg_type; |
1620 | 1618 | ||
1621 | /* A control message: ignore them */ | 1619 | /* A control message: ignore them */ |
1622 | if (type < XFRM_MSG_BASE) | 1620 | if (type < XFRM_MSG_BASE) |
1623 | return 0; | 1621 | return 0; |
1624 | 1622 | ||
1625 | /* Unknown message: reply with EINVAL */ | 1623 | /* Unknown message: reply with EINVAL */ |
1626 | if (type > XFRM_MSG_MAX) | 1624 | if (type > XFRM_MSG_MAX) |
1627 | goto err_einval; | 1625 | goto err_einval; |
1628 | 1626 | ||
1629 | type -= XFRM_MSG_BASE; | 1627 | type -= XFRM_MSG_BASE; |
1630 | link = &xfrm_dispatch[type]; | 1628 | link = &xfrm_dispatch[type]; |
1631 | 1629 | ||
1632 | /* All operations require privileges, even GET */ | 1630 | /* All operations require privileges, even GET */ |
1633 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) { | 1631 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) { |
1634 | *errp = -EPERM; | 1632 | *errp = -EPERM; |
1635 | return -1; | 1633 | return -1; |
1636 | } | 1634 | } |
1637 | 1635 | ||
1638 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || | 1636 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || |
1639 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && | 1637 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && |
1640 | (nlh->nlmsg_flags & NLM_F_DUMP)) { | 1638 | (nlh->nlmsg_flags & NLM_F_DUMP)) { |
1641 | if (link->dump == NULL) | 1639 | if (link->dump == NULL) |
1642 | goto err_einval; | 1640 | goto err_einval; |
1643 | 1641 | ||
1644 | if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, | 1642 | if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, |
1645 | link->dump, NULL)) != 0) { | 1643 | link->dump, NULL)) != 0) { |
1646 | return -1; | 1644 | return -1; |
1647 | } | 1645 | } |
1648 | 1646 | ||
1649 | netlink_queue_skip(nlh, skb); | 1647 | netlink_queue_skip(nlh, skb); |
1650 | return -1; | 1648 | return -1; |
1651 | } | 1649 | } |
1652 | 1650 | ||
1653 | memset(xfrma, 0, sizeof(xfrma)); | 1651 | memset(xfrma, 0, sizeof(xfrma)); |
1654 | 1652 | ||
1655 | if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) | 1653 | if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) |
1656 | goto err_einval; | 1654 | goto err_einval; |
1657 | 1655 | ||
1658 | if (nlh->nlmsg_len > min_len) { | 1656 | if (nlh->nlmsg_len > min_len) { |
1659 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); | 1657 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); |
1660 | struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len); | 1658 | struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len); |
1661 | 1659 | ||
1662 | while (RTA_OK(attr, attrlen)) { | 1660 | while (RTA_OK(attr, attrlen)) { |
1663 | unsigned short flavor = attr->rta_type; | 1661 | unsigned short flavor = attr->rta_type; |
1664 | if (flavor) { | 1662 | if (flavor) { |
1665 | if (flavor > XFRMA_MAX) | 1663 | if (flavor > XFRMA_MAX) |
1666 | goto err_einval; | 1664 | goto err_einval; |
1667 | xfrma[flavor - 1] = attr; | 1665 | xfrma[flavor - 1] = attr; |
1668 | } | 1666 | } |
1669 | attr = RTA_NEXT(attr, attrlen); | 1667 | attr = RTA_NEXT(attr, attrlen); |
1670 | } | 1668 | } |
1671 | } | 1669 | } |
1672 | 1670 | ||
1673 | if (link->doit == NULL) | 1671 | if (link->doit == NULL) |
1674 | goto err_einval; | 1672 | goto err_einval; |
1675 | *errp = link->doit(skb, nlh, (void **) &xfrma); | 1673 | *errp = link->doit(skb, nlh, (void **) &xfrma); |
1676 | 1674 | ||
1677 | return *errp; | 1675 | return *errp; |
1678 | 1676 | ||
1679 | err_einval: | 1677 | err_einval: |
1680 | *errp = -EINVAL; | 1678 | *errp = -EINVAL; |
1681 | return -1; | 1679 | return -1; |
1682 | } | 1680 | } |
1683 | 1681 | ||
1684 | static void xfrm_netlink_rcv(struct sock *sk, int len) | 1682 | static void xfrm_netlink_rcv(struct sock *sk, int len) |
1685 | { | 1683 | { |
1686 | unsigned int qlen = 0; | 1684 | unsigned int qlen = 0; |
1687 | 1685 | ||
1688 | do { | 1686 | do { |
1689 | mutex_lock(&xfrm_cfg_mutex); | 1687 | mutex_lock(&xfrm_cfg_mutex); |
1690 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); | 1688 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); |
1691 | mutex_unlock(&xfrm_cfg_mutex); | 1689 | mutex_unlock(&xfrm_cfg_mutex); |
1692 | 1690 | ||
1693 | } while (qlen); | 1691 | } while (qlen); |
1694 | } | 1692 | } |
1695 | 1693 | ||
1696 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | 1694 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
1697 | { | 1695 | { |
1698 | struct xfrm_user_expire *ue; | 1696 | struct xfrm_user_expire *ue; |
1699 | struct nlmsghdr *nlh; | 1697 | struct nlmsghdr *nlh; |
1700 | unsigned char *b = skb->tail; | 1698 | unsigned char *b = skb->tail; |
1701 | 1699 | ||
1702 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, | 1700 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, |
1703 | sizeof(*ue)); | 1701 | sizeof(*ue)); |
1704 | ue = NLMSG_DATA(nlh); | 1702 | ue = NLMSG_DATA(nlh); |
1705 | nlh->nlmsg_flags = 0; | 1703 | nlh->nlmsg_flags = 0; |
1706 | 1704 | ||
1707 | copy_to_user_state(x, &ue->state); | 1705 | copy_to_user_state(x, &ue->state); |
1708 | ue->hard = (c->data.hard != 0) ? 1 : 0; | 1706 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
1709 | 1707 | ||
1710 | nlh->nlmsg_len = skb->tail - b; | 1708 | nlh->nlmsg_len = skb->tail - b; |
1711 | return skb->len; | 1709 | return skb->len; |
1712 | 1710 | ||
1713 | nlmsg_failure: | 1711 | nlmsg_failure: |
1714 | skb_trim(skb, b - skb->data); | 1712 | skb_trim(skb, b - skb->data); |
1715 | return -1; | 1713 | return -1; |
1716 | } | 1714 | } |
1717 | 1715 | ||
1718 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | 1716 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) |
1719 | { | 1717 | { |
1720 | struct sk_buff *skb; | 1718 | struct sk_buff *skb; |
1721 | int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire)); | 1719 | int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire)); |
1722 | 1720 | ||
1723 | skb = alloc_skb(len, GFP_ATOMIC); | 1721 | skb = alloc_skb(len, GFP_ATOMIC); |
1724 | if (skb == NULL) | 1722 | if (skb == NULL) |
1725 | return -ENOMEM; | 1723 | return -ENOMEM; |
1726 | 1724 | ||
1727 | if (build_expire(skb, x, c) < 0) | 1725 | if (build_expire(skb, x, c) < 0) |
1728 | BUG(); | 1726 | BUG(); |
1729 | 1727 | ||
1730 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1728 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
1731 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 1729 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
1732 | } | 1730 | } |
1733 | 1731 | ||
1734 | static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) | 1732 | static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) |
1735 | { | 1733 | { |
1736 | struct sk_buff *skb; | 1734 | struct sk_buff *skb; |
1737 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | 1735 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); |
1738 | 1736 | ||
1739 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | 1737 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); |
1740 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | 1738 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); |
1741 | skb = alloc_skb(len, GFP_ATOMIC); | 1739 | skb = alloc_skb(len, GFP_ATOMIC); |
1742 | if (skb == NULL) | 1740 | if (skb == NULL) |
1743 | return -ENOMEM; | 1741 | return -ENOMEM; |
1744 | 1742 | ||
1745 | if (build_aevent(skb, x, c) < 0) | 1743 | if (build_aevent(skb, x, c) < 0) |
1746 | BUG(); | 1744 | BUG(); |
1747 | 1745 | ||
1748 | NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; | 1746 | NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; |
1749 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); | 1747 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); |
1750 | } | 1748 | } |
1751 | 1749 | ||
1752 | static int xfrm_notify_sa_flush(struct km_event *c) | 1750 | static int xfrm_notify_sa_flush(struct km_event *c) |
1753 | { | 1751 | { |
1754 | struct xfrm_usersa_flush *p; | 1752 | struct xfrm_usersa_flush *p; |
1755 | struct nlmsghdr *nlh; | 1753 | struct nlmsghdr *nlh; |
1756 | struct sk_buff *skb; | 1754 | struct sk_buff *skb; |
1757 | unsigned char *b; | 1755 | unsigned char *b; |
1758 | int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); | 1756 | int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); |
1759 | 1757 | ||
1760 | skb = alloc_skb(len, GFP_ATOMIC); | 1758 | skb = alloc_skb(len, GFP_ATOMIC); |
1761 | if (skb == NULL) | 1759 | if (skb == NULL) |
1762 | return -ENOMEM; | 1760 | return -ENOMEM; |
1763 | b = skb->tail; | 1761 | b = skb->tail; |
1764 | 1762 | ||
1765 | nlh = NLMSG_PUT(skb, c->pid, c->seq, | 1763 | nlh = NLMSG_PUT(skb, c->pid, c->seq, |
1766 | XFRM_MSG_FLUSHSA, sizeof(*p)); | 1764 | XFRM_MSG_FLUSHSA, sizeof(*p)); |
1767 | nlh->nlmsg_flags = 0; | 1765 | nlh->nlmsg_flags = 0; |
1768 | 1766 | ||
1769 | p = NLMSG_DATA(nlh); | 1767 | p = NLMSG_DATA(nlh); |
1770 | p->proto = c->data.proto; | 1768 | p->proto = c->data.proto; |
1771 | 1769 | ||
1772 | nlh->nlmsg_len = skb->tail - b; | 1770 | nlh->nlmsg_len = skb->tail - b; |
1773 | 1771 | ||
1774 | NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; | 1772 | NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; |
1775 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); | 1773 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); |
1776 | 1774 | ||
1777 | nlmsg_failure: | 1775 | nlmsg_failure: |
1778 | kfree_skb(skb); | 1776 | kfree_skb(skb); |
1779 | return -1; | 1777 | return -1; |
1780 | } | 1778 | } |
1781 | 1779 | ||
1782 | static int inline xfrm_sa_len(struct xfrm_state *x) | 1780 | static int inline xfrm_sa_len(struct xfrm_state *x) |
1783 | { | 1781 | { |
1784 | int l = 0; | 1782 | int l = 0; |
1785 | if (x->aalg) | 1783 | if (x->aalg) |
1786 | l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); | 1784 | l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); |
1787 | if (x->ealg) | 1785 | if (x->ealg) |
1788 | l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8); | 1786 | l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8); |
1789 | if (x->calg) | 1787 | if (x->calg) |
1790 | l += RTA_SPACE(sizeof(*x->calg)); | 1788 | l += RTA_SPACE(sizeof(*x->calg)); |
1791 | if (x->encap) | 1789 | if (x->encap) |
1792 | l += RTA_SPACE(sizeof(*x->encap)); | 1790 | l += RTA_SPACE(sizeof(*x->encap)); |
1793 | 1791 | ||
1794 | return l; | 1792 | return l; |
1795 | } | 1793 | } |
1796 | 1794 | ||
1797 | static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) | 1795 | static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) |
1798 | { | 1796 | { |
1799 | struct xfrm_usersa_info *p; | 1797 | struct xfrm_usersa_info *p; |
1800 | struct xfrm_usersa_id *id; | 1798 | struct xfrm_usersa_id *id; |
1801 | struct nlmsghdr *nlh; | 1799 | struct nlmsghdr *nlh; |
1802 | struct sk_buff *skb; | 1800 | struct sk_buff *skb; |
1803 | unsigned char *b; | 1801 | unsigned char *b; |
1804 | int len = xfrm_sa_len(x); | 1802 | int len = xfrm_sa_len(x); |
1805 | int headlen; | 1803 | int headlen; |
1806 | 1804 | ||
1807 | headlen = sizeof(*p); | 1805 | headlen = sizeof(*p); |
1808 | if (c->event == XFRM_MSG_DELSA) { | 1806 | if (c->event == XFRM_MSG_DELSA) { |
1809 | len += RTA_SPACE(headlen); | 1807 | len += RTA_SPACE(headlen); |
1810 | headlen = sizeof(*id); | 1808 | headlen = sizeof(*id); |
1811 | } | 1809 | } |
1812 | len += NLMSG_SPACE(headlen); | 1810 | len += NLMSG_SPACE(headlen); |
1813 | 1811 | ||
1814 | skb = alloc_skb(len, GFP_ATOMIC); | 1812 | skb = alloc_skb(len, GFP_ATOMIC); |
1815 | if (skb == NULL) | 1813 | if (skb == NULL) |
1816 | return -ENOMEM; | 1814 | return -ENOMEM; |
1817 | b = skb->tail; | 1815 | b = skb->tail; |
1818 | 1816 | ||
1819 | nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); | 1817 | nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); |
1820 | nlh->nlmsg_flags = 0; | 1818 | nlh->nlmsg_flags = 0; |
1821 | 1819 | ||
1822 | p = NLMSG_DATA(nlh); | 1820 | p = NLMSG_DATA(nlh); |
1823 | if (c->event == XFRM_MSG_DELSA) { | 1821 | if (c->event == XFRM_MSG_DELSA) { |
1824 | id = NLMSG_DATA(nlh); | 1822 | id = NLMSG_DATA(nlh); |
1825 | memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); | 1823 | memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); |
1826 | id->spi = x->id.spi; | 1824 | id->spi = x->id.spi; |
1827 | id->family = x->props.family; | 1825 | id->family = x->props.family; |
1828 | id->proto = x->id.proto; | 1826 | id->proto = x->id.proto; |
1829 | 1827 | ||
1830 | p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p))); | 1828 | p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p))); |
1831 | } | 1829 | } |
1832 | 1830 | ||
1833 | copy_to_user_state(x, p); | 1831 | copy_to_user_state(x, p); |
1834 | 1832 | ||
1835 | if (x->aalg) | 1833 | if (x->aalg) |
1836 | RTA_PUT(skb, XFRMA_ALG_AUTH, | 1834 | RTA_PUT(skb, XFRMA_ALG_AUTH, |
1837 | sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); | 1835 | sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); |
1838 | if (x->ealg) | 1836 | if (x->ealg) |
1839 | RTA_PUT(skb, XFRMA_ALG_CRYPT, | 1837 | RTA_PUT(skb, XFRMA_ALG_CRYPT, |
1840 | sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); | 1838 | sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); |
1841 | if (x->calg) | 1839 | if (x->calg) |
1842 | RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); | 1840 | RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); |
1843 | 1841 | ||
1844 | if (x->encap) | 1842 | if (x->encap) |
1845 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 1843 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
1846 | 1844 | ||
1847 | nlh->nlmsg_len = skb->tail - b; | 1845 | nlh->nlmsg_len = skb->tail - b; |
1848 | 1846 | ||
1849 | NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; | 1847 | NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; |
1850 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); | 1848 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); |
1851 | 1849 | ||
1852 | nlmsg_failure: | 1850 | nlmsg_failure: |
1853 | rtattr_failure: | 1851 | rtattr_failure: |
1854 | kfree_skb(skb); | 1852 | kfree_skb(skb); |
1855 | return -1; | 1853 | return -1; |
1856 | } | 1854 | } |
1857 | 1855 | ||
1858 | static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) | 1856 | static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) |
1859 | { | 1857 | { |
1860 | 1858 | ||
1861 | switch (c->event) { | 1859 | switch (c->event) { |
1862 | case XFRM_MSG_EXPIRE: | 1860 | case XFRM_MSG_EXPIRE: |
1863 | return xfrm_exp_state_notify(x, c); | 1861 | return xfrm_exp_state_notify(x, c); |
1864 | case XFRM_MSG_NEWAE: | 1862 | case XFRM_MSG_NEWAE: |
1865 | return xfrm_aevent_state_notify(x, c); | 1863 | return xfrm_aevent_state_notify(x, c); |
1866 | case XFRM_MSG_DELSA: | 1864 | case XFRM_MSG_DELSA: |
1867 | case XFRM_MSG_UPDSA: | 1865 | case XFRM_MSG_UPDSA: |
1868 | case XFRM_MSG_NEWSA: | 1866 | case XFRM_MSG_NEWSA: |
1869 | return xfrm_notify_sa(x, c); | 1867 | return xfrm_notify_sa(x, c); |
1870 | case XFRM_MSG_FLUSHSA: | 1868 | case XFRM_MSG_FLUSHSA: |
1871 | return xfrm_notify_sa_flush(c); | 1869 | return xfrm_notify_sa_flush(c); |
1872 | default: | 1870 | default: |
1873 | printk("xfrm_user: Unknown SA event %d\n", c->event); | 1871 | printk("xfrm_user: Unknown SA event %d\n", c->event); |
1874 | break; | 1872 | break; |
1875 | } | 1873 | } |
1876 | 1874 | ||
1877 | return 0; | 1875 | return 0; |
1878 | 1876 | ||
1879 | } | 1877 | } |
1880 | 1878 | ||
1881 | static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | 1879 | static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, |
1882 | struct xfrm_tmpl *xt, struct xfrm_policy *xp, | 1880 | struct xfrm_tmpl *xt, struct xfrm_policy *xp, |
1883 | int dir) | 1881 | int dir) |
1884 | { | 1882 | { |
1885 | struct xfrm_user_acquire *ua; | 1883 | struct xfrm_user_acquire *ua; |
1886 | struct nlmsghdr *nlh; | 1884 | struct nlmsghdr *nlh; |
1887 | unsigned char *b = skb->tail; | 1885 | unsigned char *b = skb->tail; |
1888 | __u32 seq = xfrm_get_acqseq(); | 1886 | __u32 seq = xfrm_get_acqseq(); |
1889 | 1887 | ||
1890 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, | 1888 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, |
1891 | sizeof(*ua)); | 1889 | sizeof(*ua)); |
1892 | ua = NLMSG_DATA(nlh); | 1890 | ua = NLMSG_DATA(nlh); |
1893 | nlh->nlmsg_flags = 0; | 1891 | nlh->nlmsg_flags = 0; |
1894 | 1892 | ||
1895 | memcpy(&ua->id, &x->id, sizeof(ua->id)); | 1893 | memcpy(&ua->id, &x->id, sizeof(ua->id)); |
1896 | memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); | 1894 | memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); |
1897 | memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); | 1895 | memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); |
1898 | copy_to_user_policy(xp, &ua->policy, dir); | 1896 | copy_to_user_policy(xp, &ua->policy, dir); |
1899 | ua->aalgos = xt->aalgos; | 1897 | ua->aalgos = xt->aalgos; |
1900 | ua->ealgos = xt->ealgos; | 1898 | ua->ealgos = xt->ealgos; |
1901 | ua->calgos = xt->calgos; | 1899 | ua->calgos = xt->calgos; |
1902 | ua->seq = x->km.seq = seq; | 1900 | ua->seq = x->km.seq = seq; |
1903 | 1901 | ||
1904 | if (copy_to_user_tmpl(xp, skb) < 0) | 1902 | if (copy_to_user_tmpl(xp, skb) < 0) |
1905 | goto nlmsg_failure; | 1903 | goto nlmsg_failure; |
1906 | if (copy_to_user_state_sec_ctx(x, skb)) | 1904 | if (copy_to_user_state_sec_ctx(x, skb)) |
1907 | goto nlmsg_failure; | 1905 | goto nlmsg_failure; |
1908 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 1906 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
1909 | goto nlmsg_failure; | 1907 | goto nlmsg_failure; |
1910 | 1908 | ||
1911 | nlh->nlmsg_len = skb->tail - b; | 1909 | nlh->nlmsg_len = skb->tail - b; |
1912 | return skb->len; | 1910 | return skb->len; |
1913 | 1911 | ||
1914 | nlmsg_failure: | 1912 | nlmsg_failure: |
1915 | skb_trim(skb, b - skb->data); | 1913 | skb_trim(skb, b - skb->data); |
1916 | return -1; | 1914 | return -1; |
1917 | } | 1915 | } |
1918 | 1916 | ||
1919 | static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | 1917 | static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, |
1920 | struct xfrm_policy *xp, int dir) | 1918 | struct xfrm_policy *xp, int dir) |
1921 | { | 1919 | { |
1922 | struct sk_buff *skb; | 1920 | struct sk_buff *skb; |
1923 | size_t len; | 1921 | size_t len; |
1924 | 1922 | ||
1925 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1923 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
1926 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); | 1924 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); |
1927 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | 1925 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); |
1928 | #ifdef CONFIG_XFRM_SUB_POLICY | 1926 | #ifdef CONFIG_XFRM_SUB_POLICY |
1929 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); | 1927 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); |
1930 | #endif | 1928 | #endif |
1931 | skb = alloc_skb(len, GFP_ATOMIC); | 1929 | skb = alloc_skb(len, GFP_ATOMIC); |
1932 | if (skb == NULL) | 1930 | if (skb == NULL) |
1933 | return -ENOMEM; | 1931 | return -ENOMEM; |
1934 | 1932 | ||
1935 | if (build_acquire(skb, x, xt, xp, dir) < 0) | 1933 | if (build_acquire(skb, x, xt, xp, dir) < 0) |
1936 | BUG(); | 1934 | BUG(); |
1937 | 1935 | ||
1938 | NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE; | 1936 | NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE; |
1939 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); | 1937 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); |
1940 | } | 1938 | } |
1941 | 1939 | ||
1942 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 1940 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
1943 | * or more templates. | 1941 | * or more templates. |
1944 | */ | 1942 | */ |
1945 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, | 1943 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
1946 | u8 *data, int len, int *dir) | 1944 | u8 *data, int len, int *dir) |
1947 | { | 1945 | { |
1948 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1946 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
1949 | struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); | 1947 | struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); |
1950 | struct xfrm_policy *xp; | 1948 | struct xfrm_policy *xp; |
1951 | int nr; | 1949 | int nr; |
1952 | 1950 | ||
1953 | switch (sk->sk_family) { | 1951 | switch (sk->sk_family) { |
1954 | case AF_INET: | 1952 | case AF_INET: |
1955 | if (opt != IP_XFRM_POLICY) { | 1953 | if (opt != IP_XFRM_POLICY) { |
1956 | *dir = -EOPNOTSUPP; | 1954 | *dir = -EOPNOTSUPP; |
1957 | return NULL; | 1955 | return NULL; |
1958 | } | 1956 | } |
1959 | break; | 1957 | break; |
1960 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 1958 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1961 | case AF_INET6: | 1959 | case AF_INET6: |
1962 | if (opt != IPV6_XFRM_POLICY) { | 1960 | if (opt != IPV6_XFRM_POLICY) { |
1963 | *dir = -EOPNOTSUPP; | 1961 | *dir = -EOPNOTSUPP; |
1964 | return NULL; | 1962 | return NULL; |
1965 | } | 1963 | } |
1966 | break; | 1964 | break; |
1967 | #endif | 1965 | #endif |
1968 | default: | 1966 | default: |
1969 | *dir = -EINVAL; | 1967 | *dir = -EINVAL; |
1970 | return NULL; | 1968 | return NULL; |
1971 | } | 1969 | } |
1972 | 1970 | ||
1973 | *dir = -EINVAL; | 1971 | *dir = -EINVAL; |
1974 | 1972 | ||
1975 | if (len < sizeof(*p) || | 1973 | if (len < sizeof(*p) || |
1976 | verify_newpolicy_info(p)) | 1974 | verify_newpolicy_info(p)) |
1977 | return NULL; | 1975 | return NULL; |
1978 | 1976 | ||
1979 | nr = ((len - sizeof(*p)) / sizeof(*ut)); | 1977 | nr = ((len - sizeof(*p)) / sizeof(*ut)); |
1980 | if (nr > XFRM_MAX_DEPTH) | 1978 | if (nr > XFRM_MAX_DEPTH) |
1981 | return NULL; | 1979 | return NULL; |
1982 | 1980 | ||
1983 | if (p->dir > XFRM_POLICY_OUT) | 1981 | if (p->dir > XFRM_POLICY_OUT) |
1984 | return NULL; | 1982 | return NULL; |
1985 | 1983 | ||
1986 | xp = xfrm_policy_alloc(GFP_KERNEL); | 1984 | xp = xfrm_policy_alloc(GFP_KERNEL); |
1987 | if (xp == NULL) { | 1985 | if (xp == NULL) { |
1988 | *dir = -ENOBUFS; | 1986 | *dir = -ENOBUFS; |
1989 | return NULL; | 1987 | return NULL; |
1990 | } | 1988 | } |
1991 | 1989 | ||
1992 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
1993 | xp->type = XFRM_POLICY_TYPE_MAIN; | 1991 | xp->type = XFRM_POLICY_TYPE_MAIN; |
1994 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
1995 | 1993 | ||
1996 | *dir = p->dir; | 1994 | *dir = p->dir; |
1997 | 1995 | ||
1998 | return xp; | 1996 | return xp; |
1999 | } | 1997 | } |
2000 | 1998 | ||
2001 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | 1999 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, |
2002 | int dir, struct km_event *c) | 2000 | int dir, struct km_event *c) |
2003 | { | 2001 | { |
2004 | struct xfrm_user_polexpire *upe; | 2002 | struct xfrm_user_polexpire *upe; |
2005 | struct nlmsghdr *nlh; | 2003 | struct nlmsghdr *nlh; |
2006 | int hard = c->data.hard; | 2004 | int hard = c->data.hard; |
2007 | unsigned char *b = skb->tail; | 2005 | unsigned char *b = skb->tail; |
2008 | 2006 | ||
2009 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); | 2007 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); |
2010 | upe = NLMSG_DATA(nlh); | 2008 | upe = NLMSG_DATA(nlh); |
2011 | nlh->nlmsg_flags = 0; | 2009 | nlh->nlmsg_flags = 0; |
2012 | 2010 | ||
2013 | copy_to_user_policy(xp, &upe->pol, dir); | 2011 | copy_to_user_policy(xp, &upe->pol, dir); |
2014 | if (copy_to_user_tmpl(xp, skb) < 0) | 2012 | if (copy_to_user_tmpl(xp, skb) < 0) |
2015 | goto nlmsg_failure; | 2013 | goto nlmsg_failure; |
2016 | if (copy_to_user_sec_ctx(xp, skb)) | 2014 | if (copy_to_user_sec_ctx(xp, skb)) |
2017 | goto nlmsg_failure; | 2015 | goto nlmsg_failure; |
2018 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2016 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2019 | goto nlmsg_failure; | 2017 | goto nlmsg_failure; |
2020 | upe->hard = !!hard; | 2018 | upe->hard = !!hard; |
2021 | 2019 | ||
2022 | nlh->nlmsg_len = skb->tail - b; | 2020 | nlh->nlmsg_len = skb->tail - b; |
2023 | return skb->len; | 2021 | return skb->len; |
2024 | 2022 | ||
2025 | nlmsg_failure: | 2023 | nlmsg_failure: |
2026 | skb_trim(skb, b - skb->data); | 2024 | skb_trim(skb, b - skb->data); |
2027 | return -1; | 2025 | return -1; |
2028 | } | 2026 | } |
2029 | 2027 | ||
2030 | static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) | 2028 | static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
2031 | { | 2029 | { |
2032 | struct sk_buff *skb; | 2030 | struct sk_buff *skb; |
2033 | size_t len; | 2031 | size_t len; |
2034 | 2032 | ||
2035 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 2033 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
2036 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); | 2034 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); |
2037 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | 2035 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); |
2038 | #ifdef CONFIG_XFRM_SUB_POLICY | 2036 | #ifdef CONFIG_XFRM_SUB_POLICY |
2039 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); | 2037 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); |
2040 | #endif | 2038 | #endif |
2041 | skb = alloc_skb(len, GFP_ATOMIC); | 2039 | skb = alloc_skb(len, GFP_ATOMIC); |
2042 | if (skb == NULL) | 2040 | if (skb == NULL) |
2043 | return -ENOMEM; | 2041 | return -ENOMEM; |
2044 | 2042 | ||
2045 | if (build_polexpire(skb, xp, dir, c) < 0) | 2043 | if (build_polexpire(skb, xp, dir, c) < 0) |
2046 | BUG(); | 2044 | BUG(); |
2047 | 2045 | ||
2048 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 2046 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
2049 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2047 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
2050 | } | 2048 | } |
2051 | 2049 | ||
2052 | static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) | 2050 | static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) |
2053 | { | 2051 | { |
2054 | struct xfrm_userpolicy_info *p; | 2052 | struct xfrm_userpolicy_info *p; |
2055 | struct xfrm_userpolicy_id *id; | 2053 | struct xfrm_userpolicy_id *id; |
2056 | struct nlmsghdr *nlh; | 2054 | struct nlmsghdr *nlh; |
2057 | struct sk_buff *skb; | 2055 | struct sk_buff *skb; |
2058 | unsigned char *b; | 2056 | unsigned char *b; |
2059 | int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 2057 | int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
2060 | int headlen; | 2058 | int headlen; |
2061 | 2059 | ||
2062 | headlen = sizeof(*p); | 2060 | headlen = sizeof(*p); |
2063 | if (c->event == XFRM_MSG_DELPOLICY) { | 2061 | if (c->event == XFRM_MSG_DELPOLICY) { |
2064 | len += RTA_SPACE(headlen); | 2062 | len += RTA_SPACE(headlen); |
2065 | headlen = sizeof(*id); | 2063 | headlen = sizeof(*id); |
2066 | } | 2064 | } |
2067 | #ifdef CONFIG_XFRM_SUB_POLICY | 2065 | #ifdef CONFIG_XFRM_SUB_POLICY |
2068 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); | 2066 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); |
2069 | #endif | 2067 | #endif |
2070 | len += NLMSG_SPACE(headlen); | 2068 | len += NLMSG_SPACE(headlen); |
2071 | 2069 | ||
2072 | skb = alloc_skb(len, GFP_ATOMIC); | 2070 | skb = alloc_skb(len, GFP_ATOMIC); |
2073 | if (skb == NULL) | 2071 | if (skb == NULL) |
2074 | return -ENOMEM; | 2072 | return -ENOMEM; |
2075 | b = skb->tail; | 2073 | b = skb->tail; |
2076 | 2074 | ||
2077 | nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); | 2075 | nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); |
2078 | 2076 | ||
2079 | p = NLMSG_DATA(nlh); | 2077 | p = NLMSG_DATA(nlh); |
2080 | if (c->event == XFRM_MSG_DELPOLICY) { | 2078 | if (c->event == XFRM_MSG_DELPOLICY) { |
2081 | id = NLMSG_DATA(nlh); | 2079 | id = NLMSG_DATA(nlh); |
2082 | memset(id, 0, sizeof(*id)); | 2080 | memset(id, 0, sizeof(*id)); |
2083 | id->dir = dir; | 2081 | id->dir = dir; |
2084 | if (c->data.byid) | 2082 | if (c->data.byid) |
2085 | id->index = xp->index; | 2083 | id->index = xp->index; |
2086 | else | 2084 | else |
2087 | memcpy(&id->sel, &xp->selector, sizeof(id->sel)); | 2085 | memcpy(&id->sel, &xp->selector, sizeof(id->sel)); |
2088 | 2086 | ||
2089 | p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p))); | 2087 | p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p))); |
2090 | } | 2088 | } |
2091 | 2089 | ||
2092 | nlh->nlmsg_flags = 0; | 2090 | nlh->nlmsg_flags = 0; |
2093 | 2091 | ||
2094 | copy_to_user_policy(xp, p, dir); | 2092 | copy_to_user_policy(xp, p, dir); |
2095 | if (copy_to_user_tmpl(xp, skb) < 0) | 2093 | if (copy_to_user_tmpl(xp, skb) < 0) |
2096 | goto nlmsg_failure; | 2094 | goto nlmsg_failure; |
2097 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2095 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2098 | goto nlmsg_failure; | 2096 | goto nlmsg_failure; |
2099 | 2097 | ||
2100 | nlh->nlmsg_len = skb->tail - b; | 2098 | nlh->nlmsg_len = skb->tail - b; |
2101 | 2099 | ||
2102 | NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; | 2100 | NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; |
2103 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2101 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
2104 | 2102 | ||
2105 | nlmsg_failure: | 2103 | nlmsg_failure: |
2106 | rtattr_failure: | 2104 | rtattr_failure: |
2107 | kfree_skb(skb); | 2105 | kfree_skb(skb); |
2108 | return -1; | 2106 | return -1; |
2109 | } | 2107 | } |
2110 | 2108 | ||
2111 | static int xfrm_notify_policy_flush(struct km_event *c) | 2109 | static int xfrm_notify_policy_flush(struct km_event *c) |
2112 | { | 2110 | { |
2113 | struct nlmsghdr *nlh; | 2111 | struct nlmsghdr *nlh; |
2114 | struct sk_buff *skb; | 2112 | struct sk_buff *skb; |
2115 | unsigned char *b; | 2113 | unsigned char *b; |
2116 | int len = 0; | 2114 | int len = 0; |
2117 | #ifdef CONFIG_XFRM_SUB_POLICY | 2115 | #ifdef CONFIG_XFRM_SUB_POLICY |
2118 | struct xfrm_userpolicy_type upt; | 2116 | struct xfrm_userpolicy_type upt; |
2119 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); | 2117 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); |
2120 | #endif | 2118 | #endif |
2121 | len += NLMSG_LENGTH(0); | 2119 | len += NLMSG_LENGTH(0); |
2122 | 2120 | ||
2123 | skb = alloc_skb(len, GFP_ATOMIC); | 2121 | skb = alloc_skb(len, GFP_ATOMIC); |
2124 | if (skb == NULL) | 2122 | if (skb == NULL) |
2125 | return -ENOMEM; | 2123 | return -ENOMEM; |
2126 | b = skb->tail; | 2124 | b = skb->tail; |
2127 | 2125 | ||
2128 | 2126 | ||
2129 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); | 2127 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); |
2130 | nlh->nlmsg_flags = 0; | 2128 | nlh->nlmsg_flags = 0; |
2131 | 2129 | ||
2132 | #ifdef CONFIG_XFRM_SUB_POLICY | 2130 | #ifdef CONFIG_XFRM_SUB_POLICY |
2133 | memset(&upt, 0, sizeof(upt)); | 2131 | memset(&upt, 0, sizeof(upt)); |
2134 | upt.type = c->data.type; | 2132 | upt.type = c->data.type; |
2135 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | 2133 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); |
2136 | #endif | 2134 | #endif |
2137 | 2135 | ||
2138 | nlh->nlmsg_len = skb->tail - b; | 2136 | nlh->nlmsg_len = skb->tail - b; |
2139 | 2137 | ||
2140 | NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; | 2138 | NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; |
2141 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2139 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
2142 | 2140 | ||
2143 | nlmsg_failure: | 2141 | nlmsg_failure: |
2144 | #ifdef CONFIG_XFRM_SUB_POLICY | 2142 | #ifdef CONFIG_XFRM_SUB_POLICY |
2145 | rtattr_failure: | 2143 | rtattr_failure: |
2146 | #endif | 2144 | #endif |
2147 | kfree_skb(skb); | 2145 | kfree_skb(skb); |
2148 | return -1; | 2146 | return -1; |
2149 | } | 2147 | } |
2150 | 2148 | ||
2151 | static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) | 2149 | static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
2152 | { | 2150 | { |
2153 | 2151 | ||
2154 | switch (c->event) { | 2152 | switch (c->event) { |
2155 | case XFRM_MSG_NEWPOLICY: | 2153 | case XFRM_MSG_NEWPOLICY: |
2156 | case XFRM_MSG_UPDPOLICY: | 2154 | case XFRM_MSG_UPDPOLICY: |
2157 | case XFRM_MSG_DELPOLICY: | 2155 | case XFRM_MSG_DELPOLICY: |
2158 | return xfrm_notify_policy(xp, dir, c); | 2156 | return xfrm_notify_policy(xp, dir, c); |
2159 | case XFRM_MSG_FLUSHPOLICY: | 2157 | case XFRM_MSG_FLUSHPOLICY: |
2160 | return xfrm_notify_policy_flush(c); | 2158 | return xfrm_notify_policy_flush(c); |
2161 | case XFRM_MSG_POLEXPIRE: | 2159 | case XFRM_MSG_POLEXPIRE: |
2162 | return xfrm_exp_policy_notify(xp, dir, c); | 2160 | return xfrm_exp_policy_notify(xp, dir, c); |
2163 | default: | 2161 | default: |
2164 | printk("xfrm_user: Unknown Policy event %d\n", c->event); | 2162 | printk("xfrm_user: Unknown Policy event %d\n", c->event); |
2165 | } | 2163 | } |
2166 | 2164 | ||
2167 | return 0; | 2165 | return 0; |
2168 | 2166 | ||
2169 | } | 2167 | } |
2170 | 2168 | ||
2171 | static int build_report(struct sk_buff *skb, u8 proto, | 2169 | static int build_report(struct sk_buff *skb, u8 proto, |
2172 | struct xfrm_selector *sel, xfrm_address_t *addr) | 2170 | struct xfrm_selector *sel, xfrm_address_t *addr) |
2173 | { | 2171 | { |
2174 | struct xfrm_user_report *ur; | 2172 | struct xfrm_user_report *ur; |
2175 | struct nlmsghdr *nlh; | 2173 | struct nlmsghdr *nlh; |
2176 | unsigned char *b = skb->tail; | 2174 | unsigned char *b = skb->tail; |
2177 | 2175 | ||
2178 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); | 2176 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); |
2179 | ur = NLMSG_DATA(nlh); | 2177 | ur = NLMSG_DATA(nlh); |
2180 | nlh->nlmsg_flags = 0; | 2178 | nlh->nlmsg_flags = 0; |
2181 | 2179 | ||
2182 | ur->proto = proto; | 2180 | ur->proto = proto; |
2183 | memcpy(&ur->sel, sel, sizeof(ur->sel)); | 2181 | memcpy(&ur->sel, sel, sizeof(ur->sel)); |
2184 | 2182 | ||
2185 | if (addr) | 2183 | if (addr) |
2186 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); | 2184 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); |
2187 | 2185 | ||
2188 | nlh->nlmsg_len = skb->tail - b; | 2186 | nlh->nlmsg_len = skb->tail - b; |
2189 | return skb->len; | 2187 | return skb->len; |
2190 | 2188 | ||
2191 | nlmsg_failure: | 2189 | nlmsg_failure: |
2192 | rtattr_failure: | 2190 | rtattr_failure: |
2193 | skb_trim(skb, b - skb->data); | 2191 | skb_trim(skb, b - skb->data); |
2194 | return -1; | 2192 | return -1; |
2195 | } | 2193 | } |
2196 | 2194 | ||
2197 | static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, | 2195 | static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, |
2198 | xfrm_address_t *addr) | 2196 | xfrm_address_t *addr) |
2199 | { | 2197 | { |
2200 | struct sk_buff *skb; | 2198 | struct sk_buff *skb; |
2201 | size_t len; | 2199 | size_t len; |
2202 | 2200 | ||
2203 | len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); | 2201 | len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); |
2204 | skb = alloc_skb(len, GFP_ATOMIC); | 2202 | skb = alloc_skb(len, GFP_ATOMIC); |
2205 | if (skb == NULL) | 2203 | if (skb == NULL) |
2206 | return -ENOMEM; | 2204 | return -ENOMEM; |
2207 | 2205 | ||
2208 | if (build_report(skb, proto, sel, addr) < 0) | 2206 | if (build_report(skb, proto, sel, addr) < 0) |
2209 | BUG(); | 2207 | BUG(); |
2210 | 2208 | ||
2211 | NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; | 2209 | NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; |
2212 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); | 2210 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); |
2213 | } | 2211 | } |
2214 | 2212 | ||
2215 | static struct xfrm_mgr netlink_mgr = { | 2213 | static struct xfrm_mgr netlink_mgr = { |
2216 | .id = "netlink", | 2214 | .id = "netlink", |
2217 | .notify = xfrm_send_state_notify, | 2215 | .notify = xfrm_send_state_notify, |
2218 | .acquire = xfrm_send_acquire, | 2216 | .acquire = xfrm_send_acquire, |
2219 | .compile_policy = xfrm_compile_policy, | 2217 | .compile_policy = xfrm_compile_policy, |
2220 | .notify_policy = xfrm_send_policy_notify, | 2218 | .notify_policy = xfrm_send_policy_notify, |
2221 | .report = xfrm_send_report, | 2219 | .report = xfrm_send_report, |
2222 | }; | 2220 | }; |
2223 | 2221 | ||
2224 | static int __init xfrm_user_init(void) | 2222 | static int __init xfrm_user_init(void) |
2225 | { | 2223 | { |
2226 | struct sock *nlsk; | 2224 | struct sock *nlsk; |
2227 | 2225 | ||
2228 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); | 2226 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); |
2229 | 2227 | ||
2230 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 2228 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
2231 | xfrm_netlink_rcv, THIS_MODULE); | 2229 | xfrm_netlink_rcv, THIS_MODULE); |
2232 | if (nlsk == NULL) | 2230 | if (nlsk == NULL) |
2233 | return -ENOMEM; | 2231 | return -ENOMEM; |
2234 | rcu_assign_pointer(xfrm_nl, nlsk); | 2232 | rcu_assign_pointer(xfrm_nl, nlsk); |
2235 | 2233 | ||
2236 | xfrm_register_km(&netlink_mgr); | 2234 | xfrm_register_km(&netlink_mgr); |
2237 | 2235 | ||
2238 | return 0; | 2236 | return 0; |
2239 | } | 2237 | } |
2240 | 2238 | ||
2241 | static void __exit xfrm_user_exit(void) | 2239 | static void __exit xfrm_user_exit(void) |
2242 | { | 2240 | { |
2243 | struct sock *nlsk = xfrm_nl; | 2241 | struct sock *nlsk = xfrm_nl; |
2244 | 2242 | ||
2245 | xfrm_unregister_km(&netlink_mgr); | 2243 | xfrm_unregister_km(&netlink_mgr); |
2246 | rcu_assign_pointer(xfrm_nl, NULL); | 2244 | rcu_assign_pointer(xfrm_nl, NULL); |
2247 | synchronize_rcu(); | 2245 | synchronize_rcu(); |
2248 | sock_release(nlsk->sk_socket); | 2246 | sock_release(nlsk->sk_socket); |
2249 | } | 2247 | } |
2250 | 2248 | ||
2251 | module_init(xfrm_user_init); | 2249 | module_init(xfrm_user_init); |
2252 | module_exit(xfrm_user_exit); | 2250 | module_exit(xfrm_user_exit); |
2253 | MODULE_LICENSE("GPL"); | 2251 | MODULE_LICENSE("GPL"); |
2254 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | 2252 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); |
2255 | 2253 | ||
2256 | 2254 |