📄 ip_to_dlpi.c
字号:
int ip2xinetursrv(queue_t *q){ mblk_t *mp; while ((mp = getq(q))) { putnext(q, mp); } return (0);}/************************************************************************ * * Function Name: ip2xinetlwsrv * Title: IP2XINET Lower Write Service routine * * Description: * Send all of the messages on this queue down to the next driver. * If we discover that we can't do a put, then stop the Linux * devices from sending us stuff. * ************************************************************************/int ip2xinetlwsrv(queue_t *q){ mblk_t *mp; int allsent = 1; int i; struct net_device *dev = ip2xinet_devs; struct ip2xinet_priv *privp; lis_flags_t oldpl; while ((mp = getq(q))) { /* M_PROTO's should be last on the list. If it is something * else, then it should be ahead, and we can just go ahead and * put it down. */ if (mp->b_datap->db_type == M_PROTO) { if (canputnext(q)) { putnext(q, mp); } else { noenable(q); putbq(q, mp); enableok(q); allsent = 0; break; } } else { putnext(q, mp); } } /* Handle the flow control. If we were able to send everything * then it is ok for the kernel to send us more stuff. Otherwise * it is not ok. Go through all of the devices and set the appropriate * state. */ lis_spin_lock_irqsave(ip2xinet_lock, &oldpl); for (i = 0; i<NUMIP2XINET; i++, dev++) { privp = (struct ip2xinet_priv *)dev->priv; if (privp->state == 1 && ip2xinet_status.ip2x_dlstate == DL_IDLE) { if (allsent) { netif_start_queue(dev); /* kernel can transmit */ } else { netif_stop_queue(dev); /* We are flow controlled. */ } } } lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl); return (0);}/************************************************************************ * * Function Name: ip2xinetlrput * Title: IP2XINET Lower Read Put Routine * * Description: * Handle messages coming upstream. Valid messages will have * a DLPI header associated with them. * Since we can't be flow controlled by Linux TCP/IP, don't need lrsrv * * Arguments: * q - upper read queue * mp - pointer to an message block * * Return Value: * none * ************************************************************************/int ip2xinetlrput(queue_t *q, mblk_t *mp){ struct iocblk *iocp; union DL_primitives *dp; struct ip2xinet_priv *privptr; struct net_device *dev; int i; lis_flags_t oldpl; lis_spin_lock_irqsave(ip2xinet_lock, &oldpl); /* use the first open ip device */ for (i = 0; i<NUMIP2XINET; i++) { privptr = &ip2xinet_private[i]; if (privptr->state == 1) break; } if (i == NUMIP2XINET) i = 0; /* All devices closed, pick the 1st one */ /* send data up to ip through the 1st open device */ dev = &ip2xinet_devs[i]; switch (mp->b_datap->db_type) { case M_CTL: freemsg(mp); break; case M_DATA: /* NOTE: We don't expect any M_DATA messages from xinet */ freemsg(mp); break; case M_PROTO: case M_PCPROTO: dp = (union DL_primitives *) mp->b_rptr;#ifdef DEBUG printk("ip2xinetlrput: %s size=%d\n", x25dbdlpmsg(dp->dl_primitive), x25dbmsgsize(mp));#endif switch (dp->dl_primitive) { case DL_BIND_ACK: /* * if we're in in BNDPND and receive a BIND_ACK we go to IDLE * */ ip2xinet_status.ip2x_dlstate = DL_IDLE; /* If we're DL_IDLE, then dev is open * and the kernel can transmit */ for (i = 0; i<NUMIP2XINET; i++) { privptr = &ip2xinet_private[i]; if (privptr->state == 1) netif_start_queue(&(ip2xinet_devs[i])); } freemsg(mp); /* Frees bind_ack no longer needed */ break; case DL_INFO_ACK: /* NOTE: currently we don't send info_req to xinet */ freemsg(mp); break; case DL_ERROR_ACK: switch (ip2xinet_status.ip2x_dlstate) { case DL_ATTACH_PENDING: /* * if we receive ERROR_ACK and we're in ATTACH_PEND * go into UNATTACHED * */ ip2xinet_status.ip2x_dlstate = DL_UNATTACHED; freemsg(mp); break; case DL_BIND_PENDING: /* * if we're in BNDPND and receive an ERR ack we go to UNBND, * */ ip2xinet_status.ip2x_dlstate = DL_UNBOUND; freemsg(mp); break; case DL_UNBIND_PENDING: /* * If we're in UNBIND_PEND and we receive ERROR_ACK * we go into IDLE * */ ip2xinet_status.ip2x_dlstate = DL_IDLE; freemsg(mp); break; case DL_DETACH_PENDING: /* * If we're in DETACH_PEND and receive and ERROR_ACK * we go into UNBND * */ ip2xinet_status.ip2x_dlstate = DL_UNBOUND; freemsg(mp); break; default: freemsg(mp); break; } break; case DL_UNITDATA_IND: /* * if we're in IDLE we can get DL_UNITDATA_IND with data * and call the guy who would normally receive data from interrupt * handler. * */ /* Check state: can't transmit if dev is closed :-) * * Note: we have to check both the dlpi state and dev->start * because during a close the DLPI state could remain * DL_IDLE if we couldn't allocate mblk for UNBIND_REQ. * There are many ways in which the dev->start could * be 1 but dlpi state - not DL_IDLE. */ if (ip2xinet_status.ip2x_dlstate == DL_IDLE && privptr->state == 1); { mblk_t * newmp; char * buf; int len, tmplen; struct ethhdr *eth; struct sk_buff *skb; newmp = unlinkb(mp); freemsg(mp); mp = newmp; /* 1st pass through. figure out the len */ for (len=sizeof(struct ethhdr); newmp != NULL; newmp = newmp->b_cont) len+=(newmp->b_wptr - newmp->b_rptr); /* ALLOCATE skb of length len+2, COPY from mp chain to skb */ skb = dev_alloc_skb(len+2); if (!skb) { printk("ip2xinet rx: failed to allocate an skb\n"); freemsg(mp); break; } skb_reserve(skb, 2); /* align IP on 16B boundary */ /* * The packet has been retrieved from the transmission * medium. Build an skb around it, so upper layers can handle it */ buf = skb_put(skb, len); for (newmp=mp, tmplen=sizeof(struct ethhdr); newmp != NULL; newmp = newmp->b_cont) { bcopy(newmp->b_rptr, buf+tmplen, newmp->b_wptr - newmp->b_rptr); tmplen+=(newmp->b_wptr - newmp->b_rptr); } eth = (struct ethhdr *)buf; /* I am not sure it's necessary, but just in case... */ memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_proto = 0x8; /* ETH_P_IP in network order */ eth->h_source[ETH_ALEN-1] ^= 0x01; /* say src is us xor 1 */ /* send it to ip2xinet_rx for handling */ ip2xinet_rx(dev, skb); } freemsg(mp); break; case DL_UDERROR_IND: freemsg(mp); break; case DL_OK_ACK: switch (dp->ok_ack.dl_correct_primitive) { case DL_ATTACH_REQ: /* * if we're in ATTACH_PEND and we received OK_ACK1 * change state to UNBND * */ ip2xinet_status.ip2x_dlstate = DL_UNBOUND; freemsg(mp); /* * We just completed building up the X.25 stack below us. * If IP is already above us, we need to send down the bind * that we would normally do when IP opens us. This allows * us to restart the X.25 stack without restarting TCP/IP. */ if (ip2xinet_num_ip_opened != 0) ip2xinet_send_down_bind(WR(q)); break; case DL_UNBIND_REQ: /* * If we're in UNBIND_PEND and receive OK_ACK1 we go to UNBND. */ ip2xinet_status.ip2x_dlstate = DL_UNBOUND; freemsg(mp); break; case DL_DETACH_REQ: /* * If we're in DETACH_PEND and receive OK_ACK1 we go to UNATT * */ ip2xinet_status.ip2x_dlstate = DL_UNATTACHED; freemsg(mp); break; default: freemsg(mp); break; } break; default: printk("ip2xinetlrput: bad prim=0x%x", dp->dl_primitive); freemsg(mp); break; } break; case M_FLUSH: if (*mp->b_rptr & FLUSHR) { flushq(q, FLUSHALL); qenable(q); } if (*mp->b_rptr & FLUSHW) { *mp->b_rptr &= ~FLUSHR; flushq(WR(q), FLUSHALL); qenable(WR(q)); putq(WR(q), mp); } else freemsg(mp); break; case M_HANGUP: /* send it to the guy that linked us up, what he does is his problem. */ putq(ip2xinet_status.readq, mp); break; case M_IOCACK: iocp = (struct iocblk *) mp->b_rptr; if (iocp->ioc_cmd == SIOCSIFMTU) { /* The set MTU ioctl was a success * Rejoice :-) */ freemsg(mp); } else putq(ip2xinet_status.readq, mp); break; case M_IOCNAK: iocp = (struct iocblk *) mp->b_rptr; if (iocp->ioc_cmd == SIOCSIFMTU) { /* The set MTU ioctl was a failure * From looking at xinet code this is * impossible, so ignore it */ freemsg(mp); } else putq(ip2xinet_status.readq, mp); break; default: printk("ip2xinetlrput: bad type=%d", mp->b_datap->db_type); freemsg(mp); break; } lis_spin_unlock_irqrestore(ip2xinet_lock, &oldpl); return (0);}/************************************************************************ * * Function Name: init_module * Title: Registering driver as a Streams kernel loadable module * * Return Value: * StrReg - major number registered or error number * ************************************************************************/int init_module(void){ int ip2_m_number, clonemajor; ip2xinet_lock = lis_alloc_kernel(sizeof(lis_spin_lock_t)); if (!ip2xinet_lock) { return -ENOMEM; } lis_spin_lock_init(ip2xinet_lock, "IP2X Lock"); if( !(ip2_m_number = ip2xinetinit()) ) { ip2xinet_lock = lis_free_mem((void *)ip2xinet_lock); return ip2_m_number; } if (( ip2_m_number = lis_register_strdev(0, &ip2xinetinfo, NUMIP2XINET, ip2xinetminfo.mi_idname)) < 0 ) { printk("ip2xinet.init_module: Unable to register driver.\n"); ip2xinet_lock = lis_free_mem((void *)ip2xinet_lock); return ip2_m_number; } clonemajor = lis_clone_major(); /* Remove the old /dev/ip2xinet node. We are about to create a new * one, and that call may fail if the old one is still there. * We don't actually care if the unlink call fails, just as long * as the node isn't there. */ lis_unlink("/dev/ip2xinet"); if ((ip2_m_number = lis_mknod("/dev/ip2xinet", 0666 | S_IFCHR, MKDEV(clonemajor, ip2_m_number))) < 0) { ip2xinet_lock = lis_free_mem((void *)ip2xinet_lock); return ip2_m_number; } return 0;}/************************************************************************ * * Function Name: cleanup_module * Title: Unregistering driver as a Streams kernel loadable module * * Return Value: * none * ************************************************************************/void cleanup_module(void){ /* Before you unload this module, unregister all of the network * devices. */ if (lis_unregister_strdev(ip2_m_number) < 0 ) { printk("ip2xinet: Unable to unregister driver.\n"); } else { cleanup_linuxip(); lis_unlink("/dev/ip2xinet"); ip2xinet_lock = lis_free_mem((void *)ip2xinet_lock); printk("ip2xinet: Unregistered, ready to be unloaded.\n"); } return;}/* * The first part of the driver was all streams. * The second half is what talks to Linux. * They used to be in separate files, but for easier compilation in * the streams directory, I have joined them. */#define IP_SAP 0x800 /* SAP for IP protocol - currently enet type */#define ARP_SAP 0x806 /* SAP for ARP *//* This is a load-time options */static int eth = 0; /* Call yourself "ethX". Default is "ip2x0"/"ip2x1" */int ip2xinet_eth;int ip2xinet_num_ip_opened = 0; void ip2xinet_rx(struct net_device *dev, struct sk_buff *skb);void do_BUG(const char *file, int line){ return;}int ip2xinet_send_down_bind(queue_t *q){ mblk_t *mp; dl_bind_req_t *bindmp; if ((mp = allocb(sizeof(union DL_primitives), BPRI_LO)) == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -