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