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)
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
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.
22    *
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.
26    *
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.
32    *
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    ********************************************************************* */
47
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"
53
54#include "cfe_iocb.h"
55#include "cfe_devfuncs.h"
56#include "cfe_ioctl.h"
57#include "cfe_error.h"
58
59#include "net_ebuf.h"
60#include "net_ether.h"
61
62
63/*  *********************************************************************
64    *  Constants
65    ********************************************************************* */
66
67#define ETH_MAX_PORTS	4
68#define ETH_MAX_BUFFERS	8
69
70/*  *********************************************************************
71    *  Types
72    ********************************************************************* */
73
74typedef 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;
82
83struct 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;
89};
90
91/*  *********************************************************************
92    *  Globals
93    ********************************************************************* */
94
95const uint8_t eth_broadcast[ENET_ADDR_LEN] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
96
97
98/*  *********************************************************************
99    *  eth_open(eth,ptye,pdata,cb)
100    *
101    *  Open an Ethernet portal.
102    *
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
108    *
109    *  Return value:
110    *  	   portal number
111    *  	   or <0 if error occured
112    ********************************************************************* */
113
114int eth_open(ether_info_t *eth,int ptype,char *pdata,
115	     int (*cb)(ebuf_t *buf,void *ref),void *ref)
116{
117    ether_port_t *p;
118    int portnum;
119
120    p = eth->eth_ports;
121
122    for (portnum = 0; portnum < ETH_MAX_PORTS; portnum++,p++) {
123	if (p->ep_rxcallback == NULL) break;
124	}
125
126    if (portnum == ETH_MAX_PORTS) {
127	return CFE_ERR_NOHANDLES;	/* no ports left */
128	}
129
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;
136
137	case ETH_PTYPE_802SAP:
138	case ETH_PTYPE_802SNAP:
139	default:
140	    /*
141	     * we only support DIX etypes right now.  If we ever want to support
142	     * non-IP stacks (unlikely) this will need to change.
143	     */
144	    return CFE_ERR_UNSUPPORTED;
145	}
146
147    p->ep_ptype = ptype;
148    p->ep_rxcallback = cb;
149    p->ep_dev = eth->eth_devhandle;
150    p->ep_ref = ref;
151
152    return portnum;
153}
154
155
156/*  *********************************************************************
157    *  eth_close(eth,port)
158    *
159    *  Close an Ethernet portal, freeing resources allocated to it.
160    *
161    *  Input parameters:
162    *  	   eth - ethernet context
163    *  	   port - portal number
164    *
165    *  Return value:
166    *  	   nothing
167    ********************************************************************* */
168
169void eth_close(ether_info_t *eth,int port)
170{
171    ether_port_t *p = &(eth->eth_ports[port]);
172
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));
177}
178
179
180/*  *********************************************************************
181    *  eth_findport(eth,buf)
182    *
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.
187    *
188    *  Input parameters:
189    *  	   eth - ethernet context
190    *  	   buf - ethernet buffer to check
191    *
192    *  Return value:
193    *  	   eth_port_t structure or NULL if packet should be dropped
194    ********************************************************************* */
195
196static ether_port_t *eth_findport(ether_info_t *eth,ebuf_t *buf)
197{
198    int idx;
199    ether_port_t *p;
200
201    /*
202     * A few pre-flight checks: packets *from* multicast addresses
203     * are not allowed.
204     */
205
206    if (buf->eb_ptr[6] & 1) return NULL;
207
208    /*
209     * Packets smaller than minimum size are not allowed.
210     */
211
212    if (buf->eb_length < 60) return NULL;
213
214    /*
215     * Packets with bad status are not allowed
216     */
217
218
219    /*
220     * Okay, scan the port list and find the matching portal.
221     */
222
223    for (idx = 0, p = eth->eth_ports; idx < ETH_MAX_PORTS; idx++,p++) {
224	if (!p->ep_rxcallback) continue; /* port not in use */
225
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;
232		    }
233		break;
234	    case ETH_PTYPE_802SAP:
235	    case ETH_PTYPE_802SNAP:
236	    default:
237		break;
238	    }
239	}
240
241    return NULL;
242}
243
244/*  *********************************************************************
245    *  eth_poll(eth)
246    *
247    *  Poll devices and process inbound packets.  If new packets arrive,
248    *  call the appropriate callback routine.
249    *
250    *  Input parameters:
251    *  	   eth - ethernet context
252    *
253    *  Return value:
254    *  	   nothing
255    ********************************************************************* */
256
257void eth_poll(ether_info_t *eth)
258{
259    ebuf_t *buf;
260    ether_port_t *p;
261    int res;
262
263
264    /*
265     * If no packets, just get out now
266     */
267
268    if (cfe_inpstat(eth->eth_devhandle) == 0) return;
269
270    /*
271     * get a packet from the free list
272     */
273
274    buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist));
275    if (!buf) return;
276
277    /*
278     * Receive network data into the packet buffer
279     */
280
281    ebuf_init_rx(buf);
282    res = cfe_read(eth->eth_devhandle,buf->eb_ptr,ENET_MAX_PKT);
283
284    /*
285     * if receive error, get out now.
286     */
287
288    if (res <= 0) {
289	q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
290	return;
291	}
292
293    /*
294     * init the rest of the fields in the ebuf
295     */
296
297    buf->eb_length = res;
298    buf->eb_status = 0;
299    buf->eb_device = eth;
300    buf->eb_usrdata = 0;
301
302    /*
303     * Look up the portal to receive the new packet
304     */
305
306    p = eth_findport(eth,buf);
307
308    /*
309     * Call the callback routine if we want to keep this
310     * buffer.  Otherwise, drop it on the floor
311     */
312
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);
317	}
318    else {
319	eth_free(buf);
320	}
321}
322
323
324/*  *********************************************************************
325    *  eth_gethwaddr(eth,hwaddr)
326    *
327    *  Obtain the hardware address of the Ethernet interface.
328    *
329    *  Input parameters:
330    *  	   eth - ethernet context
331    *  	   hwaddr - place to put hardware address - 6 bytes
332    *
333    *  Return value:
334    *  	   nothing
335    ********************************************************************* */
336
337void eth_gethwaddr(ether_info_t *eth,uint8_t *hwaddr)
338{
339    memcpy(hwaddr,eth->eth_hwaddr,ENET_ADDR_LEN);
340}
341
342/*  *********************************************************************
343    *  eth_sethwaddr(eth,hwaddr)
344    *
345    *  Set the hardware address of the Ethernet interface.
346    *
347    *  Input parameters:
348    *  	   eth - ethernet context
349    *  	   hwaddr - new hardware address - 6 bytes
350    *
351    *  Return value:
352    *  	   nothing
353    ********************************************************************* */
354
355void eth_sethwaddr(ether_info_t *eth,uint8_t *hwaddr)
356{
357    int retlen;
358
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);
362
363}
364
365
366
367/*  *********************************************************************
368    *  eth_setspeed(eth,speed)
369    *
370    *  Set the speed of the Ethernet interface.
371    *
372    *  Input parameters:
373    *  	   eth - ethernet context
374    *  	   speed - target speed (or auto for automatic)
375    *
376    *  Return value:
377    *  	   nothing
378    ********************************************************************* */
379
380int eth_setspeed(ether_info_t *eth,int speed)
381{
382    int retlen;
383
384    return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETSPEED,
385		     (uint8_t *) &speed,sizeof(speed),&retlen,0);
386
387}
388
389/*  *********************************************************************
390    *  eth_setloopback(eth,loop)
391    *
392    *  Configure loopback mode options for the Ethernet
393    *
394    *  Input parameters:
395    *  	   eth - ethernet context
396    *  	   loop - loopback mode to set
397    *
398    *  Return value:
399    *  	   nothing
400    ********************************************************************* */
401
402int eth_setloopback(ether_info_t *eth,int loop)
403{
404    int retlen;
405
406    return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETLOOPBACK,
407		     (uint8_t *) &loop,sizeof(loop),&retlen,0);
408
409}
410
411/*  *********************************************************************
412    *  eth_getspeed(eth,speed)
413    *
414    *  Get the current setting for the Ethernet speed (note that this
415    *  is the speed we want to achieve, not the current speed)
416    *
417    *  Input parameters:
418    *  	   eth - ethernet context
419    *  	   speed - pointer to int to receive speed
420    *
421    *  Return value:
422    *  	   nothing
423    ********************************************************************* */
424
425int eth_getspeed(ether_info_t *eth,int *speed)
426{
427    int retlen;
428
429    return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETSPEED,
430		     (uint8_t *) speed,sizeof(*speed),&retlen,0);
431
432}
433
434/*  *********************************************************************
435    *  eth_getloopback(eth,loop)
436    *
437    *  Read the loopback state of the Ethernet interface
438    *
439    *  Input parameters:
440    *  	   eth - ethernet context
441    *  	   loop - pointer to int to receive loopback state
442    *
443    *  Return value:
444    *  	   nothing
445    ********************************************************************* */
446
447int eth_getloopback(ether_info_t *eth,int *loop)
448{
449    int retlen;
450
451    return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETLOOPBACK,
452		     (uint8_t *) loop,sizeof(*loop),&retlen,0);
453
454}
455
456/*  *********************************************************************
457    *  eth_send(buf,dest)
458    *
459    *  Transmit a packet.
460    *
461    *  Input parameters:
462    *  	   buf - ebuf structure describing packet
463    *  	   dest - destination hardware address
464    *
465    *  Return value:
466    *  	   0 - no error
467    *  	   else error code
468    ********************************************************************* */
469
470int eth_send(ebuf_t *buf,uint8_t *dest)
471{
472    ether_info_t *eth = buf->eb_device;
473    ether_port_t *p = &(eth->eth_ports[buf->eb_port]);
474    int res;
475
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;
490	}
491
492    res = cfe_write(p->ep_dev,ebuf_ptr(buf),ebuf_length(buf));
493
494
495    return res;
496}
497
498/*  *********************************************************************
499    *  eth_alloc(eth,port)
500    *
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.
505    *
506    *  Input parameters:
507    *  	   eth - ethernet context
508    *  	   port - portal ID
509    *
510    *  Return value:
511    *  	   ebuf, or NULL if no ebufs left
512    ********************************************************************* */
513
514ebuf_t *eth_alloc(ether_info_t *eth,int port)
515{
516    ebuf_t *buf;
517    ether_port_t *p = &(eth->eth_ports[port]);
518
519    buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist));
520    if (buf == NULL) return NULL;
521
522    buf->eb_status = 0;
523    buf->eb_port = port;
524    buf->eb_device = eth;
525    ebuf_init_tx(buf);
526
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;
537	}
538
539    /*
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.
543     */
544    buf->eb_length = 0;
545
546    return buf;
547}
548
549/*  *********************************************************************
550    *  eth_free(buf)
551    *
552    *  Free an ebuf.
553    *
554    *  Input parameters:
555    *  	   buf - ebuf to free
556    *
557    *  Return value:
558    *  	   nothing
559    ********************************************************************* */
560
561void eth_free(ebuf_t *buf)
562{
563    ether_info_t *eth = buf->eb_device;
564
565    q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
566}
567
568
569/*  *********************************************************************
570    *  eth_getmtu(eth,port)
571    *
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.
575    *
576    *  Input parameters:
577    *  	   eth - ethernet context
578    *  	   port - portal ID
579    *
580    *  Return value:
581    *  	   number of bytes
582    ********************************************************************* */
583
584
585int eth_getmtu(ether_info_t *eth,int port)
586{
587    ether_port_t *p = &(eth->eth_ports[port]);
588
589    return p->ep_mtu;
590}
591
592
593/*  *********************************************************************
594    *  eth_init(devname)
595    *
596    *  Create an Ethernet context for a particular Ethernet device.
597    *
598    *  Input parameters:
599    *  	   devname - device name for underlying Ethernet driver
600    *
601    *  Return value:
602    *  	   ethernet context, or NULL of it could not be created.
603    ********************************************************************* */
604
605ether_info_t *eth_init(char *devname)
606{
607    int idx;
608    ebuf_t *buf;
609    ether_info_t *eth;
610    int devhandle;
611    int retlen;
612
613    /*
614     * Open the device driver
615     */
616
617    devhandle = cfe_open(devname);
618    if (devhandle < 0) return NULL;
619
620    eth = KMALLOC(sizeof(ether_info_t),0);
621    if (!eth) {
622	cfe_close(devhandle);
623	return NULL;
624	}
625
626    memset(eth,0,sizeof(ether_info_t));
627
628    /*
629     * Obtain hardware address
630     */
631
632    cfe_ioctl(devhandle,IOCTL_ETHER_GETHWADDR,&(eth->eth_hwaddr[0]),
633	      sizeof(eth->eth_hwaddr),&retlen,0);
634
635    /*
636     * Allocate portal table
637     */
638
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;
644	}
645
646    memset(eth->eth_ports,0,ETH_MAX_PORTS*sizeof(ether_port_t));
647
648    /*
649     * Allocate buffer pool
650     */
651
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;
658	}
659
660    /*
661     * Chain buffers onto the free list
662     */
663
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++;
669	}
670
671    /*
672     * Remember the device handle
673     */
674
675    eth->eth_devhandle = devhandle;
676
677    return eth;
678}
679
680
681/*  *********************************************************************
682    *  eth_uninit(eth)
683    *
684    *  Close and free up an Ethernet context
685    *
686    *  Input parameters:
687    *  	   eth - ethernet context
688    *
689    *  Return value:
690    *  	   nothing
691    ********************************************************************* */
692
693void eth_uninit(ether_info_t *eth)
694{
695    cfe_close(eth->eth_devhandle);
696    KFREE(eth->eth_bufpool);
697    KFREE(eth->eth_ports);
698    KFREE(eth);
699}
700
701
702