1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include "core.h"
38#include "bearer.h"
39
40#define MAX_ETH_BEARERS MAX_BEARERS
41
42#define ETH_ADDR_OFFSET 4
43
44
45
46
47
48
49
50
51
52struct eth_bearer {
53 struct tipc_bearer *bearer;
54 struct net_device *dev;
55 struct packet_type tipc_packet_type;
56 struct work_struct setup;
57 struct work_struct cleanup;
58};
59
60static struct tipc_media eth_media_info;
61static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
62static int eth_started;
63
64static int recv_notification(struct notifier_block *nb, unsigned long evt,
65 void *dv);
66
67
68
69static struct notifier_block notifier = {
70 .notifier_call = recv_notification,
71 .priority = 0
72};
73
74
75
76
77
78
79
80static void eth_media_addr_set(const struct tipc_bearer *tb_ptr,
81 struct tipc_media_addr *a, char *mac)
82{
83 memcpy(a->value, mac, ETH_ALEN);
84 memset(a->value + ETH_ALEN, 0, sizeof(a->value) - ETH_ALEN);
85 a->media_id = TIPC_MEDIA_TYPE_ETH;
86 a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, ETH_ALEN);
87}
88
89
90
91
92static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
93 struct tipc_media_addr *dest)
94{
95 struct sk_buff *clone;
96 struct net_device *dev;
97 int delta;
98
99 clone = skb_clone(buf, GFP_ATOMIC);
100 if (!clone)
101 return 0;
102
103 dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
104 delta = dev->hard_header_len - skb_headroom(buf);
105
106 if ((delta > 0) &&
107 pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
108 kfree_skb(clone);
109 return 0;
110 }
111
112 skb_reset_network_header(clone);
113 clone->dev = dev;
114 clone->protocol = htons(ETH_P_TIPC);
115 dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
116 dev->dev_addr, clone->len);
117 dev_queue_xmit(clone);
118 return 0;
119}
120
121
122
123
124
125
126
127
128static int recv_msg(struct sk_buff *buf, struct net_device *dev,
129 struct packet_type *pt, struct net_device *orig_dev)
130{
131 struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
132
133 if (!net_eq(dev_net(dev), &init_net)) {
134 kfree_skb(buf);
135 return 0;
136 }
137
138 if (likely(eb_ptr->bearer)) {
139 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
140 buf->next = NULL;
141 tipc_recv_msg(buf, eb_ptr->bearer);
142 return 0;
143 }
144 }
145 kfree_skb(buf);
146 return 0;
147}
148
149
150
151
152static void setup_bearer(struct work_struct *work)
153{
154 struct eth_bearer *eb_ptr =
155 container_of(work, struct eth_bearer, setup);
156
157 dev_add_pack(&eb_ptr->tipc_packet_type);
158}
159
160
161
162
163static int enable_bearer(struct tipc_bearer *tb_ptr)
164{
165 struct net_device *dev = NULL;
166 struct net_device *pdev = NULL;
167 struct eth_bearer *eb_ptr = ð_bearers[0];
168 struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS];
169 char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
170 int pending_dev = 0;
171
172
173 while (eb_ptr->dev) {
174 if (!eb_ptr->bearer)
175 pending_dev++;
176 if (++eb_ptr == stop)
177 return pending_dev ? -EAGAIN : -EDQUOT;
178 }
179
180
181 read_lock(&dev_base_lock);
182 for_each_netdev(&init_net, pdev) {
183 if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) {
184 dev = pdev;
185 dev_hold(dev);
186 break;
187 }
188 }
189 read_unlock(&dev_base_lock);
190 if (!dev)
191 return -ENODEV;
192
193
194 eb_ptr->dev = dev;
195 eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
196 eb_ptr->tipc_packet_type.dev = dev;
197 eb_ptr->tipc_packet_type.func = recv_msg;
198 eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
199 INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
200 INIT_WORK(&eb_ptr->setup, setup_bearer);
201 schedule_work(&eb_ptr->setup);
202
203
204 eb_ptr->bearer = tb_ptr;
205 tb_ptr->usr_handle = (void *)eb_ptr;
206 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
207 memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN);
208 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH;
209 tb_ptr->bcast_addr.broadcast = 1;
210 tb_ptr->mtu = dev->mtu;
211 tb_ptr->blocked = 0;
212 eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
213 return 0;
214}
215
216
217
218
219
220
221static void cleanup_bearer(struct work_struct *work)
222{
223 struct eth_bearer *eb_ptr =
224 container_of(work, struct eth_bearer, cleanup);
225
226 dev_remove_pack(&eb_ptr->tipc_packet_type);
227 dev_put(eb_ptr->dev);
228 eb_ptr->dev = NULL;
229}
230
231
232
233
234
235
236
237
238static void disable_bearer(struct tipc_bearer *tb_ptr)
239{
240 struct eth_bearer *eb_ptr = (struct eth_bearer *)tb_ptr->usr_handle;
241
242 eb_ptr->bearer = NULL;
243 INIT_WORK(&eb_ptr->cleanup, cleanup_bearer);
244 schedule_work(&eb_ptr->cleanup);
245}
246
247
248
249
250
251
252
253static int recv_notification(struct notifier_block *nb, unsigned long evt,
254 void *ptr)
255{
256 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
257 struct eth_bearer *eb_ptr = ð_bearers[0];
258 struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS];
259
260 if (!net_eq(dev_net(dev), &init_net))
261 return NOTIFY_DONE;
262
263 while ((eb_ptr->dev != dev)) {
264 if (++eb_ptr == stop)
265 return NOTIFY_DONE;
266 }
267 if (!eb_ptr->bearer)
268 return NOTIFY_DONE;
269
270 eb_ptr->bearer->mtu = dev->mtu;
271
272 switch (evt) {
273 case NETDEV_CHANGE:
274 if (netif_carrier_ok(dev))
275 tipc_continue(eb_ptr->bearer);
276 else
277 tipc_block_bearer(eb_ptr->bearer->name);
278 break;
279 case NETDEV_UP:
280 tipc_continue(eb_ptr->bearer);
281 break;
282 case NETDEV_DOWN:
283 tipc_block_bearer(eb_ptr->bearer->name);
284 break;
285 case NETDEV_CHANGEMTU:
286 case NETDEV_CHANGEADDR:
287 tipc_block_bearer(eb_ptr->bearer->name);
288 tipc_continue(eb_ptr->bearer);
289 break;
290 case NETDEV_UNREGISTER:
291 case NETDEV_CHANGENAME:
292 tipc_disable_bearer(eb_ptr->bearer->name);
293 break;
294 }
295 return NOTIFY_OK;
296}
297
298
299
300
301static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
302{
303 if (str_size < 18)
304 return 1;
305
306 sprintf(str_buf, "%pM", a->value);
307 return 0;
308}
309
310
311
312
313static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area)
314{
315 memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE);
316 msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH;
317 memcpy(msg_area + ETH_ADDR_OFFSET, a->value, ETH_ALEN);
318 return 0;
319}
320
321
322
323
324static int eth_msg2addr(const struct tipc_bearer *tb_ptr,
325 struct tipc_media_addr *a, char *msg_area)
326{
327 if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH)
328 return 1;
329
330 eth_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET);
331 return 0;
332}
333
334
335
336
337static struct tipc_media eth_media_info = {
338 .send_msg = send_msg,
339 .enable_bearer = enable_bearer,
340 .disable_bearer = disable_bearer,
341 .addr2str = eth_addr2str,
342 .addr2msg = eth_addr2msg,
343 .msg2addr = eth_msg2addr,
344 .priority = TIPC_DEF_LINK_PRI,
345 .tolerance = TIPC_DEF_LINK_TOL,
346 .window = TIPC_DEF_LINK_WIN,
347 .type_id = TIPC_MEDIA_TYPE_ETH,
348 .name = "eth"
349};
350
351
352
353
354
355
356
357int tipc_eth_media_start(void)
358{
359 int res;
360
361 if (eth_started)
362 return -EINVAL;
363
364 res = tipc_register_media(ð_media_info);
365 if (res)
366 return res;
367
368 res = register_netdevice_notifier_rh(¬ifier);
369 if (!res)
370 eth_started = 1;
371 return res;
372}
373
374
375
376
377void tipc_eth_media_stop(void)
378{
379 if (!eth_started)
380 return;
381
382 flush_scheduled_work();
383 unregister_netdevice_notifier_rh(¬ifier);
384 eth_started = 0;
385}
386