GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / net / net_ether.c
blob453b88ad030b4d477ad5a0a717cd6d23f693d1e2
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Ethernet Datalink File: net_ether.c
5 *
6 * This module provides a simple datalink (LLC1) interface
7 * capable of demultiplexing standard DIX-style Ethernet packets.
8 *
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"
54 #include "cfe_iocb.h"
55 #include "cfe_devfuncs.h"
56 #include "cfe_ioctl.h"
57 #include "cfe_error.h"
59 #include "net_ebuf.h"
60 #include "net_ether.h"
63 /* *********************************************************************
64 * Constants
65 ********************************************************************* */
67 #define ETH_MAX_PORTS 4
68 #define ETH_MAX_BUFFERS 8
70 /* *********************************************************************
71 * Types
72 ********************************************************************* */
74 typedef struct ether_port_s {
75 int ep_dev;
76 uint8_t ep_proto[8];
77 int ep_ptype;
78 int ep_mtu;
79 int (*ep_rxcallback)(ebuf_t *buf,void *ref);
80 void *ep_ref;
81 } ether_port_t;
83 struct ether_info_s {
84 ether_port_t *eth_ports;
85 queue_t eth_freelist;
86 uint8_t eth_hwaddr[6];
87 int eth_devhandle;
88 ebuf_t *eth_bufpool;
91 /* *********************************************************************
92 * Globals
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.
103 * Input parameters:
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
109 * Return value:
110 * portal number
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)
117 ether_port_t *p;
118 int portnum;
120 p = eth->eth_ports;
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 */
130 switch (ptype) {
131 case ETH_PTYPE_DIX:
132 p->ep_proto[0] = pdata[0];
133 p->ep_proto[1] = pdata[1];
134 p->ep_mtu = ENET_MAX_PKT - ENET_DIX_HEADER;
135 break;
137 case ETH_PTYPE_802SAP:
138 case ETH_PTYPE_802SNAP:
139 default:
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;
147 p->ep_ptype = ptype;
148 p->ep_rxcallback = cb;
149 p->ep_dev = eth->eth_devhandle;
150 p->ep_ref = ref;
152 return portnum;
156 /* *********************************************************************
157 * eth_close(eth,port)
159 * Close an Ethernet portal, freeing resources allocated to it.
161 * Input parameters:
162 * eth - ethernet context
163 * port - portal number
165 * Return value:
166 * nothing
167 ********************************************************************* */
169 void eth_close(ether_info_t *eth,int port)
171 ether_port_t *p = &(eth->eth_ports[port]);
173 p->ep_ptype = 0;
174 p->ep_rxcallback = NULL;
175 p->ep_dev = 0;
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.
188 * Input parameters:
189 * eth - ethernet context
190 * buf - ethernet buffer to check
192 * Return value:
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)
198 int idx;
199 ether_port_t *p;
202 * A few pre-flight checks: packets *from* multicast addresses
203 * are not allowed.
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) {
227 case ETH_PTYPE_DIX:
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);
231 return p;
233 break;
234 case ETH_PTYPE_802SAP:
235 case ETH_PTYPE_802SNAP:
236 default:
237 break;
241 return NULL;
244 /* *********************************************************************
245 * eth_poll(eth)
247 * Poll devices and process inbound packets. If new packets arrive,
248 * call the appropriate callback routine.
250 * Input parameters:
251 * eth - ethernet context
253 * Return value:
254 * nothing
255 ********************************************************************* */
257 void eth_poll(ether_info_t *eth)
259 ebuf_t *buf;
260 ether_port_t *p;
261 int res;
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));
275 if (!buf) return;
278 * Receive network data into the packet buffer
281 ebuf_init_rx(buf);
282 res = cfe_read(eth->eth_devhandle,buf->eb_ptr,ENET_MAX_PKT);
285 * if receive error, get out now.
288 if (res <= 0) {
289 q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
290 return;
294 * init the rest of the fields in the ebuf
297 buf->eb_length = res;
298 buf->eb_status = 0;
299 buf->eb_device = eth;
300 buf->eb_usrdata = 0;
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
313 if (p) {
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);
318 else {
319 eth_free(buf);
324 /* *********************************************************************
325 * eth_gethwaddr(eth,hwaddr)
327 * Obtain the hardware address of the Ethernet interface.
329 * Input parameters:
330 * eth - ethernet context
331 * hwaddr - place to put hardware address - 6 bytes
333 * Return value:
334 * nothing
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.
347 * Input parameters:
348 * eth - ethernet context
349 * hwaddr - new hardware address - 6 bytes
351 * Return value:
352 * nothing
353 ********************************************************************* */
355 void eth_sethwaddr(ether_info_t *eth,uint8_t *hwaddr)
357 int retlen;
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.
372 * Input parameters:
373 * eth - ethernet context
374 * speed - target speed (or auto for automatic)
376 * Return value:
377 * nothing
378 ********************************************************************* */
380 int eth_setspeed(ether_info_t *eth,int speed)
382 int retlen;
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
394 * Input parameters:
395 * eth - ethernet context
396 * loop - loopback mode to set
398 * Return value:
399 * nothing
400 ********************************************************************* */
402 int eth_setloopback(ether_info_t *eth,int loop)
404 int retlen;
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)
417 * Input parameters:
418 * eth - ethernet context
419 * speed - pointer to int to receive speed
421 * Return value:
422 * nothing
423 ********************************************************************* */
425 int eth_getspeed(ether_info_t *eth,int *speed)
427 int retlen;
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
439 * Input parameters:
440 * eth - ethernet context
441 * loop - pointer to int to receive loopback state
443 * Return value:
444 * nothing
445 ********************************************************************* */
447 int eth_getloopback(ether_info_t *eth,int *loop)
449 int retlen;
451 return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETLOOPBACK,
452 (uint8_t *) loop,sizeof(*loop),&retlen,0);
456 /* *********************************************************************
457 * eth_send(buf,dest)
459 * Transmit a packet.
461 * Input parameters:
462 * buf - ebuf structure describing packet
463 * dest - destination hardware address
465 * Return value:
466 * 0 - no error
467 * else error code
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]);
474 int res;
476 switch (p->ep_ptype) {
477 case ETH_PTYPE_DIX:
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);
484 break;
485 case ETH_PTYPE_802SAP:
486 case ETH_PTYPE_802SNAP:
487 default:
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));
495 return res;
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
504 * for DIX, 802, etc.
506 * Input parameters:
507 * eth - ethernet context
508 * port - portal ID
510 * Return value:
511 * ebuf, or NULL if no ebufs left
512 ********************************************************************* */
514 ebuf_t *eth_alloc(ether_info_t *eth,int port)
516 ebuf_t *buf;
517 ether_port_t *p = &(eth->eth_ports[port]);
519 buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist));
520 if (buf == NULL) return NULL;
522 buf->eb_status = 0;
523 buf->eb_port = port;
524 buf->eb_device = eth;
525 ebuf_init_tx(buf);
527 switch (p->ep_ptype) {
528 case ETH_PTYPE_NONE:
529 break;
530 case ETH_PTYPE_DIX:
531 ebuf_seek(buf,ENET_DIX_HEADER);
532 break;
533 case ETH_PTYPE_802SAP:
534 case ETH_PTYPE_802SNAP:
535 default:
536 break;
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.
544 buf->eb_length = 0;
546 return buf;
549 /* *********************************************************************
550 * eth_free(buf)
552 * Free an ebuf.
554 * Input parameters:
555 * buf - ebuf to free
557 * Return value:
558 * nothing
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.
576 * Input parameters:
577 * eth - ethernet context
578 * port - portal ID
580 * Return value:
581 * number of bytes
582 ********************************************************************* */
585 int eth_getmtu(ether_info_t *eth,int port)
587 ether_port_t *p = &(eth->eth_ports[port]);
589 return p->ep_mtu;
593 /* *********************************************************************
594 * eth_init(devname)
596 * Create an Ethernet context for a particular Ethernet device.
598 * Input parameters:
599 * devname - device name for underlying Ethernet driver
601 * Return value:
602 * ethernet context, or NULL of it could not be created.
603 ********************************************************************* */
605 ether_info_t *eth_init(char *devname)
607 int idx;
608 ebuf_t *buf;
609 ether_info_t *eth;
610 int devhandle;
611 int retlen;
614 * Open the device driver
617 devhandle = cfe_open(devname);
618 if (devhandle < 0) return NULL;
620 eth = KMALLOC(sizeof(ether_info_t),0);
621 if (!eth) {
622 cfe_close(devhandle);
623 return NULL;
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);
642 KFREE(eth);
643 return NULL;
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);
656 KFREE(eth);
657 return NULL;
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);
668 buf++;
672 * Remember the device handle
675 eth->eth_devhandle = devhandle;
677 return eth;
681 /* *********************************************************************
682 * eth_uninit(eth)
684 * Close and free up an Ethernet context
686 * Input parameters:
687 * eth - ethernet context
689 * Return value:
690 * nothing
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);
698 KFREE(eth);