]> git.ipfire.org Git - people/ms/rstp.git/blame - packet.c
fixes for 4.3.3 GCC warnings/errors
[people/ms/rstp.git] / packet.c
CommitLineData
f2592588
SH
1/*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
22 Stephen Hemminger <shemminger@linux-foundation.org>
23
24******************************************************************************/
25
26#include "packet.h"
27#include "epoll_loop.h"
28#include "netif_utils.h"
29#include "bridge_ctl.h"
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <string.h>
35#include <unistd.h>
36#include <stdint.h>
37#include <sys/socket.h>
38#include <sys/ioctl.h>
39#include <fcntl.h>
40#include <netinet/in.h>
41
42#include <linux/if.h>
43#include <linux/if_ether.h>
44#include <linux/if_packet.h>
45#include <linux/filter.h>
46
47#include "log.h"
48
96e20123
SH
49static struct epoll_event_handler packet_event;
50
358260ff 51#ifdef PACKET_DEBUG
96e20123
SH
52static void dump_packet(const unsigned char *buf, int cc)
53{
54 int i, j;
55 for (i = 0; i < cc; i += 16) {
56 for (j = 0; j < 16 && i + j < cc; j++)
57 printf(" %02x", buf[i + j]);
58 printf("\n");
59 }
60 printf("\n");
61 fflush(stdout);
62}
63#endif
f2592588
SH
64
65/*
66 * To send/receive Spanning Tree packets we use PF_PACKET because
67 * it allows the filtering we want but gives raw data
68 */
3cf368c1 69void packet_send(int ifindex, const struct iovec *iov, int iov_count, int len)
f2592588
SH
70{
71 int l;
96e20123
SH
72 struct sockaddr_ll sl = {
73 .sll_family = AF_PACKET,
74 .sll_protocol = htons(ETH_P_802_2),
75 .sll_ifindex = ifindex,
76 .sll_halen = ETH_ALEN,
77 };
f2592588 78
3cf368c1
SA
79 if (iov_count > 0 && iov[0].iov_len > ETH_ALEN)
80 memcpy(&sl.sll_addr, iov[0].iov_base, ETH_ALEN);
81
82 struct msghdr msg = {
83 .msg_name = &sl,
84 .msg_namelen = sizeof(sl),
85 .msg_iov = (struct iovec *)iov,
86 .msg_iovlen = iov_count,
87 .msg_control = NULL,
88 .msg_controllen = 0,
89 .msg_flags = 0,
90 };
f2592588 91
358260ff
SH
92#ifdef PACKET_DEBUG
93 printf("Transmit Dst index %d %02x:%02x:%02x:%02x:%02x:%02x\n",
94 sl.sll_ifindex,
96e20123
SH
95 sl.sll_addr[0], sl.sll_addr[1], sl.sll_addr[2],
96 sl.sll_addr[3], sl.sll_addr[4], sl.sll_addr[5]);
3cf368c1
SA
97
98 {
99 int i;
100 for (i = 0; i < iov_count; i++)
101 dump_packet(iov[i].iov_base, iov[i].iov_len);
102 }
96e20123 103#endif
358260ff 104
3cf368c1 105 l = sendmsg(packet_event.fd, &msg, 0);
f2592588 106
96e20123
SH
107 if (l < 0) {
108 if (errno != EWOULDBLOCK)
109 ERROR("send failed: %m");
110 } else if (l != len)
111 ERROR("short write in sendto: %d instead of %d", l, len);
f2592588
SH
112}
113
96e20123 114static void packet_rcv(uint32_t events, struct epoll_event_handler *h)
f2592588
SH
115{
116 int cc;
117 unsigned char buf[2048];
96e20123
SH
118 struct sockaddr_ll sl;
119 socklen_t salen = sizeof sl;
f2592588 120
358260ff 121 cc = recvfrom(h->fd, &buf, sizeof(buf), 0, (struct sockaddr *) &sl, &salen);
f2592588 122 if (cc <= 0) {
96e20123 123 ERROR("recvfrom failed: %m");
f2592588
SH
124 return;
125 }
126
358260ff
SH
127#ifdef PACKET_DEBUG
128 printf("Receive Src ifindex %d %02x:%02x:%02x:%02x:%02x:%02x\n",
129 sl.sll_ifindex,
130 sl.sll_addr[0], sl.sll_addr[1], sl.sll_addr[2],
131 sl.sll_addr[3], sl.sll_addr[4], sl.sll_addr[5]);
f2592588 132
96e20123 133 dump_packet(buf, cc);
f2592588
SH
134#endif
135
96e20123 136 bridge_bpdu_rcv(sl.sll_ifindex, buf, cc);
f2592588
SH
137}
138
139/* Berkeley Packet filter code to filter out spanning tree packets.
140 from tcpdump -dd stp
141 */
142static struct sock_filter stp_filter[] = {
143 { 0x28, 0, 0, 0x0000000c },
144 { 0x25, 3, 0, 0x000005dc },
145 { 0x30, 0, 0, 0x0000000e },
146 { 0x15, 0, 1, 0x00000042 },
147 { 0x6, 0, 0, 0x00000060 },
148 { 0x6, 0, 0, 0x00000000 },
149};
150
151/*
96e20123 152 * Open up a raw packet socket to catch all 802.2 packets.
f2592588 153 * and install a packet filter to only see STP (SAP 42)
96e20123
SH
154 *
155 * Since any bridged devices are already in promiscious mode
156 * no need to add multicast address.
f2592588 157 */
96e20123 158int packet_sock_init(void)
f2592588
SH
159{
160 int s;
f2592588
SH
161 struct sock_fprog prog = {
162 .len = sizeof(stp_filter) / sizeof(stp_filter[0]),
163 .filter = stp_filter,
164 };
165
96e20123 166 s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_802_2));
f2592588
SH
167 if (s < 0) {
168 ERROR("socket failed: %m");
169 return -1;
170 }
171
96e20123 172 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
f2592588
SH
173 ERROR("setsockopt packet filter failed: %m");
174
175 else if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
176 ERROR("fcntl set nonblock failed: %m");
177
178 else {
96e20123
SH
179 packet_event.fd = s;
180 packet_event.handler = packet_rcv;
f2592588 181
96e20123 182 if (add_epoll(&packet_event) == 0)
f2592588
SH
183 return 0;
184 }
185
186 close(s);
187 return -1;
188}