1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Ethernet Datalink File: net_ether.c
6 * This module provides a simple datalink (LLC1) interface
7 * capable of demultiplexing standard DIX-style Ethernet packets.
9 * Author: Mitch Lichtenberg (mpl@broadcom.com)
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
16 * This software is furnished under license and may be used and
17 * copied only in accordance with the following terms and
18 * conditions. Subject to these conditions, you may download,
19 * copy, install, use, modify and distribute modified or unmodified
20 * copies of this software in source and/or binary form. No title
21 * or ownership is transferred hereby.
23 * 1) Any source code used, modified or distributed must reproduce
24 * and retain this copyright notice and list of conditions
25 * as they appear in the source file.
27 * 2) No right is granted to use any trade name, trademark, or
28 * logo of Broadcom Corporation. The "Broadcom Corporation"
29 * name may not be used to endorse or promote products derived
30 * from this software without the prior written permission of
31 * Broadcom Corporation.
33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGE.
46 ********************************************************************* */
48 #include "lib_types.h"
49 #include "lib_string.h"
50 #include "lib_queue.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
55 #include "cfe_devfuncs.h"
56 #include "cfe_ioctl.h"
57 #include "cfe_error.h"
60 #include "net_ether.h"
63 /* *********************************************************************
65 ********************************************************************* */
67 #define ETH_MAX_PORTS 4
68 #define ETH_MAX_BUFFERS 8
70 /* *********************************************************************
72 ********************************************************************* */
74 typedef struct ether_port_s
{
79 int (*ep_rxcallback
)(ebuf_t
*buf
,void *ref
);
84 ether_port_t
*eth_ports
;
86 uint8_t eth_hwaddr
[6];
91 /* *********************************************************************
93 ********************************************************************* */
95 const uint8_t eth_broadcast
[ENET_ADDR_LEN
] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
98 /* *********************************************************************
99 * eth_open(eth,ptye,pdata,cb)
101 * Open an Ethernet portal.
104 * eth - ethernet context
105 * ptype - protocol type (ETH_PTYPE_xxx)
106 * pdata - protocol data (two bytes for DIX protocols)
107 * cb - callback for receive packets
111 * or <0 if error occured
112 ********************************************************************* */
114 int eth_open(ether_info_t
*eth
,int ptype
,char *pdata
,
115 int (*cb
)(ebuf_t
*buf
,void *ref
),void *ref
)
122 for (portnum
= 0; portnum
< ETH_MAX_PORTS
; portnum
++,p
++) {
123 if (p
->ep_rxcallback
== NULL
) break;
126 if (portnum
== ETH_MAX_PORTS
) {
127 return CFE_ERR_NOHANDLES
; /* no ports left */
132 p
->ep_proto
[0] = pdata
[0];
133 p
->ep_proto
[1] = pdata
[1];
134 p
->ep_mtu
= ENET_MAX_PKT
- ENET_DIX_HEADER
;
137 case ETH_PTYPE_802SAP
:
138 case ETH_PTYPE_802SNAP
:
141 * we only support DIX etypes right now. If we ever want to support
142 * non-IP stacks (unlikely) this will need to change.
144 return CFE_ERR_UNSUPPORTED
;
148 p
->ep_rxcallback
= cb
;
149 p
->ep_dev
= eth
->eth_devhandle
;
156 /* *********************************************************************
157 * eth_close(eth,port)
159 * Close an Ethernet portal, freeing resources allocated to it.
162 * eth - ethernet context
163 * port - portal number
167 ********************************************************************* */
169 void eth_close(ether_info_t
*eth
,int port
)
171 ether_port_t
*p
= &(eth
->eth_ports
[port
]);
174 p
->ep_rxcallback
= NULL
;
176 memset(&(p
->ep_proto
[0]),0,sizeof(p
->ep_proto
));
180 /* *********************************************************************
181 * eth_findport(eth,buf)
183 * Locate the portal associated with a particular Ethernet packet.
184 * Parse the packet enough to determine if it's addressed
185 * correctly and to a valid protocol, and then look up the
186 * corresponding portal.
189 * eth - ethernet context
190 * buf - ethernet buffer to check
193 * eth_port_t structure or NULL if packet should be dropped
194 ********************************************************************* */
196 static ether_port_t
*eth_findport(ether_info_t
*eth
,ebuf_t
*buf
)
202 * A few pre-flight checks: packets *from* multicast addresses
206 if (buf
->eb_ptr
[6] & 1) return NULL
;
209 * Packets smaller than minimum size are not allowed.
212 if (buf
->eb_length
< 60) return NULL
;
215 * Packets with bad status are not allowed
220 * Okay, scan the port list and find the matching portal.
223 for (idx
= 0, p
= eth
->eth_ports
; idx
< ETH_MAX_PORTS
; idx
++,p
++) {
224 if (!p
->ep_rxcallback
) continue; /* port not in use */
226 switch (p
->ep_ptype
) {
228 if ((p
->ep_proto
[0] == buf
->eb_ptr
[12]) &&
229 (p
->ep_proto
[1] == buf
->eb_ptr
[13])) {
230 ebuf_skip(buf
,ENET_DIX_HEADER
);
234 case ETH_PTYPE_802SAP
:
235 case ETH_PTYPE_802SNAP
:
244 /* *********************************************************************
247 * Poll devices and process inbound packets. If new packets arrive,
248 * call the appropriate callback routine.
251 * eth - ethernet context
255 ********************************************************************* */
257 void eth_poll(ether_info_t
*eth
)
265 * If no packets, just get out now
268 if (cfe_inpstat(eth
->eth_devhandle
) == 0) return;
271 * get a packet from the free list
274 buf
= (ebuf_t
*) q_deqnext(&(eth
->eth_freelist
));
278 * Receive network data into the packet buffer
282 res
= cfe_read(eth
->eth_devhandle
,buf
->eb_ptr
,ENET_MAX_PKT
);
285 * if receive error, get out now.
289 q_enqueue(&(eth
->eth_freelist
),(queue_t
*) buf
);
294 * init the rest of the fields in the ebuf
297 buf
->eb_length
= res
;
299 buf
->eb_device
= eth
;
303 * Look up the portal to receive the new packet
306 p
= eth_findport(eth
,buf
);
309 * Call the callback routine if we want to keep this
310 * buffer. Otherwise, drop it on the floor
314 buf
->eb_port
= p
- eth
->eth_ports
;
315 res
= (*(p
->ep_rxcallback
))(buf
,p
->ep_ref
);
316 if (res
== ETH_DROP
) eth_free(buf
);
324 /* *********************************************************************
325 * eth_gethwaddr(eth,hwaddr)
327 * Obtain the hardware address of the Ethernet interface.
330 * eth - ethernet context
331 * hwaddr - place to put hardware address - 6 bytes
335 ********************************************************************* */
337 void eth_gethwaddr(ether_info_t
*eth
,uint8_t *hwaddr
)
339 memcpy(hwaddr
,eth
->eth_hwaddr
,ENET_ADDR_LEN
);
342 /* *********************************************************************
343 * eth_sethwaddr(eth,hwaddr)
345 * Set the hardware address of the Ethernet interface.
348 * eth - ethernet context
349 * hwaddr - new hardware address - 6 bytes
353 ********************************************************************* */
355 void eth_sethwaddr(ether_info_t
*eth
,uint8_t *hwaddr
)
359 memcpy(eth
->eth_hwaddr
,hwaddr
,ENET_ADDR_LEN
);
360 cfe_ioctl(eth
->eth_devhandle
,IOCTL_ETHER_SETHWADDR
,&(eth
->eth_hwaddr
[0]),
361 sizeof(eth
->eth_hwaddr
),&retlen
,0);
367 /* *********************************************************************
368 * eth_setspeed(eth,speed)
370 * Set the speed of the Ethernet interface.
373 * eth - ethernet context
374 * speed - target speed (or auto for automatic)
378 ********************************************************************* */
380 int eth_setspeed(ether_info_t
*eth
,int speed
)
384 return cfe_ioctl(eth
->eth_devhandle
,IOCTL_ETHER_SETSPEED
,
385 (uint8_t *) &speed
,sizeof(speed
),&retlen
,0);
389 /* *********************************************************************
390 * eth_setloopback(eth,loop)
392 * Configure loopback mode options for the Ethernet
395 * eth - ethernet context
396 * loop - loopback mode to set
400 ********************************************************************* */
402 int eth_setloopback(ether_info_t
*eth
,int loop
)
406 return cfe_ioctl(eth
->eth_devhandle
,IOCTL_ETHER_SETLOOPBACK
,
407 (uint8_t *) &loop
,sizeof(loop
),&retlen
,0);
411 /* *********************************************************************
412 * eth_getspeed(eth,speed)
414 * Get the current setting for the Ethernet speed (note that this
415 * is the speed we want to achieve, not the current speed)
418 * eth - ethernet context
419 * speed - pointer to int to receive speed
423 ********************************************************************* */
425 int eth_getspeed(ether_info_t
*eth
,int *speed
)
429 return cfe_ioctl(eth
->eth_devhandle
,IOCTL_ETHER_GETSPEED
,
430 (uint8_t *) speed
,sizeof(*speed
),&retlen
,0);
434 /* *********************************************************************
435 * eth_getloopback(eth,loop)
437 * Read the loopback state of the Ethernet interface
440 * eth - ethernet context
441 * loop - pointer to int to receive loopback state
445 ********************************************************************* */
447 int eth_getloopback(ether_info_t
*eth
,int *loop
)
451 return cfe_ioctl(eth
->eth_devhandle
,IOCTL_ETHER_GETLOOPBACK
,
452 (uint8_t *) loop
,sizeof(*loop
),&retlen
,0);
456 /* *********************************************************************
462 * buf - ebuf structure describing packet
463 * dest - destination hardware address
468 ********************************************************************* */
470 int eth_send(ebuf_t
*buf
,uint8_t *dest
)
472 ether_info_t
*eth
= buf
->eb_device
;
473 ether_port_t
*p
= &(eth
->eth_ports
[buf
->eb_port
]);
476 switch (p
->ep_ptype
) {
478 ebuf_seek(buf
,-ENET_DIX_HEADER
);
479 ebuf_put_bytes(buf
,dest
,ENET_ADDR_LEN
);
480 ebuf_put_bytes(buf
,eth
->eth_hwaddr
,ENET_ADDR_LEN
);
481 ebuf_put_bytes(buf
,p
->ep_proto
,2);
482 /* adjust pointer and add in DIX header length */
483 ebuf_prepend(buf
,ENET_DIX_HEADER
);
485 case ETH_PTYPE_802SAP
:
486 case ETH_PTYPE_802SNAP
:
488 eth_free(buf
); /* should not happen */
489 return CFE_ERR_UNSUPPORTED
;
492 res
= cfe_write(p
->ep_dev
,ebuf_ptr(buf
),ebuf_length(buf
));
498 /* *********************************************************************
499 * eth_alloc(eth,port)
501 * Allocate an Ethernet buffer. Ethernet buffers know what
502 * ports they are associated with, since we need to reserve
503 * space for the EThernet header, which might vary in size
507 * eth - ethernet context
511 * ebuf, or NULL if no ebufs left
512 ********************************************************************* */
514 ebuf_t
*eth_alloc(ether_info_t
*eth
,int port
)
517 ether_port_t
*p
= &(eth
->eth_ports
[port
]);
519 buf
= (ebuf_t
*) q_deqnext(&(eth
->eth_freelist
));
520 if (buf
== NULL
) return NULL
;
524 buf
->eb_device
= eth
;
527 switch (p
->ep_ptype
) {
531 ebuf_seek(buf
,ENET_DIX_HEADER
);
533 case ETH_PTYPE_802SAP
:
534 case ETH_PTYPE_802SNAP
:
540 * 'eb_ptr' points at new data, length is cleared.
541 * We will add the length back in at send time when the
542 * ethernet header is filled in.
549 /* *********************************************************************
559 ********************************************************************* */
561 void eth_free(ebuf_t
*buf
)
563 ether_info_t
*eth
= buf
->eb_device
;
565 q_enqueue(&(eth
->eth_freelist
),(queue_t
*) buf
);
569 /* *********************************************************************
570 * eth_getmtu(eth,port)
572 * Return the mtu of the specified Ethernet port. The mtu
573 * is the maximum number of bytes you can put in the buffer,
574 * excluding the Ethernet header.
577 * eth - ethernet context
582 ********************************************************************* */
585 int eth_getmtu(ether_info_t
*eth
,int port
)
587 ether_port_t
*p
= &(eth
->eth_ports
[port
]);
593 /* *********************************************************************
596 * Create an Ethernet context for a particular Ethernet device.
599 * devname - device name for underlying Ethernet driver
602 * ethernet context, or NULL of it could not be created.
603 ********************************************************************* */
605 ether_info_t
*eth_init(char *devname
)
614 * Open the device driver
617 devhandle
= cfe_open(devname
);
618 if (devhandle
< 0) return NULL
;
620 eth
= KMALLOC(sizeof(ether_info_t
),0);
622 cfe_close(devhandle
);
626 memset(eth
,0,sizeof(ether_info_t
));
629 * Obtain hardware address
632 cfe_ioctl(devhandle
,IOCTL_ETHER_GETHWADDR
,&(eth
->eth_hwaddr
[0]),
633 sizeof(eth
->eth_hwaddr
),&retlen
,0);
636 * Allocate portal table
639 eth
->eth_ports
= KMALLOC(ETH_MAX_PORTS
*sizeof(ether_port_t
),0);
640 if (!eth
->eth_ports
) {
641 cfe_close(devhandle
);
646 memset(eth
->eth_ports
,0,ETH_MAX_PORTS
*sizeof(ether_port_t
));
649 * Allocate buffer pool
652 eth
->eth_bufpool
= (ebuf_t
*) KMALLOC(sizeof(ebuf_t
)*ETH_MAX_BUFFERS
,0);
653 if (!eth
->eth_bufpool
) {
654 cfe_close(devhandle
);
655 KFREE(eth
->eth_ports
);
661 * Chain buffers onto the free list
664 q_init(&(eth
->eth_freelist
));
665 buf
= eth
->eth_bufpool
;
666 for (idx
= 0; idx
< ETH_MAX_BUFFERS
; idx
++) {
667 q_enqueue(&(eth
->eth_freelist
),(queue_t
*) buf
);
672 * Remember the device handle
675 eth
->eth_devhandle
= devhandle
;
681 /* *********************************************************************
684 * Close and free up an Ethernet context
687 * eth - ethernet context
691 ********************************************************************* */
693 void eth_uninit(ether_info_t
*eth
)
695 cfe_close(eth
->eth_devhandle
);
696 KFREE(eth
->eth_bufpool
);
697 KFREE(eth
->eth_ports
);