[ipv6] Fix router solicitation struct and flag checking
[gpxe.git] / src / net / eth_slow.c
blobc108bd10066d9037a0f46a09eb5f93548335335d
1 /*
2 * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdlib.h>
22 #include <string.h>
23 #include <byteswap.h>
24 #include <errno.h>
25 #include <gpxe/iobuf.h>
26 #include <gpxe/netdevice.h>
27 #include <gpxe/if_ether.h>
28 #include <gpxe/ethernet.h>
29 #include <gpxe/eth_slow.h>
31 /** @file
33 * Ethernet slow protocols
35 * We implement a very simple passive LACP entity, that pretends that
36 * each port is the only port on an individual system. We avoid the
37 * need for timeout logic (and retaining local state about our
38 * partner) by requesting the same timeout period (1s or 30s) as our
39 * partner requests, and then simply responding to every packet the
40 * partner sends us.
43 struct net_protocol eth_slow_protocol;
45 /** Slow protocols multicast address */
46 static const uint8_t eth_slow_address[ETH_ALEN] =
47 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
49 /**
50 * Name LACP TLV type
52 * @v type LACP TLV type
53 * @ret name Name of LACP TLV type
55 static inline __attribute__ (( always_inline )) const char *
56 eth_slow_lacp_tlv_name ( uint8_t type ) {
57 switch ( type ) {
58 case ETH_SLOW_TLV_TERMINATOR: return "terminator";
59 case ETH_SLOW_TLV_LACP_ACTOR: return "actor";
60 case ETH_SLOW_TLV_LACP_PARTNER: return "partner";
61 case ETH_SLOW_TLV_LACP_COLLECTOR: return "collector";
62 default: return "<invalid>";
66 /**
67 * Name marker TLV type
69 * @v type Marker TLV type
70 * @ret name Name of marker TLV type
72 static inline __attribute__ (( always_inline )) const char *
73 eth_slow_marker_tlv_name ( uint8_t type ) {
74 switch ( type ) {
75 case ETH_SLOW_TLV_TERMINATOR: return "terminator";
76 case ETH_SLOW_TLV_MARKER_REQUEST: return "request";
77 case ETH_SLOW_TLV_MARKER_RESPONSE: return "response";
78 default: return "<invalid>";
82 /**
83 * Name LACP state
85 * @v state LACP state
86 * @ret name LACP state name
88 static const char * eth_slow_lacp_state_name ( uint8_t state ) {
89 static char state_chars[] = "AFGSRTLX";
90 unsigned int i;
92 for ( i = 0 ; i < 8 ; i++ ) {
93 state_chars[i] |= 0x20;
94 if ( state & ( 1 << i ) )
95 state_chars[i] &= ~0x20;
97 return state_chars;
101 * Dump LACP packet
103 * @v iobuf I/O buffer
104 * @v netdev Network device
105 * @v label "RX" or "TX"
107 static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
108 struct net_device *netdev,
109 const char *label ) {
110 union eth_slow_packet *eth_slow = iobuf->data;
111 struct eth_slow_lacp *lacp = &eth_slow->lacp;
113 DBGC ( netdev,
114 "SLOW %p %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
115 netdev, label, ntohs ( lacp->actor.system_priority ),
116 eth_ntoa ( lacp->actor.system ),
117 ntohs ( lacp->actor.key ),
118 ntohs ( lacp->actor.port_priority ),
119 ntohs ( lacp->actor.port ),
120 eth_slow_lacp_state_name ( lacp->actor.state ) );
121 DBGC ( netdev,
122 "SLOW %p %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
123 netdev, label, ntohs ( lacp->partner.system_priority ),
124 eth_ntoa ( lacp->partner.system ),
125 ntohs ( lacp->partner.key ),
126 ntohs ( lacp->partner.port_priority ),
127 ntohs ( lacp->partner.port ),
128 eth_slow_lacp_state_name ( lacp->partner.state ) );
129 DBGC ( netdev, "SLOW %p %s LACP collector %04x (%d us)\n",
130 netdev, label, ntohs ( lacp->collector.max_delay ),
131 ( ntohs ( lacp->collector.max_delay ) * 10 ) );
132 DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
136 * Process incoming LACP packet
138 * @v iobuf I/O buffer
139 * @v netdev Network device
140 * @ret rc Return status code
142 static int eth_slow_lacp_rx ( struct io_buffer *iobuf,
143 struct net_device *netdev ) {
144 union eth_slow_packet *eth_slow = iobuf->data;
145 struct eth_slow_lacp *lacp = &eth_slow->lacp;
147 eth_slow_lacp_dump ( iobuf, netdev, "RX" );
149 /* Build response */
150 memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
151 memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );
152 memset ( &lacp->collector, 0, sizeof ( lacp->collector ) );
153 lacp->collector.tlv.type = ETH_SLOW_TLV_LACP_COLLECTOR;
154 lacp->collector.tlv.length = ETH_SLOW_TLV_LACP_COLLECTOR_LEN;
155 memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) );
156 lacp->partner.tlv.type = ETH_SLOW_TLV_LACP_PARTNER;
157 lacp->partner.tlv.length = ETH_SLOW_TLV_LACP_PARTNER_LEN;
158 memset ( &lacp->partner.reserved, 0,
159 sizeof ( lacp->partner.reserved ) );
160 memset ( &lacp->actor, 0, sizeof ( lacp->actor ) );
161 lacp->actor.tlv.type = ETH_SLOW_TLV_LACP_ACTOR;
162 lacp->actor.tlv.length = ETH_SLOW_TLV_LACP_ACTOR_LEN;
163 lacp->actor.system_priority = htons ( LACP_SYSTEM_PRIORITY_MAX );
164 memcpy ( lacp->actor.system, netdev->ll_addr,
165 sizeof ( lacp->actor.system ) );
166 lacp->actor.key = htons ( 1 );
167 lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX );
168 lacp->actor.port = htons ( 1 );
169 lacp->actor.state = ( LACP_STATE_IN_SYNC |
170 LACP_STATE_COLLECTING |
171 LACP_STATE_DISTRIBUTING |
172 ( lacp->partner.state & LACP_STATE_FAST ) );
173 lacp->header.version = ETH_SLOW_LACP_VERSION;
175 /* Send response */
176 eth_slow_lacp_dump ( iobuf, netdev, "TX" );
177 return net_tx ( iobuf, netdev, &eth_slow_protocol, eth_slow_address );
181 * Dump marker packet
183 * @v iobuf I/O buffer
184 * @v netdev Network device
185 * @v label "RX" or "TX"
187 static void eth_slow_marker_dump ( struct io_buffer *iobuf,
188 struct net_device *netdev,
189 const char *label ) {
190 union eth_slow_packet *eth_slow = iobuf->data;
191 struct eth_slow_marker *marker = &eth_slow->marker;
193 DBGC ( netdev, "SLOW %p %s marker %s port %04x system %s xact %08x\n",
194 netdev, label,
195 eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
196 ntohs ( marker->marker.port ),
197 eth_ntoa ( marker->marker.system ),
198 ntohl ( marker->marker.xact ) );
199 DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
203 * Process incoming marker packet
205 * @v iobuf I/O buffer
206 * @v netdev Network device
207 * @ret rc Return status code
209 static int eth_slow_marker_rx ( struct io_buffer *iobuf,
210 struct net_device *netdev ) {
211 union eth_slow_packet *eth_slow = iobuf->data;
212 struct eth_slow_marker *marker = &eth_slow->marker;
214 eth_slow_marker_dump ( iobuf, netdev, "RX" );
216 if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
217 /* Send marker response */
218 marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE;
219 eth_slow_marker_dump ( iobuf, netdev, "TX" );
220 return net_tx ( iobuf, netdev, &eth_slow_protocol,
221 eth_slow_address );
222 } else {
223 /* Discard all other marker packets */
224 free_iob ( iobuf );
225 return -EINVAL;
230 * Process incoming slow packet
232 * @v iobuf I/O buffer
233 * @v netdev Network device
234 * @v ll_source Link-layer source address
235 * @ret rc Return status code
237 static int eth_slow_rx ( struct io_buffer *iobuf,
238 struct net_device *netdev,
239 const void *ll_source __unused ) {
240 union eth_slow_packet *eth_slow = iobuf->data;
242 /* Sanity checks */
243 if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
244 free_iob ( iobuf );
245 return -EINVAL;
248 /* Handle according to subtype */
249 switch ( eth_slow->header.subtype ) {
250 case ETH_SLOW_SUBTYPE_LACP:
251 return eth_slow_lacp_rx ( iobuf, netdev );
252 case ETH_SLOW_SUBTYPE_MARKER:
253 return eth_slow_marker_rx ( iobuf, netdev );
254 default:
255 DBGC ( netdev, "SLOW %p RX unknown subtype %02x\n",
256 netdev, eth_slow->header.subtype );
257 free_iob ( iobuf );
258 return -EINVAL;
262 /** Slow protocol */
263 struct net_protocol eth_slow_protocol __net_protocol = {
264 .name = "Slow",
265 .net_proto = htons ( ETH_P_SLOW ),
266 .rx = eth_slow_rx,