Browse Source

Remove the concept of the media-independent link-layer header and replace

it with metadata in the pkb structure.  This is required since UNDI will
want to be able to parse the link-layer header without destroying it.
tags/v0.9.3
Michael Brown 19 years ago
parent
commit
bdc8190c8d
6 changed files with 195 additions and 127 deletions
  1. 1
    1
      src/include/gpxe/arp.h
  2. 0
    63
      src/include/gpxe/llh.h
  3. 26
    36
      src/include/gpxe/netdevice.h
  4. 32
    0
      src/include/gpxe/pkbuff.h
  5. 20
    27
      src/net/arp.c
  6. 116
    0
      src/net/ethernet.c

+ 1
- 1
src/include/gpxe/arp.h View File

12
 struct pk_buff;
12
 struct pk_buff;
13
 
13
 
14
 extern int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
14
 extern int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
15
-			 void *ll_addr );
15
+			 const void **ll_addr );
16
 
16
 
17
 extern int arp_process ( struct net_interface *arp_netif,
17
 extern int arp_process ( struct net_interface *arp_netif,
18
 			 struct pk_buff *pkb );
18
 			 struct pk_buff *pkb );

+ 0
- 63
src/include/gpxe/llh.h View File

1
-#ifndef _LLH_H
2
-#define _LLH_H
3
-
4
-/** @file
5
- *
6
- * Link-layer headers
7
- *
8
- * This file defines a media-independent link-layer header, used for
9
- * communication between the network and link layers of the stack.
10
- *
11
- */
12
-
13
-#include <stdint.h>
14
-
15
-/** Maximum length of a link-layer address */
16
-#define MAX_LLH_ADDR_LEN 6
17
-
18
-/** Maximum length of a network-layer address */
19
-#define MAX_NET_ADDR_LEN 4
20
-
21
-/* Network-layer address may be required to contain a raw link-layer address */
22
-#if MAX_NET_ADDR_LEN < MAX_LLH_ADDR_LEN
23
-#undef MAX_NET_ADDR_LEN
24
-#define MAX_NET_ADDR_LEN MAX_LLH_ADDR_LEN
25
-#endif
26
-
27
-/** A media-independent link-layer header
28
- *
29
- * This structure represents a generic link-layer header.  It never
30
- * appears on the wire, but is used to communicate between different
31
- * layers within the gPXE protocol stack.
32
- */
33
-struct gpxehdr {
34
-	/** The network-layer protocol
35
-	 *
36
-	 * This is the network-layer protocol expressed as an
37
-	 * ETH_P_XXX constant, in network-byte order.
38
-	 */
39
-	uint16_t net_proto;
40
-	/** Flags
41
-	 *
42
-	 * Filled in only on outgoing packets.  Value is the
43
-	 * bitwise-OR of zero or more GPXE_FL_XXX constants.
44
-	 */
45
-	uint8_t flags;
46
-	/** Network-layer address length 
47
-	 *
48
-	 * Filled in only on outgoing packets.
49
-	 */
50
-	uint8_t net_addr_len;
51
-	/** Network-layer address
52
-	 *
53
-	 * Filled in only on outgoing packets.
54
-	 */
55
-	uint8_t net_addr[MAX_NET_ADDR_LEN];
56
-} __attribute__ (( packed ));
57
-
58
-/* Media-independent link-layer header flags */
59
-#define GPXE_FL_BROADCAST	0x01
60
-#define GPXE_FL_MULTICAST	0x02
61
-#define GPXE_FL_RAW		0x04
62
-
63
-#endif /* _LLH_H */

+ 26
- 36
src/include/gpxe/netdevice.h View File

8
  */
8
  */
9
 
9
 
10
 #include <stdint.h>
10
 #include <stdint.h>
11
-#include <gpxe/llh.h>
12
 #include <gpxe/list.h>
11
 #include <gpxe/list.h>
13
 
12
 
14
 struct net_device;
13
 struct net_device;
15
 struct net_interface;
14
 struct net_interface;
16
 struct pk_buff;
15
 struct pk_buff;
17
 
16
 
17
+/** Maximum length of a link-layer address */
18
+#define MAX_LLH_ADDR_LEN 6
19
+
20
+/** Maximum length of a network-layer address */
21
+#define MAX_NET_ADDR_LEN 4
22
+
18
 /**
23
 /**
19
  * A network device
24
  * A network device
20
  *
25
  *
45
 	/** Poll for received packet
50
 	/** Poll for received packet
46
 	 *
51
 	 *
47
 	 * @v netdev	Network device
52
 	 * @v netdev	Network device
48
-	 * @v retrieve	Flag indicating whether or not to retrieve packet
49
 	 * @v pkb	Packet buffer to contain received packet
53
 	 * @v pkb	Packet buffer to contain received packet
50
 	 * @ret rc	Return status code
54
 	 * @ret rc	Return status code
51
 	 *
55
 	 *
53
 	 * received packet.  If no packet is available, the method
57
 	 * received packet.  If no packet is available, the method
54
 	 * should return -EAGAIN (i.e. this method is *always*
58
 	 * should return -EAGAIN (i.e. this method is *always*
55
 	 * considered to be a non-blocking read).  If a packet is
59
 	 * considered to be a non-blocking read).  If a packet is
56
-	 * available, but @c retrieve is false, the method should
57
-	 * return zero for success.  If a packet is available and @c
58
-	 * retrieve is true, the method should fill the packet buffer
59
-	 * and return zero for success.
60
+	 * available, the method should fill the packet buffer and
61
+	 * return zero for success.
60
 	 */
62
 	 */
61
-	int ( * poll ) ( struct net_device *netdev, int retrieve,
62
-			 struct pk_buff *pkb );
63
-	/** Build media-specific link-layer header
63
+	int ( * poll ) ( struct net_device *netdev, struct pk_buff *pkb );
64
+	/** Build link-layer header
64
 	 *
65
 	 *
65
 	 * @v netdev	Network device
66
 	 * @v netdev	Network device
66
 	 * @v pkb	Packet buffer
67
 	 * @v pkb	Packet buffer
67
 	 * @ret rc	Return status code
68
 	 * @ret rc	Return status code
68
 	 *
69
 	 *
69
-	 * This method should convert the packet buffer's generic
70
-	 * link-layer header (a struct gpxehdr) into a media-specific
71
-	 * link-layer header (e.g. a struct ethhdr).  The generic
72
-	 * header should be removed from the buffer (via pkb_pull())
73
-	 * and the media-specific header should be prepended (via
74
-	 * pkb_push()) in its place.
70
+	 * This method should fill in the link-layer header based on
71
+	 * the metadata contained in @c pkb.
75
 	 *
72
 	 *
76
 	 * If a link-layer header cannot be constructed (e.g. because
73
 	 * If a link-layer header cannot be constructed (e.g. because
77
 	 * of a missing ARP cache entry), then this method should
74
 	 * of a missing ARP cache entry), then this method should
78
 	 * return an error (after transmitting an ARP request, if
75
 	 * return an error (after transmitting an ARP request, if
79
 	 * applicable).
76
 	 * applicable).
80
 	 */
77
 	 */
81
-	int ( * make_media_header ) ( struct net_device *netdev,
82
-				      struct pk_buff *pkb );
83
-	/** Build media-independent link-layer header
78
+	int ( * build_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
79
+	/** Parse link-layer header
84
 	 *
80
 	 *
85
 	 * @v netdev	Network device
81
 	 * @v netdev	Network device
86
 	 * @v pkb	Packet buffer
82
 	 * @v pkb	Packet buffer
87
 	 * @ret rc	Return status code
83
 	 * @ret rc	Return status code
88
 	 *
84
 	 *
89
-	 * This method should convert the packet buffer's
90
-	 * media-specific link-layer header (e.g. a struct ethhdr)
91
-	 * into a generic link-layer header (a struct gpxehdr).  It
92
-	 * performs the converse function of make_media_header().
93
-	 *
94
-	 * Note that the gpxehdr::addr and gpxehdr::addrlen fields
95
-	 * will not be filled in by this function, since doing so
96
-	 * would require understanding the network-layer header.
85
+	 * This method should parse the link-layer header and fill in
86
+	 * the metadata in @c pkb.
97
 	 */
87
 	 */
98
-	int ( * make_generic_header ) ( struct net_device *netdev,
99
-					struct pk_buff *pkb );
88
+	int ( * parse_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
100
 	/** Link-layer protocol
89
 	/** Link-layer protocol
101
 	 *
90
 	 *
102
 	 * This is an ARPHRD_XXX constant, in network byte order.
91
 	 * This is an ARPHRD_XXX constant, in network byte order.
103
 	 */
92
 	 */
104
 	uint16_t ll_proto;
93
 	uint16_t ll_proto;
94
+	/** Link-layer header length */
95
+	uint8_t ll_hlen;
105
 	/** Link-layer address length */
96
 	/** Link-layer address length */
106
 	uint8_t ll_addr_len;
97
 	uint8_t ll_addr_len;
107
 	/** Link-layer address
98
 	/** Link-layer address
151
 	 */
142
 	 */
152
 	int ( * process ) ( struct net_interface *netif,
143
 	int ( * process ) ( struct net_interface *netif,
153
 			    struct pk_buff *pkb );
144
 			    struct pk_buff *pkb );
154
-	/** Add media-independent link-layer header
145
+	/** Fill in packet metadata
155
 	 *
146
 	 *
156
 	 * @v netif	Network interface
147
 	 * @v netif	Network interface
157
 	 * @v pkb	Packet buffer
148
 	 * @v pkb	Packet buffer
158
 	 * @ret rc	Return status code
149
 	 * @ret rc	Return status code
159
 	 *
150
 	 *
160
-	 * This method should prepend a generic link-layer header (a
161
-	 * struct @c gpxehdr) to the packet buffer using pkb_push().
151
+	 * This method should fill in the @c pkb metadata with enough
152
+	 * information to enable net_device::build_llh to construct
153
+	 * the link-layer header.
162
 	 */
154
 	 */
163
-	int ( * add_generic_header ) ( struct net_interface *netif,
164
-				       struct pk_buff *pkb );
155
+	int ( * add_llh_metadata ) ( struct net_interface *netif,
156
+				     struct pk_buff *pkb );
165
 };
157
 };
166
 
158
 
167
 /**
159
 /**
196
 
188
 
197
 extern int register_netdevice ( struct net_device *netdev );
189
 extern int register_netdevice ( struct net_device *netdev );
198
 
190
 
199
-static inline void unregister_netdevice ( struct net_device *netdev __unused ){
200
-	/* Do nothing */
201
-}
191
+extern void unregister_netdevice ( struct net_device *netdev );
202
 
192
 
203
 static inline void free_netdevice ( struct net_device *netdev __unused ) {
193
 static inline void free_netdevice ( struct net_device *netdev __unused ) {
204
 	/* Do nothing */
194
 	/* Do nothing */

+ 32
- 0
src/include/gpxe/pkbuff.h View File

26
 	void *tail;
26
 	void *tail;
27
 	/** End of the buffer */
27
 	/** End of the buffer */
28
         void *end;
28
         void *end;
29
+
30
+	/** The network-layer protocol
31
+	 *
32
+	 * This is the network-layer protocol expressed as an
33
+	 * ETH_P_XXX constant, in network-byte order.
34
+	 */
35
+	uint16_t net_proto;
36
+	/** Flags
37
+	 *
38
+	 * Filled in only on outgoing packets.  Value is the
39
+	 * bitwise-OR of zero or more PKB_FL_XXX constants.
40
+	 */
41
+	uint8_t flags;
42
+	/** Network-layer address length 
43
+	 *
44
+	 * Filled in only on outgoing packets.
45
+	 */
46
+	uint8_t net_addr_len;
47
+	/** Network-layer address
48
+	 *
49
+	 * Filled in only on outgoing packets.
50
+	 */
51
+	void *net_addr;
29
 };
52
 };
30
 
53
 
54
+/** Packet is a broadcast packet */
55
+#define PKB_FL_BROADCAST 0x01
56
+
57
+/** Packet is a multicast packet */
58
+#define PKB_FL_MULTICAST 0x02
59
+
60
+/** Network-layer address is a raw hardware address */
61
+#define PKB_FL_RAW_NET_ADDR 0x04
62
+
31
 /**
63
 /**
32
  * Add data to start of packet buffer
64
  * Add data to start of packet buffer
33
  *
65
  *

+ 20
- 27
src/net/arp.c View File

23
 #include <gpxe/if_ether.h>
23
 #include <gpxe/if_ether.h>
24
 #include <gpxe/if_arp.h>
24
 #include <gpxe/if_arp.h>
25
 #include <gpxe/pkbuff.h>
25
 #include <gpxe/pkbuff.h>
26
-#include <gpxe/llh.h>
27
 #include <gpxe/netdevice.h>
26
 #include <gpxe/netdevice.h>
28
 #include <gpxe/arp.h>
27
 #include <gpxe/arp.h>
29
 
28
 
91
  *
90
  *
92
  * @v netdev		Network device
91
  * @v netdev		Network device
93
  * @v pkb		Packet buffer
92
  * @v pkb		Packet buffer
94
- * @v ll_addr		Buffer to contain link-layer address
93
+ * @ret ll_addr		Pointer to link-layer address
95
  * @ret rc		Return status code
94
  * @ret rc		Return status code
96
  *
95
  *
97
- * The packet buffer must start with a media-independent link-layer
98
- * header (a struct @c gpxehdr).  This function will use the ARP cache
99
- * to look up the link-layer address for the media corresponding to
100
- * @c netdev and the network-layer address as specified in @c gpxehdr.
96
+ * This function will use the ARP cache to look up the link-layer
97
+ * address for the media corresponding to @c netdev and the
98
+ * network-layer address as specified in the @c pkb metadata.
101
  *
99
  *
102
  * If no address is found in the ARP cache, an ARP request will be
100
  * If no address is found in the ARP cache, an ARP request will be
103
  * transmitted, -ENOENT will be returned, and the packet buffer
101
  * transmitted, -ENOENT will be returned, and the packet buffer
104
  * contents will be undefined.
102
  * contents will be undefined.
105
  */
103
  */
106
 int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
104
 int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
107
-		  void *ll_addr ) {
108
-	struct gpxehdr *gpxehdr = pkb->data;
105
+		  const void **ll_addr ) {
109
 	const struct arp_entry *arp;
106
 	const struct arp_entry *arp;
110
 	struct net_interface *netif;
107
 	struct net_interface *netif;
111
 	struct arphdr *arphdr;
108
 	struct arphdr *arphdr;
112
 
109
 
113
 	/* Look for existing entry in ARP table */
110
 	/* Look for existing entry in ARP table */
114
-	arp = arp_find_entry ( netdev->ll_proto, gpxehdr->net_proto,
115
-			       gpxehdr->net_addr, gpxehdr->net_addr_len );
111
+	arp = arp_find_entry ( netdev->ll_proto, pkb->net_proto,
112
+			       pkb->net_addr, pkb->net_addr_len );
116
 	if ( arp ) {
113
 	if ( arp ) {
117
-		memcpy ( ll_addr, arp->ll_addr, netdev->ll_addr_len );
114
+		*ll_addr = arp->ll_addr;
118
 		return 0;
115
 		return 0;
119
 	}
116
 	}
120
 
117
 
121
 	/* Find interface for this protocol */
118
 	/* Find interface for this protocol */
122
-	netif = netdev_find_netif ( netdev, gpxehdr->net_proto );
119
+	netif = netdev_find_netif ( netdev, pkb->net_proto );
123
 	if ( ! netif )
120
 	if ( ! netif )
124
 		return -EAFNOSUPPORT;
121
 		return -EAFNOSUPPORT;
125
 
122
 
126
 	/* Build up ARP request */
123
 	/* Build up ARP request */
127
-	pkb_unput ( pkb, pkb_len ( pkb ) - sizeof ( *gpxehdr ) );
124
+	pkb_empty ( pkb );
128
 	arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
125
 	arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
129
 	arphdr->ar_hrd = netdev->ll_proto;
126
 	arphdr->ar_hrd = netdev->ll_proto;
130
 	arphdr->ar_hln = netdev->ll_addr_len;
127
 	arphdr->ar_hln = netdev->ll_addr_len;
131
-	arphdr->ar_pro = gpxehdr->net_proto;
132
-	arphdr->ar_pln = gpxehdr->net_addr_len;
128
+	arphdr->ar_pro = pkb->net_proto;
129
+	arphdr->ar_pln = pkb->net_addr_len;
133
 	arphdr->ar_op = htons ( ARPOP_REQUEST );
130
 	arphdr->ar_op = htons ( ARPOP_REQUEST );
134
 	memcpy ( pkb_put ( pkb, netdev->ll_addr_len ),
131
 	memcpy ( pkb_put ( pkb, netdev->ll_addr_len ),
135
 		 netdev->ll_addr, netdev->ll_addr_len );
132
 		 netdev->ll_addr, netdev->ll_addr_len );
138
 	memset ( pkb_put ( pkb, netdev->ll_addr_len ),
135
 	memset ( pkb_put ( pkb, netdev->ll_addr_len ),
139
 		 0xff, netdev->ll_addr_len );
136
 		 0xff, netdev->ll_addr_len );
140
 	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
137
 	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
141
-		 gpxehdr->net_addr, netif->net_addr_len );
142
-	pkb_pull ( pkb, sizeof ( *gpxehdr ) );
138
+		 pkb->net_addr, netif->net_addr_len );
143
 
139
 
144
 	/* Locate ARP interface and send ARP request */
140
 	/* Locate ARP interface and send ARP request */
145
 	netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) );
141
 	netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) );
228
  * @v pkb		Packet buffer
224
  * @v pkb		Packet buffer
229
  * @ret rc		Return status code
225
  * @ret rc		Return status code
230
  */
226
  */
231
-int arp_add_generic_header ( struct net_interface *arp_netif __unused,
232
-			     struct pk_buff *pkb ) {
227
+int arp_add_llh_metadata ( struct net_interface *arp_netif __unused,
228
+			   struct pk_buff *pkb ) {
233
 	struct arphdr *arphdr = pkb->data;
229
 	struct arphdr *arphdr = pkb->data;
234
-	struct gpxehdr *gpxehdr;
235
-
236
-	/* We're ARP; we always know the raw link-layer address we want */
237
-	gpxehdr = pkb_push ( pkb, sizeof ( *gpxehdr ) );
238
-	gpxehdr->net_proto = htons ( ETH_P_ARP );
239
-	gpxehdr->flags = GPXE_FL_RAW;
240
-	gpxehdr->net_addr_len = arphdr->ar_hln;
241
-	memcpy ( gpxehdr->net_addr, arp_target_ha ( arphdr ), arphdr->ar_hln );
230
+
231
+	pkb->net_proto = htons ( ETH_P_ARP );
232
+	pkb->flags = PKB_FL_RAW_NET_ADDR;
233
+	pkb->net_addr_len = arphdr->ar_hln;
234
+	pkb->net_addr = arp_target_ha ( arphdr );
242
 	
235
 	
243
 	return 0;
236
 	return 0;
244
 }
237
 }

+ 116
- 0
src/net/ethernet.c View File

1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
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.
8
+ *
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.
13
+ *
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.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <string.h>
21
+#include <byteswap.h>
22
+#include <assert.h>
23
+#include <gpxe/if_ether.h>
24
+#include <gpxe/netdevice.h>
25
+#include <gpxe/pkbuff.h>
26
+#include <gpxe/arp.h>
27
+
28
+/** @file
29
+ *
30
+ * Ethernet protocol
31
+ *
32
+ */
33
+
34
+/** Ethernet broadcast MAC address */
35
+static uint8_t eth_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
36
+
37
+/**
38
+ * Build Ethernet link-layer header
39
+ *
40
+ * @v netdev	Network device
41
+ * @v pkb	Packet buffer
42
+ * @ret rc	Return status code
43
+ *
44
+ * This constructs the Ethernet link-layer header (destination MAC,
45
+ * source MAC, network-layer protocol) based on the metadata found in
46
+ * @c pkb.
47
+ *
48
+ * If the destination MAC address cannot be determined, an ARP request
49
+ * is sent for the requested network-layer address instead.
50
+ */
51
+int eth_build_llh ( struct net_device *netdev, struct pk_buff *pkb ) {
52
+	struct ethhdr *ethhdr = pkb->data;
53
+	const void *eth_dest;
54
+	int rc;
55
+
56
+	/* Do the easy bits */
57
+	ethhdr->h_protocol = pkb->net_proto;
58
+	memcpy ( ethhdr->h_source, netdev->ll_addr,
59
+		 sizeof ( ethhdr->h_source ) );
60
+
61
+	/* Work out the destination MAC address */
62
+	if ( pkb->flags & PKB_FL_RAW_NET_ADDR ) {
63
+		eth_dest = pkb->net_addr;
64
+	} else if ( pkb->flags & PKB_FL_BROADCAST ) {
65
+		eth_dest = eth_broadcast;
66
+	} else if ( pkb->flags & PKB_FL_MULTICAST ) {
67
+		/* IP multicast is a special case; there exists a
68
+		 * direct mapping from IP address to MAC address
69
+		 */
70
+		assert ( pkb->net_proto == htons ( ETH_P_IP ) );
71
+		ethhdr->h_dest[0] = 0x01;
72
+		ethhdr->h_dest[1] = 0x00;
73
+		ethhdr->h_dest[2] = 0x5e;
74
+		ethhdr->h_dest[3] = *( ( char * ) pkb->net_addr + 1 ) & 0x7f;
75
+		ethhdr->h_dest[4] = *( ( char * ) pkb->net_addr + 2 );
76
+		ethhdr->h_dest[5] = *( ( char * ) pkb->net_addr + 3 );
77
+		eth_dest = ethhdr->h_dest;
78
+	} else {
79
+		/* Otherwise, look up the address using ARP */
80
+		if ( ( rc = arp_resolve ( netdev, pkb, &eth_dest ) ) != 0 )
81
+			return rc;
82
+	}
83
+
84
+	/* Fill in destination MAC address */
85
+	memcpy ( ethhdr->h_dest, eth_dest, sizeof ( ethhdr->h_dest ) );
86
+
87
+	return 0;
88
+}
89
+
90
+/**
91
+ * Parse Ethernet link-layer header
92
+ *
93
+ * @v netdev	Network device
94
+ * @v pkb	Packet buffer
95
+ * @ret rc	Return status code
96
+ *
97
+ * This parses the Ethernet link-layer header (destination MAC, source
98
+ * MAC, network-layer protocol) and fills in the metadata in @c pkb.
99
+ */
100
+int eth_parse_llh ( struct net_device *netdev __unused, struct pk_buff *pkb ) {
101
+	struct ethhdr *ethhdr = pkb->data;
102
+
103
+	pkb->net_proto = ethhdr->h_protocol;
104
+	pkb->flags = PKB_FL_RAW_NET_ADDR;
105
+	pkb->net_addr_len = sizeof ( ethhdr->h_dest );
106
+	pkb->net_addr = ethhdr->h_dest;
107
+
108
+	if ( memcmp ( ethhdr->h_dest, eth_broadcast,
109
+		      sizeof ( ethhdr->h_dest ) ) == 0 ) {
110
+		pkb->flags |= PKB_FL_BROADCAST;
111
+	} else if ( ethhdr->h_dest[0] & 0x01 ) {
112
+		pkb->flags |= PKB_FL_MULTICAST;
113
+	}
114
+
115
+	return 0;
116
+}

Loading…
Cancel
Save