]>
git.ipfire.org Git - people/ms/rstp.git/blob - bpdu_sock.c
1 /*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
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)
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
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.
18 The full GNU General Public License is included in this distribution in the
21 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
23 ******************************************************************************/
25 #include "bpdu_sock.h"
26 #include "epoll_loop.h"
27 #include "netif_utils.h"
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
40 #include <linux/if_arp.h>
41 #include <linux/llc.h>
49 static const uint8_t stp_mc
[ETH_ALEN
] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
51 void bpdu_send(struct epoll_event_handler
*h
, unsigned char *data
, int len
)
53 struct sockaddr_llc to
;
54 memset(&to
, 0, sizeof(to
));
55 to
.sllc_family
= AF_LLC
;
56 to
.sllc_arphrd
= ARPHRD_ETHER
;
57 to
.sllc_sap
= LLC_SAP_BSPAN
;
58 memcpy(to
.sllc_mac
, stp_mc
, ETH_ALEN
);
60 if (fcntl(h
->fd
, F_SETFL
, 0) < 0)
61 ERROR("Error unsetting O_NONBLOCK: %m");
63 int l
= sendto(h
->fd
, data
, len
, 0, (struct sockaddr
*)&to
, sizeof(to
));
65 ERROR("sendto failed: %m");
67 ERROR("short write in sendto: %d instead of %d", l
, len
);
69 if (fcntl(h
->fd
, F_SETFL
, O_NONBLOCK
) < 0)
70 ERROR("Error setting O_NONBLOCK: %m");
73 void bpdu_rcv_handler(uint32_t events
, struct epoll_event_handler
*h
)
75 struct sockaddr_llc from
;
76 socklen_t fromlen
= sizeof(from
);
78 unsigned char buf
[2048];
80 cc
= recvfrom(h
->fd
, &buf
, sizeof(buf
), 0,
81 (struct sockaddr
*) &from
, &fromlen
);
83 ERROR("recvfrom failed: %m");
88 printf("Src %02x:%02x:%02x:%02x:%02x:%02x\n",
89 from
.sllc_mac
[0], from
.sllc_mac
[1],
90 from
.sllc_mac
[2], from
.sllc_mac
[3],
91 from
.sllc_mac
[4], from
.sllc_mac
[5]);
93 for (i
= 0; i
< cc
; i
+= 16) {
94 for (j
= 0; j
< 16 && i
+j
< cc
; j
++)
95 printf(" %02x", buf
[i
+j
]);
102 bpdu_rcv(h
->arg
, buf
, cc
);
106 /* We added name as an arg here because we can't do if_indextoname here,
107 That needs <net/if.h> which conflicts with <linux/if.h> */
108 /* Needs fixing. Socket should be closed in case of errors */
109 int bpdu_sock_create(struct epoll_event_handler
*h
,
110 int if_index
, char *name
, struct ifdata
*arg
)
112 struct sockaddr_llc llc_addr
;
113 memset(&llc_addr
, 0, sizeof(llc_addr
));
114 llc_addr
.sllc_family
= AF_LLC
;
115 llc_addr
.sllc_arphrd
= ARPHRD_ETHER
;
116 llc_addr
.sllc_sap
= LLC_SAP_BSPAN
;
119 TSTM((s
= socket(AF_LLC
, SOCK_DGRAM
, 0)) >= 0, -1, "%m");
121 TST(get_hwaddr(name
, llc_addr
.sllc_mac
) == 0, -1);
123 TSTM(bind(s
, (struct sockaddr
*) &llc_addr
, sizeof(llc_addr
)) == 0, -1,
124 "Can't bind to LLC SAP %#x: %m", llc_addr
.sllc_sap
);
127 memset(&ifr
, 0, sizeof(ifr
));
128 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
129 ifr
.ifr_hwaddr
.sa_family
= AF_UNSPEC
;
130 memcpy(ifr
.ifr_hwaddr
.sa_data
, stp_mc
, ETH_ALEN
);
132 TSTM(ioctl(s
, SIOCADDMULTI
, &ifr
) == 0, -1,
133 "can't set multicast address for %s: %m", ifr
.ifr_name
);
136 TSTM(fcntl(s
, F_SETFL
, O_NONBLOCK
) == 0, -1, "%m");
140 h
->handler
= bpdu_rcv_handler
;
142 if (add_epoll(h
) < 0)
148 void bpdu_sock_delete(struct epoll_event_handler
*h
)