⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_to_dlpi.c

📁 7号信令功能代码,为开源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    {        printk("ip2xopen: failed: allocb failed");        return -EAGAIN;  /* Other drivers seem to return this on error */    }    ip2xinet_status.ip2x_dlstate = DL_BIND_PENDING;    mp->b_datap->db_type = M_PROTO;    mp->b_wptr += DL_BIND_REQ_SIZE;    bindmp = (dl_bind_req_t *) mp->b_rptr;    bindmp->dl_primitive = DL_BIND_REQ;    bindmp->dl_sap = IP_SAP;    putq(q, mp);    return 0;}/* * Open and close */int ip2xinet_open(struct net_device *dev){    int i;    int err;    struct ip2xinet_priv *privp = (struct ip2xinet_priv *)dev->priv;    lis_flags_t oldpl;    lis_spin_lock_irqsave(ip2xinet_lock, &oldpl);    /* BEFORE ANYTHING CHECK THAT the streams I_LINK SUCCEEDED */    if (!(ip2xinet_status.ip2x_dlstate == DL_UNBOUND || 	(ip2xinet_num_ip_opened != 0 && ip2xinet_status.ip2x_dlstate == DL_IDLE)))    {	/* Normally we'd do the I_LINK, this would set us up into the	* UNBOUND state but something went wrong.  Either the I_LINK has	* not completed yet, or it failed.  In any case we're not in	* the shape to succeed so return a failure code and exit.  	*	*/	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);	return -EAGAIN;  /* Other drivers seem to return this on error */    }    /* Send a DL_BIND DOWN */    if (ip2xinet_num_ip_opened == 0)    {	if ((err = ip2xinet_send_down_bind(ip2xinet_status.lowerq)) != 0)	{	    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);	    return err;	}    }    ip2xinet_num_ip_opened++;    /*      * Assign the hardware address of the board: use "\0IP2Xx", where     * x is 0 to 7. The first byte is '\0': a safe choice with regard     * to multicast     */    for (i=0; i < ETH_ALEN; i++)        dev->dev_addr[i] = "\0IP2X0"[i];    dev->dev_addr[ETH_ALEN-1] += (dev - ip2xinet_devs); /* the number */    privp->state = 1;    if (ip2xinet_status.ip2x_dlstate == DL_IDLE)	netif_start_queue(dev);  /* kernel can transmit */    else	netif_stop_queue(dev);  /* wait until DL_IDLE, then kernel can tx */    MOD_INC_USE_COUNT;    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);    return 0;}int ip2xinet_release(struct net_device *dev){    queue_t *q;    mblk_t *mp;    lis_flags_t oldpl;    struct ip2xinet_priv *privp = (struct ip2xinet_priv *)dev->priv;        lis_spin_lock_irqsave(ip2xinet_lock, &oldpl);    privp->state = 0;    netif_stop_queue(dev); /* can't transmit any more */    MOD_DEC_USE_COUNT;    ip2xinet_num_ip_opened--;    /* BEFORE ANYTHING CHECK THAT we're in IDLE */    if (ip2xinet_status.ip2x_dlstate != DL_IDLE)    {	/* Normally we'd do the I_UNBIND, from DL_IDLE	* In all other cases we ignore the dlpi state as we'll unlink soon	*	*/	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);	return 0;    }    /* Send a DL_UNBIND DOWN */    if (ip2xinet_num_ip_opened == 0)    {	q=ip2xinet_status.lowerq;	if ((mp = allocb(sizeof(union DL_primitives), BPRI_LO)) == NULL)	{	    printk("ip2xopen: failed: allocb failed");	    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);	    return 0;  /* Other drivers seem to return this on error */	}	ip2xinet_status.ip2x_dlstate = DL_UNBIND_PENDING;	if (mp)	{	    dl_unbind_req_t *unbindmp;	    mp->b_datap->db_type = M_PROTO;	    mp->b_wptr += DL_UNBIND_REQ_SIZE;	    unbindmp = (dl_unbind_req_t *) mp->b_rptr;	    unbindmp->dl_primitive = DL_UNBIND_REQ;	    putq(q, mp);	}    }    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);    return 0;}/* * Configuration changes (passed on by ifconfig) * Not that we actually do anything with them. */int ip2xinet_config(struct net_device *dev, struct ifmap *map){    lis_flags_t oldpl;    lis_spin_lock_irqsave(ip2xinet_lock, &oldpl);    if (dev->flags & IFF_UP) /* can't act on a running interface */    {	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);        return -EBUSY;    }    /* Don't allow changing the I/O address */    if (map->base_addr != dev->base_addr)     {	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);        printk(KERN_WARNING "ip2xinet: Can't change I/O address\n");        return -EOPNOTSUPP;    }    /* Don't allow changing the IRQ */    if (map->irq != dev->irq)     {	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);        printk(KERN_WARNING "ip2xinet: Can't change IRQ\n");        return -EOPNOTSUPP;    }    /* ignore other fields */    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);    return 0;}/* * Receive a packet: retrieve, encapsulate and pass over to upper levels * * This routine is called from the lrput routine.  We should already hold * the driver lock when we are called from there. */void ip2xinet_rx(struct net_device *dev, struct sk_buff *skb){    struct ip2xinet_priv *privp = (struct ip2xinet_priv *)dev->priv;    /*     * The packet has been retrieved from the transmission     * medium. Build an skb around it, so upper layers can handle it     */    /* Write metadata, and then pass to the receive level */    skb->dev = dev;    skb->protocol = eth_type_trans(skb, dev);    skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */    privp->stats.rx_packets++;    netif_rx(skb);    return;}    /* * Transmit a packet (low level interface) * * This routine is called from ip2xinet_tx. That function * grabbed the driver lock when it was called. */void ip2xinet_hw_tx(char *buf, int len, struct net_device *dev){    /*     * This function deals with hw details,      * while all other procedures are rather device-independent     */    struct iphdr *ih, *iph;    struct ethhdr *eth;    struct ip2xinet_priv *privp;    queue_t *q;    mblk_t *mp, *nmp;    dl_unitdata_req_t * req;    int mylen;    /* sanity check */    if (len < sizeof(struct ethhdr) + sizeof(struct iphdr))     {        printk("ip2xinet: Hmm... packet too short (%i octets)\n",               len);        return;    }#if 0    if (0)     { /* enable this conditional to look at all the data */        int i;        PDEBUG("ip2xinet: len is %i\n" KERN_DEBUG "data:",len);        for (i=14 ; i<len; i++)            printk(" %02x",buf[i]&0xff);        printk("\n");    }#endif    /*     * Ethhdr is 14 bytes, but the kernel arranges for iphdr     * to be aligned (i.e., ethhdr is unaligned)     */    ih = (struct iphdr *)(buf+sizeof(struct ethhdr));    PDEBUGG("%08lx:%05i --> %08lx:%05i\n",	   ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source),	   ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest));    /*     * Ok, now the packet is ready for transmission:      */    /*      * Here we do a putq to the bottom q.     */    privp = &ip2xinet_private[dev - ip2xinet_devs];    q=ip2xinet_status.lowerq;    /* THIS IS WHERE WE ALLOCATE UNITDATA_REQ and send data down */    if ((mp = allocb(sizeof(struct iphdr)+DL_UNITDATA_REQ_SIZE, BPRI_LO)) == NULL)    {	printk("ip2xhwtx: failed: allocb failed");	return ;    }    mp->b_datap->db_type = M_PROTO;      mp->b_wptr += (sizeof(struct iphdr ) + DL_UNITDATA_REQ_SIZE);    /*     * xinet expects a DLPI header ahead of the datagram, as in Unix.     * The destination address in this header needs to be the next hop      * address.  We're going to get this from the destination address in     * the Ethernet header and rely upon froute/x25route having added     * a static ARP entry with:     *		IP address of machine at other end of circuit     *		MAC address equal to IP address of that same machine     * Though the IP address of IP datagrams passed down to us may be many      * hops away, the destination Ethernet address will always be the next     * hop IP address.     */    eth = (struct ethhdr *)(buf);    iph = (struct iphdr *)(mp->b_rptr+ DL_UNITDATA_REQ_SIZE);    iph->saddr = ih->saddr;			/* likely unused by xinet */    iph->daddr = (eth->h_dest[3] << 24)		/* next hop address */               + (eth->h_dest[2] << 16)               + (eth->h_dest[1] << 8)               + (eth->h_dest[0]);    iph->check = 0;    req = (dl_unitdata_req_t *) mp->b_rptr;    req->dl_primitive = DL_UNITDATA_REQ;    req->dl_dest_addr_length = 4;    req->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE + 			       (int ) &((struct iphdr *) 0)->daddr;    /* Copy from buf to mp, make everything right, then send the stuff to     * xinet IF WE CAN.     * Could we use esballoc here?     */    mylen = len - sizeof(struct ethhdr);    if ((nmp = allocb(mylen, BPRI_LO)) == NULL)    {        printk("ip2xhwtx: failed: allocb failed");	freemsg(mp);	return;    }    linkb(mp, nmp);    bcopy( buf+sizeof(struct ethhdr), nmp->b_rptr, mylen);    nmp->b_wptr += mylen;    putq(q, mp);    privp->stats.tx_packets++;}/* * Transmit a packet (called by the kernel) */int ip2xinet_tx(struct sk_buff *skb, struct net_device *dev){    lis_flags_t oldpl;    if (skb == NULL)     {        return 0;    }    if (skb->len < (sizeof(struct ethhdr) + sizeof(struct iphdr)))    {	dev_kfree_skb(skb);	return 0;    }    lis_spin_lock_irqsave(ip2xinet_lock, &oldpl);    if (netif_queue_stopped(dev))    {	lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);	return -EBUSY;    }    dev->trans_start = jiffies; /* save the timestamp */    ip2xinet_hw_tx(skb->data, skb->len, dev);    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);    dev_kfree_skb(skb); /* release it */    return 0; /* zero == done */}/* * Ioctl commands  */int ip2xinet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){     PDEBUG("ioctl\n");    return 0;}/* * Return statistics to the caller */struct net_device_stats *ip2xinet_stats(struct net_device *dev){    struct ip2xinet_priv *priv = (struct ip2xinet_priv *)dev->priv;    /* The only stats we keep are transmitted and received packets.     *     * Note: xinet stats are kind of useless since the structure      *       ifstats doesn't exist under linux.  So rather than     *       keep track of stats in xinet we do it in ip2xinet.     */    return &priv->stats;}int ip2xinet_rebuild_header(struct sk_buff *skb){    struct ethhdr *eth = (struct ethhdr *)(skb->data);    // return arp_find(&(eth->h_dest),skb);    return arp_find(eth->h_dest, skb);}/* * This function builds the hardware header from the source and destination * hardware addresses that were previousely retrieved, its job is to organise * the information passed to it as arguments */int ip2xinet_hard_header(struct sk_buff *skb, struct net_device *dev,                          unsigned short type, void *daddr, void *saddr,		         unsigned len){    struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);	/* 	*	Set the protocol type. For a packet of type ETH_P_802_3 	*      we put the length in here instead. It is up to the	*      802.2 layer to carry protocol information.	*/		if(type!=ETH_P_802_3) 		eth->h_proto = htons(type);	else		eth->h_proto = htons(len);	/*	*	Set the source hardware address. 	*/		if(saddr)		memcpy(eth->h_source,saddr,dev->addr_len);	else		memcpy(eth->h_source,dev->dev_addr,dev->addr_len);	/*	*	Anyway, the loopback-device should never use this function... 	*/	if (dev->flags & IFF_LOOPBACK) 	{		memset(eth->h_dest, 0, dev->addr_len);		return(dev->hard_header_len);	}		if(daddr)	{		memcpy(eth->h_dest,daddr,dev->addr_len);		return dev->hard_header_len;	}		return -dev->hard_header_len;}/* * The "change_mtu" method is usually not needed. * If you need it, it must be like this. * * The change in MTU (Maximum Transfer Unit) * must be communicated to xinet */int ip2xinet_change_mtu(struct net_device *dev, int new_mtu){    lis_flags_t oldpl;    /* check ranges */    if ((new_mtu < 68) || (new_mtu > 1500))        return -EINVAL;    /* Do anything you need, and accept the value     */    lis_spin_lock_irqsave(ip2xinet_lock, &oldpl);    dev->mtu = new_mtu; /* accept the new value */    lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl);    return 0;}/* * The init function (sometimes called probe). * It is invoked by register_netdev() * * NOTE: This is different from the init() function that can be called from *       streams */int ip2xinet_init(struct net_device *dev){    /*      * Assign other fields in dev, using ether_setup() and some     * hand assignments     */    ether_setup(dev);    dev->open            = ip2xinet_open;    dev->stop            = ip2xinet_release;    dev->set_config      = ip2xinet_config;    dev->hard_start_xmit = ip2xinet_tx;    dev->do_ioctl        = ip2xinet_ioctl;    dev->get_stats       = ip2xinet_stats;    dev->change_mtu      = ip2xinet_change_mtu;      dev->rebuild_header  = ip2xinet_rebuild_header;    dev->hard_header     = ip2xinet_hard_header;    dev->hard_header_len = ETH_HLEN;    dev->flags           |= IFF_NOARP;    dev->type            = ARPHRD_ETHER;    dev->addr_len 	= 6;	/* fake ethernet address */    dev->tx_queue_len	= 10;    /* dev->dev_addr is handled in the open() */    dev->flags &= ~IFF_BROADCAST; /* X25 doesn't broadcast */    dev->flags &= ~IFF_MULTICAST; /* X25 doesn't multicast */    /*     * Then, allocate the priv field. This encloses the statistics     * and a few private fields.     */    dev->priv = &ip2xinet_private[dev - ip2xinet_devs];    if (dev->priv == NULL)        return -ENOMEM;    memset(dev->priv, 0, sizeof(struct ip2xinet_priv));    dev_init_buffers(dev);    ip2xinet_status.ip2x_dlstate = UNLINKED;    return 0;}struct net_device ip2xinet_devs[NUMIP2XINET];/* * Finally, the module stuff */int init_linuxip(void){    int result, i, device_present = 0;    struct net_device *dev = ip2xinet_devs;    ip2xinet_eth = eth; /* copy the cfg datum in the non-static place */    /* call them "ip2x0"... "ip2x7" */    for (i = 0; i<NUMIP2XINET; i++,dev++)    {	memset(dev, 0, sizeof (struct net_device));	memcpy(dev->name, "ip2x0", 6);	dev->name[4] = (char) ('0' + i);        dev->init = ip2xinet_init;	/* the rest of the fields are filled in by ip2xinet_init */    }    dev = ip2xinet_devs;    for (i=0; i < NUMIP2XINET;  i++, dev++)        if ((result = register_netdev(dev)))            printk("ip2xinet: error %i registering device \"%s\"\n",                   result, dev->name);        else 	    device_present++;    return device_present ? 0 : -ENODEV;}void cleanup_linuxip(void){    int i;        for (i = 0; i<NUMIP2XINET; i++)    {	unregister_netdev(&ip2xinet_devs[i]);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -