2 * IS-IS Rout(e)ing protocol - isis_pfpacket.c
4 * Copyright (C) 2001,2002 Sampo Saaristo
5 * Tampere University of Technology
6 * Institute of Communications Engineering
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public Licenseas published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
13 * This program is distributed in the hope that it will be useful,but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <net/ethernet.h> /* the L2 protocols */
25 #include <netpacket/packet.h>
31 #include "isisd/dict.h"
32 #include "isisd/include-netbsd/iso.h"
33 #include "isisd/isis_constants.h"
34 #include "isisd/isis_common.h"
35 #include "isisd/isis_circuit.h"
36 #include "isisd/isis_flags.h"
37 #include "isisd/isisd.h"
38 #include "isisd/isis_constants.h"
39 #include "isisd/isis_circuit.h"
40 #include "isisd/isis_network.h"
44 extern struct zebra_privs_t isisd_privs
;
47 * Table 9 - Architectural constants for use with ISO 8802 subnetworks
51 u_char ALL_L1_ISS
[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
52 u_char ALL_L2_ISS
[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
53 u_char ALL_ISS
[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
54 u_char ALL_ESS
[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
56 static char discard_buff
[8192];
57 static char sock_buff
[8192];
60 * if level is 0 we are joining p2p multicast
61 * FIXME: and the p2p multicast being ???
64 isis_multicast_join (int fd
, int registerto
, int if_num
)
66 struct packet_mreq mreq
;
68 memset (&mreq
, 0, sizeof (mreq
));
69 mreq
.mr_ifindex
= if_num
;
72 mreq
.mr_type
= PACKET_MR_MULTICAST
;
73 mreq
.mr_alen
= ETH_ALEN
;
75 memcpy (&mreq
.mr_address
, ALL_L1_ISS
, ETH_ALEN
);
76 else if (registerto
== 2)
77 memcpy (&mreq
.mr_address
, ALL_L2_ISS
, ETH_ALEN
);
78 else if (registerto
== 3)
79 memcpy (&mreq
.mr_address
, ALL_ISS
, ETH_ALEN
);
81 memcpy (&mreq
.mr_address
, ALL_ESS
, ETH_ALEN
);
86 mreq
.mr_type
= PACKET_MR_ALLMULTI
;
89 zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
90 "address = %02x:%02x:%02x:%02x:%02x:%02x",
91 fd
, registerto
, if_num
, mreq
.mr_address
[0], mreq
.mr_address
[1],
92 mreq
.mr_address
[2], mreq
.mr_address
[3], mreq
.mr_address
[4],
94 #endif /* EXTREME_DEBUG */
95 if (setsockopt (fd
, SOL_PACKET
, PACKET_ADD_MEMBERSHIP
, &mreq
,
96 sizeof (struct packet_mreq
)))
98 zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno
));
106 open_packet_socket (struct isis_circuit
*circuit
)
108 struct sockaddr_ll s_addr
;
109 int fd
, retval
= ISIS_OK
;
111 fd
= socket (PF_PACKET
, SOCK_DGRAM
, htons (ETH_P_ALL
));
114 zlog_warn ("open_packet_socket(): socket() failed %s",
115 safe_strerror (errno
));
120 * Bind to the physical interface
122 memset (&s_addr
, 0, sizeof (struct sockaddr_ll
));
123 s_addr
.sll_family
= AF_PACKET
;
124 s_addr
.sll_protocol
= htons (ETH_P_ALL
);
125 s_addr
.sll_ifindex
= circuit
->interface
->ifindex
;
127 if (bind (fd
, (struct sockaddr
*) (&s_addr
),
128 sizeof (struct sockaddr_ll
)) < 0)
130 zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno
));
136 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
139 * Join to multicast groups
141 * 8.4.2 - Broadcast subnetwork IIH PDUs
142 * FIXME: is there a case only one will fail??
144 if (circuit
->circuit_is_type
& IS_LEVEL_1
)
146 /* joining ALL_L1_ISS */
147 retval
= isis_multicast_join (circuit
->fd
, 1,
148 circuit
->interface
->ifindex
);
149 /* joining ALL_ISS */
150 retval
= isis_multicast_join (circuit
->fd
, 3,
151 circuit
->interface
->ifindex
);
153 if (circuit
->circuit_is_type
& IS_LEVEL_2
)
154 /* joining ALL_L2_ISS */
155 retval
= isis_multicast_join (circuit
->fd
, 2,
156 circuit
->interface
->ifindex
);
161 isis_multicast_join (circuit
->fd
, 0, circuit
->interface
->ifindex
);
168 * Create the socket and set the tx/rx funcs
171 isis_sock_init (struct isis_circuit
*circuit
)
173 int retval
= ISIS_OK
;
175 if (isisd_privs
.change (ZPRIVS_RAISE
))
176 zlog_err ("%s: could not raise privs, %s", __func__
, safe_strerror (errno
));
178 retval
= open_packet_socket (circuit
);
180 if (retval
!= ISIS_OK
)
182 zlog_warn ("%s: could not initialize the socket", __func__
);
186 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
188 circuit
->tx
= isis_send_pdu_bcast
;
189 circuit
->rx
= isis_recv_pdu_bcast
;
191 else if (circuit
->circ_type
== CIRCUIT_T_P2P
)
193 circuit
->tx
= isis_send_pdu_p2p
;
194 circuit
->rx
= isis_recv_pdu_p2p
;
198 zlog_warn ("isis_sock_init(): unknown circuit type");
199 retval
= ISIS_WARNING
;
204 if (isisd_privs
.change (ZPRIVS_LOWER
))
205 zlog_err ("%s: could not lower privs, %s", __func__
, safe_strerror (errno
));
211 llc_check (u_char
* llc
)
213 if (*llc
!= ISO_SAP
|| *(llc
+ 1) != ISO_SAP
|| *(llc
+ 2) != 3)
220 isis_recv_pdu_bcast (struct isis_circuit
*circuit
, u_char
* ssnpa
)
222 int bytesread
, addr_len
;
223 struct sockaddr_ll s_addr
;
226 addr_len
= sizeof (s_addr
);
228 memset (&s_addr
, 0, sizeof (struct sockaddr_ll
));
230 bytesread
= recvfrom (circuit
->fd
, (void *) &llc
,
232 (struct sockaddr
*) &s_addr
, (socklen_t
*) &addr_len
);
236 zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
237 circuit
->fd
, safe_strerror (errno
));
238 zlog_warn ("circuit is %s", circuit
->interface
->name
);
239 zlog_warn ("circuit fd %d", circuit
->fd
);
240 zlog_warn ("bytesread %d", bytesread
);
241 /* get rid of the packet */
242 bytesread
= read (circuit
->fd
, discard_buff
, sizeof (discard_buff
));
246 * Filtering by llc field, discard packets sent by this host (other circuit)
248 if (!llc_check (llc
) || s_addr
.sll_pkttype
== PACKET_OUTGOING
)
250 /* Read the packet into discard buff */
251 bytesread
= read (circuit
->fd
, discard_buff
, sizeof (discard_buff
));
253 zlog_warn ("isis_recv_pdu_bcast(): read() failed");
257 /* on lan we have to read to the static buff first */
258 bytesread
= recvfrom (circuit
->fd
, sock_buff
, circuit
->interface
->mtu
, 0,
259 (struct sockaddr
*) &s_addr
, (socklen_t
*) &addr_len
);
261 /* then we lose the LLC */
262 stream_write (circuit
->rcv_stream
, sock_buff
+ LLC_LEN
, bytesread
- LLC_LEN
);
264 memcpy (ssnpa
, &s_addr
.sll_addr
, s_addr
.sll_halen
);
270 isis_recv_pdu_p2p (struct isis_circuit
*circuit
, u_char
* ssnpa
)
272 int bytesread
, addr_len
;
273 struct sockaddr_ll s_addr
;
275 memset (&s_addr
, 0, sizeof (struct sockaddr_ll
));
276 addr_len
= sizeof (s_addr
);
278 /* we can read directly to the stream */
279 bytesread
= stream_recvfrom (circuit
->rcv_stream
, circuit
->fd
,
280 circuit
->interface
->mtu
, 0,
281 (struct sockaddr
*) &s_addr
,
282 (socklen_t
*) &addr_len
);
284 if (s_addr
.sll_pkttype
== PACKET_OUTGOING
)
286 /* Read the packet into discard buff */
287 bytesread
= read (circuit
->fd
, discard_buff
, sizeof (discard_buff
));
289 zlog_warn ("isis_recv_pdu_p2p(): read() failed");
293 /* If we don't have protocol type 0x00FE which is
294 * ISO over GRE we exit with pain :)
296 if (ntohs (s_addr
.sll_protocol
) != 0x00FE)
298 zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
299 ntohs (s_addr
.sll_protocol
));
303 memcpy (ssnpa
, &s_addr
.sll_addr
, s_addr
.sll_halen
);
309 isis_send_pdu_bcast (struct isis_circuit
*circuit
, int level
)
311 /* we need to do the LLC in here because of P2P circuits, which will
315 struct sockaddr_ll sa
;
317 stream_set_getp (circuit
->snd_stream
, 0);
318 memset (&sa
, 0, sizeof (struct sockaddr_ll
));
319 sa
.sll_family
= AF_PACKET
;
320 sa
.sll_protocol
= htons (stream_get_endp (circuit
->snd_stream
) + LLC_LEN
);
321 sa
.sll_ifindex
= circuit
->interface
->ifindex
;
322 sa
.sll_halen
= ETH_ALEN
;
324 memcpy (&sa
.sll_addr
, ALL_L1_ISS
, ETH_ALEN
);
326 memcpy (&sa
.sll_addr
, ALL_L2_ISS
, ETH_ALEN
);
328 /* on a broadcast circuit */
329 /* first we put the LLC in */
334 /* then we copy the data */
335 memcpy (sock_buff
+ LLC_LEN
, circuit
->snd_stream
->data
,
336 stream_get_endp (circuit
->snd_stream
));
338 /* now we can send this */
339 written
= sendto (circuit
->fd
, sock_buff
,
340 stream_get_endp(circuit
->snd_stream
) + LLC_LEN
, 0,
341 (struct sockaddr
*) &sa
, sizeof (struct sockaddr_ll
));
347 isis_send_pdu_p2p (struct isis_circuit
*circuit
, int level
)
351 struct sockaddr_ll sa
;
353 stream_set_getp (circuit
->snd_stream
, 0);
354 memset (&sa
, 0, sizeof (struct sockaddr_ll
));
355 sa
.sll_family
= AF_PACKET
;
356 sa
.sll_protocol
= htons (stream_get_endp (circuit
->snd_stream
) + LLC_LEN
);
357 sa
.sll_ifindex
= circuit
->interface
->ifindex
;
358 sa
.sll_halen
= ETH_ALEN
;
360 memcpy (&sa
.sll_addr
, ALL_L1_ISS
, ETH_ALEN
);
362 memcpy (&sa
.sll_addr
, ALL_L2_ISS
, ETH_ALEN
);
365 /* lets try correcting the protocol */
366 sa
.sll_protocol
= htons (0x00FE);
367 written
= sendto (circuit
->fd
, circuit
->snd_stream
->data
,
368 stream_get_endp (circuit
->snd_stream
), 0,
369 (struct sockaddr
*) &sa
,
370 sizeof (struct sockaddr_ll
));