📄 ldl.c
字号:
bp->b_datap->db_type = M_PROTO; ud = (dl_unitdata_ind_t *)bp->b_rptr; ud->dl_primitive = DL_UNITDATA_IND; ud->dl_dest_addr_length = 6; ud->dl_dest_addr_offset = DL_UNITDATA_IND_SIZE; ud->dl_src_addr_length = 6; ud->dl_src_addr_offset = DL_UNITDATA_IND_SIZE + 6; ud->dl_group_address = *dp->b_rptr & 1; bp->b_wptr += DL_UNITDATA_IND_SIZE; memcpy(bp->b_wptr, dp->b_rptr, 12); bp->b_wptr += 12; len = *(unsigned short *)(dp->b_rptr + 12); dp->b_rptr += 14; if (dp->b_wptr - dp->b_rptr > len) dp->b_wptr = dp->b_rptr + len; linkb(bp, dp); return bp;}STATIC int ipx_8023_mkhdr(struct dl *dl, unsigned char *dst, int datalen, struct sk_buff *skb){ unsigned char *hdr; hdr = skb_push(skb, 14); memcpy(hdr, dst, 6); memcpy(hdr + 6, dl->ndev->dev->dev_addr, 6); *(unsigned short *)(hdr + 12) = htons(datalen); return 1;}/* * Token Ring 802.2 LLC * * The bound sap must match the dsap of the received frame but the * control field can be anything at all. LLC uses _real_ control * fields for link layer protocol. * * For received data the entire header is returned even though we * extract the addresses into the unitdata indication header. * * For transmitted data the caller has built the header by the * time we get the frame. We transmit the frame as-is. *//* * Token ring header. * * Note that there is no length field as there is in an Ethernet * header. IP packet types have to be encoded inside a SNAP header * beyond the LLC header. */typedef struct tr_hdr{ u8 acf ; u8 fcf ; u8 dst_addr[6] ; u8 src_addr[6] ; /* * Routing control bytes: Only present if the routing bit * is set in the first byte of the src_addr. */ u8 bl ; /* brdcst & lgth */ u8 df ; /* direction & lrgst frm bits */} tr_hdr_t ;/* * After a variable amount of routing data you come to the * LLC header. */typedef struct tr_llc_frm_hdr{ u8 llc_dsap ; /* destination SAP address */ u8 llc_ssap ; /* source SAP address */ u8 llc_ctl[1] ; /* control field */} tr_llc_frm_hdr_t ;/* * A few bits from the token ring header. */#define SADDR_0_RTE_PRES 0x80 /* 1=rte info present, 0=none */#define RCF_0_LLLLL 0x1F /* length bits */#define FCF_FF 0xC0 /* frame type bits */#define FCF_MAC 0x00 /* MAC frame */#define FCF_LLC 0x40 /* LLC frame */STATIC int tr_8022_want(struct dl *dl, unsigned char *fr, int len){ /* patterned after eth_8022_want */ tr_hdr_t *trp ; tr_llc_frm_hdr_t *llcp ; int rtelgth ;#if 0 { int i ; printk("tr_8022_want:\n") ; for (i = 0; i < 16; i++) printk("%02x ", fr[i]) ; printk("\n") ; for (; i < 32; i++) printk("%02x ", fr[i]) ; printk("\n") ; }#endif trp = (tr_hdr_t *) fr ; ASSERT(dl->sap_len == 1); if (len < sizeof(tr_hdr_t)-2 + sizeof(tr_llc_frm_hdr_t)) return 0; /* * Decode the type of frame. If a MAC frame, we don't want it. * If an LLC frame, we will look at it. */ if ((trp->fcf & FCF_FF) != FCF_LLC) /* must be LLC type frame */ return(0) ; /* we don't want it */ /* * Find out how much routing info is present and skip over it. * Establish llcp pointing to the LLC header. * * The length in the RCF includes the two bytes of routing control * at the front of the RCF. These two bytes are included in our * header structure. */ if (trp->src_addr[0] & SADDR_0_RTE_PRES) { /* has source route field */ rtelgth = trp->bl & RCF_0_LLLLL ; if (rtelgth < 2) /* count includes rte ctl fld */ return 0 ; /* ill-formed, don't want it */ if (rtelgth & 0x01) /* must be pairs of bytes */ return 0 ; /* ill-formed, don't want it */ llcp = (tr_llc_frm_hdr_t *) (fr + sizeof(*trp)-2 + rtelgth) ; } else /* no source route field */ { /* don't skip as many bytes */ llcp = (tr_llc_frm_hdr_t *) (fr + sizeof(*trp)-2) ; } /* * Now that we know where the SAPs are and that it's an LLC frame * we can search for a dlsap match. * * The LDLFLAG_RAW check will disappear when we * get the RAW LLC frametype to work. * It means that when running in RAW mode, any value of the * control field will be accepted. */ if (!(dl->flags & LDLFLAG_RAW) && llcp->llc_ctl[0] != 0x03) return 0 ; if (dl->flags & LDLFLAG_PROMISC_SAP) return 1; /* wants everything */ if (llcp->llc_dsap != dl->sap->sap.sap[0]) { struct sap *sap = dl->subs; while (sap != NULL) { if (llcp->llc_dsap == sap->sap.sap[0]) break; sap = sap->next_sap; } if (sap == NULL) return 0; } return 1;}/* * Strip the token ring addresses from the frame. Also strip out the * route information and the LLC header. */STATIC mblk_t *tr_8022_rcvind(struct dl *dl, mblk_t *dp){ mblk_t *bp; dl_unitdata_ind_t *ud; tr_hdr_t *trp ; tr_llc_frm_hdr_t *llcp ; int rtelgth = 0 ; ASSERT(dl->sap_len == 1); ASSERT(dl->addr_len == 6); trp = (tr_hdr_t *) dp->b_rptr ; if (trp->src_addr[0] & SADDR_0_RTE_PRES) { /* has source route field */ rtelgth = trp->bl & RCF_0_LLLLL ; } llcp = (tr_llc_frm_hdr_t *) (dp->b_rptr + sizeof(*trp)-2 + rtelgth) ; if ((bp = allocb(DL_UNITDATA_IND_SIZE + 14, BPRI_LO)) == NULL) { freeb(dp); return NULL; } bp->b_datap->db_type = M_PROTO; ud = (dl_unitdata_ind_t *)bp->b_rptr; ud->dl_primitive = DL_UNITDATA_IND; ud->dl_dest_addr_length = 7; ud->dl_dest_addr_offset = DL_UNITDATA_IND_SIZE + 7; ud->dl_src_addr_length = 7; ud->dl_src_addr_offset = DL_UNITDATA_IND_SIZE; ud->dl_group_address = 0 ; bp->b_wptr += DL_UNITDATA_IND_SIZE; memcpy(bp->b_wptr, trp->dst_addr, 6); bp->b_wptr += 6 ; *bp->b_wptr++ = llcp->llc_dsap ; memcpy(bp->b_wptr+6, trp->src_addr, 6); bp->b_wptr += 6 ; *bp->b_wptr++ = llcp->llc_ssap ; dp->b_rptr += sizeof(*trp)-2 + rtelgth + sizeof(tr_llc_frm_hdr_t) ; linkb(bp, dp); return bp;}/* * Data buffer contains the data part of an LLC frame. Add the LLC * header and the token ring MAC header. */STATIC int tr_8022_mkhdr(struct dl *dl, unsigned char *dst, int datalen, struct sk_buff *skb){ tr_hdr_t *trp ; tr_llc_frm_hdr_t *llcp ; unsigned char dsap; dsap = *(dst + 6); if (dsap != dl->sap->sap.sap[0]) { struct sap *sap; for (sap = dl->subs; sap; sap = sap->next_sap) if (dsap == sap->sap.sap[0]) break; if (sap == NULL) return 0; } /* * Omit the router control field and turn off the source route * bit in the source address. This may or may not prove to * be correct. */ trp = (tr_hdr_t *) skb_push(skb, sizeof(tr_hdr_t)-2 + sizeof(*llcp)); trp->acf = 0x10 ; /* canned */ trp->fcf = 0x40 ; /* canned */ memcpy(trp->dst_addr, dst, 6); memcpy(trp->src_addr, dl->ndev->dev->dev_addr, 6); trp->src_addr[0] &= ~SADDR_0_RTE_PRES ; /* no route */ llcp = (tr_llc_frm_hdr_t *) ( ((char *)(trp+1)) - 2 ) ; llcp->llc_dsap = dsap ; llcp->llc_ssap = dsap ; llcp->llc_ctl[0] = 0x03 ; return 1;}/* * HDLC Raw */STATIC int hdlc_raw_want(struct dl *dl, unsigned char *fr, int len){ return 1; /* take everything */}STATIC mblk_t *hdlc_raw_rcvind(struct dl *dl, mblk_t *dp){ mblk_t *bp; dl_unitdata_ind_t *ud; if ((bp = allocb(DL_UNITDATA_IND_SIZE + 14, BPRI_LO)) == NULL) { freeb(dp); return NULL; } bp->b_datap->db_type = M_PROTO; ud = (dl_unitdata_ind_t *)bp->b_rptr; ud->dl_primitive = DL_UNITDATA_IND; ud->dl_dest_addr_length = 0; ud->dl_dest_addr_offset = 0; ud->dl_src_addr_length = 0; ud->dl_src_addr_offset = 0; ud->dl_group_address = 0; bp->b_wptr += DL_UNITDATA_IND_SIZE; linkb(bp, dp); return bp;}STATIC int hdlc_raw_mkhdr(struct dl *dl, unsigned char *dst, int datalen, struct sk_buff *skb){ return 1;}/* * FDDI 802.2 */STATIC int fddi_8022_want(struct dl *dl, unsigned char *fr, int len){ ASSERT(0); return 0;}STATIC mblk_t *fddi_8022_rcvind(struct dl *dl, mblk_t *dp){ ASSERT(0); return NULL;}STATIC int fddi_8022_mkhdr(struct dl *dl, unsigned char *dst, int datalen, struct sk_buff *skb){ ASSERT(0); return 0;}/* * FDDI SNAP */STATIC int fddi_snap_want(struct dl *dl, unsigned char *fr, int len){ ASSERT(0); return 0;}STATIC mblk_t *fddi_snap_rcvind(struct dl *dl, mblk_t *dp){ ASSERT(0); return NULL;}STATIC int fddi_snap_mkhdr(struct dl *dl, unsigned char *dst, int datalen, struct sk_buff *skb){ ASSERT(0); return 0;}/****************************************************************************//* End of: Frame type support routines. *//****************************************************************************//****************************************************************************//* *//* Receive side Linux socket driver interface routines. *//* *//****************************************************************************/STATIC INLINE void dl_rcv_put(mblk_t *dp, struct dl *dl, int copy){ mblk_t *mp; if (dp == NULL) { if (copy == 0) freeb(dp); ++dl->lost_rcv; return; } if (copy != 0 && (dp = dupb(dp)) == NULL) { ++dl->lost_rcv; ginc(net_rx_drp_cnt) ; return; } ginc(net_rx_cnt) ; if ((dl->flags & LDLFLAG_RAW) == 0) { if ((mp = dl->rcvind(dl, dp)) == NULL) { freeb(dp); ++dl->lost_rcv; return; } } else mp = dp;#if 1 /* * Insert in our read queue and send upstream from the read * service routine. Do not do putnexts from interrupt level. */ if (canput(dl->rq)) { putq(dl->rq, mp); ginc(unitdata_q_cnt) ; } else { freemsg(mp); ginc(unitdata_drp_cnt) ; ++dl->lost_rcv; }#else if (qsize(dl->rq) == 0 && canputnext(dl->rq)) { if (ldl_debug_mask & LDL_DEBUG_UDIND) ldl_mp_data_dump("ldl_unitdata_ind", mp, ldl_debug_mask & LDL_DEBUG_ALLDATA) ; putnext(dl->rq, mp); ginc(unitdata_ind_cnt) ; } else if (canput(dl->rq)) { putq(dl->rq, mp); ginc(unitdata_q_cnt) ; } else { freemsg(mp); ginc(unitdata_drp_cnt) ; ++dl->lost_rcv; }#endif}/* * Our "interrupt" function * * This is called from the Linux networking code whenever * a packet comes in from the device. * * It is not a real interrupt function as the driver has * returned from the hardware interrupt when this is called. * * For speed, we should avoid queueing the packet on our read * queue AND use dupmsg() if the packet is to be sent upstream * on more than one interface. But we cannot just putnext() our * message and dupmsg() it later (upstreams modules may have * changed or deallocated the message in the meantime). * To get around this problem we defer the putnext() until * we have done our first dupmsg() or we know that no dupmsg() * is needed. * But we can only avoid queueing if the read queue is empty; * otherwise our M_PROTO message could go upstream before any * M_PCPROTO messages queued on our read queue. */STATIC int rcv_func(struct sk_buff *skb, struct ldldev *dev, struct packet_type *pt){ mblk_t *dp; struct dl *dl, *last = NULL; struct sap *sap;#if 0 struct ethhdr *hdr = (struct ethhdr *)skb->mac.raw;#endif unsigned char *fr_ptr, fr_buf[LDL_MAX_HDR_LEN]; int fr_len; ASSERT(dev->type == ARPHRD_ETHER || dev->type == ARPHRD_LOOPBACK || dev->type == ARPHRD_IEEE802 || IS_ARPHRD_IEEE802_TR(dev) || dev->type == ARPHRD_HDLC); /* ARPHRD_FDDI */ fr_len = skb->tail - skb->mac.raw; if ((dp = allocb(2 + fr_len, BPRI_LO)) != NULL) { /* * Prepare the data block. * The header is removed later for those that do no want it. * The two extra unused bytes makes the data more processor * cache-efficient in the higher level protocols (at least for * ethernet). */ dp->b_rptr = dp->b_wptr += 2; dp->b_datap->db_type = M_DATA; memcpy(dp->b_wptr, skb->mac.raw, fr_len); fr_ptr = dp->b_rptr; dp->b_wptr += fr_len; } else { /* We still need the frame type for correct drop stats */ fr_ptr = &fr_buf[0]; fr_len = lis_min(skb->end - skb->mac.raw, LDL_MAX_HDR_LEN); ASSERT(fr_len > 0); memcpy(fr_buf, skb->mac.raw, fr_len); } if (ldl_debug_mask & LDL_DEBUG_RCV_FUNC) ldl_skbuff_dump("ldl_rcv_func: skb", skb, ldl_debug_mask & LDL_DEBUG_ALLDATA) ;#ifdef KERNEL_2_1 dev_kfree_skb(skb);#else dev_kfree_skb(skb, FREE_WRITE);#endif if (ldl_debug_mask & LDL_DEBUG_RCV_FUNC) ldl_bfr_dump("ldl_rcv_func", fr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -