📄 netiucv.c
字号:
skb_put(pskb, NETIUCV_HDRLEN); pskb->dev = dev; pskb->ip_summed = CHECKSUM_NONE; pskb->protocol = ntohs(ETH_P_IP); while (1) { struct sk_buff *skb; ll_header *header = (ll_header *)pskb->data; if (header->next == 0) break; skb_pull(pskb, NETIUCV_HDRLEN); header->next -= offset; offset += header->next; header->next -= NETIUCV_HDRLEN; if (skb_tailroom(pskb) < header->next) { printk(KERN_WARNING "%s: Illegal next field in iucv header: %d > %d\n", dev->name, header->next, skb_tailroom(pskb)); return; } skb_put(pskb, header->next); pskb->mac.raw = pskb->data; skb = dev_alloc_skb(pskb->len); if (!skb) { printk(KERN_WARNING "%s Out of memory in netiucv_unpack_skb\n", dev->name); privptr->stats.rx_dropped++; return; } memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len); skb->mac.raw = skb->data; skb->dev = pskb->dev; skb->protocol = pskb->protocol; pskb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb->len; skb_pull(pskb, header->next); skb_put(pskb, NETIUCV_HDRLEN); }}static voidconn_action_rx(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; netiucv_priv *privptr = (netiucv_priv *)conn->netdev->priv; __u16 msglen = eib->ln1msg2.ipbfln1f; int rc;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif if (!conn->netdev) { /* FRITZ: How to tell iucv LL to drop the msg? */ printk(KERN_WARNING "Received data for unlinked connection\n"); return; } if (msglen > conn->max_buffsize) { /* FRITZ: How to tell iucv LL to drop the msg? */ privptr->stats.rx_dropped++; return; } conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, conn->rx_buff->data, msglen, NULL, NULL, NULL); if (rc != 0 || msglen < 5) { privptr->stats.rx_errors++; return; } netiucv_unpack_skb(conn, conn->rx_buff);}static voidconn_action_txdone(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; netiucv_priv *privptr = NULL; /* Shut up, gcc! skb is always below 2G. */ struct sk_buff *skb = (struct sk_buff *)(unsigned long)eib->ipmsgtag; __u32 txbytes = 0; __u32 txpackets = 0; __u32 stat_maxcq = 0; unsigned long saveflags; ll_header header;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif fsm_deltimer(&conn->timer); if (conn && conn->netdev && conn->netdev->priv) privptr = (netiucv_priv *)conn->netdev->priv; if (skb) { if (privptr) { privptr->stats.tx_packets++; privptr->stats.tx_bytes += (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); } dev_kfree_skb_any(skb); } conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; conn->tx_buff->len = 0; spin_lock_irqsave(&conn->collect_lock, saveflags); while ((skb = skb_dequeue(&conn->collect_queue))) { header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN; memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); memcpy(skb_put(conn->tx_buff, skb->len), skb->data, skb->len); txbytes += skb->len; txpackets++; stat_maxcq++; atomic_dec(&skb->users); dev_kfree_skb_any(skb); } if (conn->collect_len > conn->prof.maxmulti) conn->prof.maxmulti = conn->collect_len; conn->collect_len = 0; spin_unlock_irqrestore(&conn->collect_lock, saveflags); if (conn->tx_buff->len) { int rc; header.next = 0; memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, CONN_EVENT_TIMER, conn); conn->prof.send_stamp = xtime; rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, conn->tx_buff->data, conn->tx_buff->len); conn->prof.doios_multi++; conn->prof.txlen += conn->tx_buff->len; if (rc != 0) { fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); if (privptr) privptr->stats.tx_errors += txpackets; } else { if (privptr) { privptr->stats.tx_packets += txpackets; privptr->stats.tx_bytes += txbytes; } if (stat_maxcq > conn->prof.maxcqueue) conn->prof.maxcqueue = stat_maxcq; } } else fsm_newstate(fi, CONN_STATE_IDLE);}static voidconn_action_connaccept(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; net_device *netdev = conn->netdev; netiucv_priv *privptr = (netiucv_priv *)netdev->priv; int rc; __u16 msglimit; __u8 udata[16];#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, conn->handle, conn, NULL, &msglimit); if (rc != 0) { printk(KERN_WARNING "%s: IUCV accept failed with error %d\n", netdev->name, rc); return; } fsm_newstate(fi, CONN_STATE_IDLE); conn->pathid = eib->ippathid; netdev->tx_queue_len = msglimit; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);}static voidconn_action_connreject(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; // iucv_connection *conn = ev->conn; iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; __u8 udata[16];#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif iucv_sever(eib->ippathid, udata);}static voidconn_action_connack(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; net_device *netdev = conn->netdev; netiucv_priv *privptr = (netiucv_priv *)netdev->priv;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif fsm_newstate(fi, CONN_STATE_IDLE); conn->pathid = eib->ippathid; netdev->tx_queue_len = eib->ipmsglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);}static voidconn_action_connsever(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; // iucv_ConnectionSevered *eib = (iucv_ConnectionSevered *)ev->data; net_device *netdev = conn->netdev; netiucv_priv *privptr = (netiucv_priv *)netdev->priv; int state = fsm_getstate(fi);#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif switch (state) { case CONN_STATE_IDLE: case CONN_STATE_TX: printk(KERN_INFO "%s: Remote dropped connection\n", netdev->name); if (conn->handle) iucv_unregister_program(conn->handle); conn->handle = 0; fsm_newstate(fi, CONN_STATE_STOPPED); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); break; }}static voidconn_action_start(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; int rc;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif if (conn->handle == 0) { conn->handle = iucv_register_program(iucvMagic, conn->userid, mask, &netiucv_ops, conn); fsm_newstate(fi, CONN_STATE_STARTWAIT); if (conn->handle <= 0) { fsm_newstate(fi, CONN_STATE_REGERR); conn->handle = 0; return; }#ifdef DEBUG printk(KERN_DEBUG "%s('%s'): registered successfully\n", conn->netdev->name, conn->userid);#endif }#ifdef DEBUG printk(KERN_DEBUG "%s('%s'): connecting ...\n", conn->netdev->name, conn->userid);#endif rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, conn->userid, iucv_host, 0, NULL, NULL, conn->handle, conn); fsm_newstate(fi, CONN_STATE_SETUPWAIT); switch (rc) { case 0: return; case 11: printk(KERN_NOTICE "%s: User %s is currently not available.\n", conn->netdev->name, netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); return; case 12: printk(KERN_NOTICE "%s: User %s is currently not ready.\n", conn->netdev->name, netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); return; case 13: printk(KERN_WARNING "%s: Too many IUCV connections.\n", conn->netdev->name); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 14: printk(KERN_WARNING "%s: User %s has too many IUCV connections.\n", conn->netdev->name, netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 15: printk(KERN_WARNING "%s: No IUCV authorization in CP directory.\n", conn->netdev->name); fsm_newstate(fi, CONN_STATE_CONNERR); break; default: printk(KERN_WARNING "%s: iucv_connect returned error %d\n", conn->netdev->name, rc); fsm_newstate(fi, CONN_STATE_CONNERR); break; } iucv_unregister_program(conn->handle); conn->handle = 0;}static voidnetiucv_purge_skb_queue(struct sk_buff_head *q){ struct sk_buff *skb; while ((skb = skb_dequeue(q))) { atomic_dec(&skb->users); dev_kfree_skb_any(skb); }}static voidconn_action_stop(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; net_device *netdev = conn->netdev; netiucv_priv *privptr = (netiucv_priv *)netdev->priv;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); if (conn->handle) iucv_unregister_program(conn->handle); conn->handle = 0; fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);}static voidconn_action_inval(fsm_instance *fi, int event, void *arg){ iucv_event *ev = (iucv_event *)arg; iucv_connection *conn = ev->conn; net_device *netdev = conn->netdev; printk(KERN_WARNING "%s: Cannot connect without username\n", netdev->name);}static const fsm_node conn_fsm[] = { { CONN_STATE_INVALID, CONN_EVENT_START, conn_action_inval }, { CONN_STATE_STOPPED, CONN_EVENT_START, conn_action_start }, { CONN_STATE_STARTWAIT, CONN_EVENT_START, conn_action_start }, { CONN_STATE_STARTWAIT, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_SETUPWAIT, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_IDLE, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_TX, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_REGERR, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_CONNERR, CONN_EVENT_STOP, conn_action_stop }, { CONN_STATE_STOPPED, CONN_EVENT_CONN_REQ, conn_action_connreject }, { CONN_STATE_STARTWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept }, { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept }, { CONN_STATE_IDLE, CONN_EVENT_CONN_REQ, conn_action_connreject }, { CONN_STATE_TX, CONN_EVENT_CONN_REQ, conn_action_connreject }, { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_ACK, conn_action_connack }, { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REJ, conn_action_connsever }, { CONN_STATE_IDLE, CONN_EVENT_CONN_REJ, conn_action_connsever }, { CONN_STATE_TX, CONN_EVENT_CONN_REJ, conn_action_connsever }, { CONN_STATE_IDLE, CONN_EVENT_RX, conn_action_rx }, { CONN_STATE_TX, CONN_EVENT_RX, conn_action_rx }, { CONN_STATE_TX, CONN_EVENT_TXDONE, conn_action_txdone },};static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);/** * Actions for interface - statemachine. *****************************************************************************//** * Startup connection by sending CONN_EVENT_START to it. * * @param fi An instance of an interface statemachine. * @param event The event, just happened. * @param arg Generic pointer, casted from net_device * upon call. */static voiddev_action_start(fsm_instance *fi, int event, void *arg){ net_device *dev = (net_device *)arg; netiucv_priv *privptr = dev->priv; iucv_event ev;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STARTWAIT); fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);}/** * Shutdown connection by sending CONN_EVENT_STOP to it. * * @param fi An instance of an interface statemachine. * @param event The event, just happened. * @param arg Generic pointer, casted from net_device * upon call. */static voiddev_action_stop(fsm_instance *fi, int event, void *arg){ net_device *dev = (net_device *)arg; netiucv_priv *privptr = dev->priv; iucv_event ev;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STOPWAIT); fsm_event(privptr->conn->fsm, CONN_EVENT_STOP, &ev);}/** * Called from connection statemachine * when a connection is up and running. * * @param fi An instance of an interface statemachine. * @param event The event, just happened. * @param arg Generic pointer, casted from net_device * upon call. */static voiddev_action_connup(fsm_instance *fi, int event, void *arg){ net_device *dev = (net_device *)arg;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif switch (fsm_getstate(fi)) { case DEV_STATE_STARTWAIT: fsm_newstate(fi, DEV_STATE_RUNNING); printk(KERN_INFO "%s: connected with remote side\n", dev->name); break; case DEV_STATE_STOPWAIT: printk(KERN_INFO "%s: got connection UP event during shutdown!!\n", dev->name); break; }}/** * Called from connection statemachine * when a connection has been shutdown. * * @param fi An instance of an interface statemachine. * @param event The event, just happened. * @param arg Generic pointer, casted from net_device * upon call. */static voiddev_action_conndown(fsm_instance *fi, int event, void *arg){ net_device *dev = (net_device *)arg; netiucv_priv *privptr = dev->priv; iucv_event ev;#ifdef DEBUG printk(KERN_DEBUG "%s() called\n", __FUNCTION__);#endif switch (fsm_getstate(fi)) { case DEV_STATE_RUNNING: fsm_newstate(fi, DEV_STATE_STARTWAIT); ev.conn = privptr->conn; fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); break; case DEV_STATE_STARTWAIT: break; case DEV_STATE_STOPWAIT: fsm_newstate(fi, DEV_STATE_STOPPED); break; }}static const fsm_node dev_fsm[] = { { DEV_STATE_STOPPED, DEV_EVENT_START, dev_action_start }, { DEV_STATE_STOPWAIT, DEV_EVENT_START, dev_action_start }, { DEV_STATE_STOPWAIT, DEV_EVENT_CONDOWN, dev_action_conndown }, { DEV_STATE_STARTWAIT, DEV_EVENT_STOP, dev_action_stop }, { DEV_STATE_STARTWAIT, DEV_EVENT_CONUP, dev_action_connup }, { DEV_STATE_STARTWAIT, DEV_EVENT_CONDOWN, dev_action_conndown }, { DEV_STATE_RUNNING, DEV_EVENT_STOP, dev_action_stop }, { DEV_STATE_RUNNING, DEV_EVENT_CONDOWN, dev_action_conndown }, { DEV_STATE_RUNNING, DEV_EVENT_CONUP, fsm_action_nop },};static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -