--- upstream/dynamips-0.2.6-RC3/dev_nm_16esw.c 2007/10/06 16:06:49 4 +++ upstream/dynamips-0.2.7/dev_nm_16esw.c 2007/10/06 16:29:14 10 @@ -1,5 +1,5 @@ /* - * Cisco C3600 simulation platform. + * Cisco router simulation platform. * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) * * NM-16ESW ethernet switch module (experimental!) @@ -30,11 +30,11 @@ #define DEBUG_ACCESS 0 #define DEBUG_UNKNOWN 0 #define DEBUG_MII 0 -#define DEBUG_MEM 0 +#define DEBUG_MEM 1 #define DEBUG_REG 1 #define DEBUG_TRANSMIT 0 #define DEBUG_RECEIVE 0 -#define DEBUG_FORWARD 0 +#define DEBUG_FORWARD 1 #define DEBUG_MIRROR 0 #define DEBUG_ARL 0 @@ -1395,17 +1395,17 @@ switch(cmd) { case BCM5600_SCHAN_CMD_EXEC: bcm5600_handle_gen_cmd(d); - d->schan_cmd_res = 0xFFFFFFFF; + d->schan_cmd_res = 0x00008002; break; case BCM5600_SCHAN_CMD_READ_MII: bcm5600_mii_read(d); - d->schan_cmd_res = 0xFFFFFFFF; + d->schan_cmd_res = 0x00048000; break; case BCM5600_SCHAN_CMD_WRITE_MII: bcm5600_mii_write(d); - d->schan_cmd_res = 0xFFFFFFFF; + d->schan_cmd_res = 0x00048000; break; case BCM5600_SCHAN_CMD_LINKSCAN: @@ -1423,7 +1423,7 @@ /* * dev_bcm5605_access() */ -void *dev_bcm5605_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, +void *dev_bcm5605_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset, u_int op_size,u_int op_type,m_uint64_t *data) { struct nm_16esw_data *d = dev->priv_data; @@ -1434,10 +1434,11 @@ #if DEBUG_ACCESS if (op_type == MTS_READ) { - BCM_LOG(d,"read access to offset=0x%x, pc=0x%llx\n",offset,cpu->pc); + BCM_LOG(d,"read access to offset=0x%x, pc=0x%llx\n", + offset,cpu_get_pc(cpu)); } else { BCM_LOG(d,"write access to offset=0x%x, pc=0x%llx, val=0x%llx\n", - offset,cpu->pc,*data); + offset,cpu_get_pc(cpu),*data); } #endif @@ -1519,6 +1520,8 @@ *data |= BCM5600_INTR_LINKSTAT_MOD; d->mii_intr = FALSE; } + + pci_dev_clear_irq(d->vm,d->pci_dev); } break; @@ -1545,10 +1548,11 @@ default: if (op_type == MTS_READ) { BCM_LOG(d,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", - offset,cpu->pc,op_size); + offset,cpu_get_pc(cpu),op_size); } else { BCM_LOG(d,"write to unknown addr 0x%x, value=0x%llx, " - "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } @@ -1850,7 +1854,11 @@ */ if (dst_mac_index == -1) { #if DEBUG_FORWARD - BCM_LOG(d,"Destination MAC address unknown, flooding.\n"); + BCM_LOG(d,"Destination MAC address " + "%2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x unknown, flooding.\n", + dst_mac->eth_addr_byte[0],dst_mac->eth_addr_byte[1], + dst_mac->eth_addr_byte[2],dst_mac->eth_addr_byte[3], + dst_mac->eth_addr_byte[4],dst_mac->eth_addr_byte[5]); #endif p->egress_bitmap = p->vlan_entry[1] & BCM5600_VTABLE_PORT_BMAP_MASK; @@ -2058,6 +2066,27 @@ return(TRUE); } +/* Determine if the specified MAC address matches a BPDU */ +static inline int bcm5600_is_bpdu(n_eth_addr_t *m) +{ + /* PVST+ */ + if (!memcmp(m,"\x01\x00\x0c\xcc\xcc\xcd",6)) + return(TRUE); + + /* Classical 802.1D */ + if (!memcmp(m,"\x01\x80\xc2\x00\x00",5) && !(m->eth_addr_byte[5] & 0xF0)) + return(TRUE); + + /* + * CDP: this is cleary a hack, but IOS seems to program this address + * in BPDU registers. + */ + if (!memcmp(m,"\x01\x00\x0c\xcc\xcc\xcc",6)) + return(TRUE); + + return(FALSE); +} + /* Handle a received packet */ static int bcm5600_handle_rx_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p) { @@ -2077,24 +2106,41 @@ /* Analyze the Ethernet header */ eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt; + /* Determine VLAN */ + if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) { + p->orig_vlan = -1; + p->real_vlan = port_entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK; + + /* TODO: 802.1p/CoS remarking */ + if (port_entry[4] & BCM5600_PTABLE_RPE_FLAG) { + } + } else { + p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF; + } + + /* Check that this VLAN exists */ + if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) + return(FALSE); + /* Check for the reserved addresses (BPDU for spanning-tree) */ - if (!memcmp(ð_hdr->daddr,"\x01\x80\xc2\x00\x00",5) || - !memcmp(ð_hdr->daddr,"\x01\x00\x0c\xcc\xcc\xcd",6)) - { + if (bcm5600_is_bpdu(ð_hdr->daddr)) { #if DEBUG_RECEIVE BCM_LOG(d,"Received a BPDU packet:\n"); mem_dump(d->vm->log_fd,p->pkt,p->pkt_len); #endif - p->orig_vlan = 0; p->egress_bitmap |= 1 << d->cpu_port; return(bcm5600_forward_pkt(d,p)); } + /* Check that this port is a member of this VLAN */ + if (!(p->vlan_entry[1] & (1 << p->ingress_port))) + return(FALSE); + /* Discard packet ? */ discard = port_entry[0] & BCM5600_PTABLE_PRT_DIS_MASK; discard >>= BCM5600_PTABLE_PRT_DIS_SHIFT; - if (discard) { + if ((p->orig_vlan == -1) && discard) { if (discard != 0x20) { printf("\n\n\n" "-----------------------------------------------------------" @@ -2113,29 +2159,6 @@ if (port_entry[1] & BCM5600_PTABLE_MI_FLAG) bcm5600_mirror_pkt(d,p,0); - /* Determine VLAN */ - if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) { - p->orig_vlan = -1; - p->real_vlan = port_entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK; - - if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) - return(FALSE); - - /* TODO: 802.1p/CoS remarking */ - if (port_entry[4] & BCM5600_PTABLE_RPE_FLAG) { - } - } else { - p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF; - - /* Check that this VLAN exists */ - if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) - return(FALSE); - - /* Check that this port is a member of this VLAN */ - if (!(p->vlan_entry[1] & (1 << p->ingress_port))) - return(FALSE); - } - #if DEBUG_RECEIVE BCM_LOG(d,"%s: received a packet on VLAN %u\n", d->ports[p->ingress_port].name,p->real_vlan); @@ -2353,7 +2376,7 @@ } /* pci_bcm5605_read() */ -static m_uint32_t pci_bcm5605_read(cpu_mips_t *cpu,struct pci_device *dev, +static m_uint32_t pci_bcm5605_read(cpu_gen_t *cpu,struct pci_device *dev, int reg) { struct nm_16esw_data *d = dev->priv_data; @@ -2367,7 +2390,7 @@ } /* pci_bcm5605_write() */ -static void pci_bcm5605_write(cpu_mips_t *cpu,struct pci_device *dev, +static void pci_bcm5605_write(cpu_gen_t *cpu,struct pci_device *dev, int reg,m_uint32_t value) { struct nm_16esw_data *d = dev->priv_data;