📄 netiucv.c
字号:
struct net_device *dev = conn->netdev; struct netiucv_priv *privptr = dev->priv; __u16 offset = 0; 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) break; skb_pull(pskb, NETIUCV_HDRLEN); header->next -= offset; offset += header->next; header->next -= NETIUCV_HDRLEN; if (skb_tailroom(pskb) < header->next) { PRINT_WARN("%s: Illegal next field in iucv header: " "%d > %d\n", dev->name, header->next, skb_tailroom(pskb)); IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n", header->next, skb_tailroom(pskb)); return; } skb_put(pskb, header->next); pskb->mac.raw = pskb->data; skb = dev_alloc_skb(pskb->len); if (!skb) { PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n", dev->name); IUCV_DBF_TEXT(data, 2, "Out of memory in netiucv_unpack_skb\n"); 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; /* * Since receiving is always initiated from a tasklet (in iucv.c), * we must use netif_rx_ni() instead of netif_rx() */ netif_rx_ni(skb); dev->last_rx = jiffies; 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){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; __u32 msglen = eib->ln1msg2.ipbfln1f; int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (!conn->netdev) { /* FRITZ: How to tell iucv LL to drop the msg? */ PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, "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++; PRINT_WARN("msglen %d > max_buffsize %d\n", msglen, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", msglen, conn->max_buffsize); 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 || msglen < 5) { privptr->stats.rx_errors++; PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); return; } netiucv_unpack_skb(conn, conn->rx_buff);}static voidconn_action_txdone(fsm_instance *fi, int event, void *arg){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; struct netiucv_priv *privptr = NULL; /* Shut up, gcc! skb is always below 2G. */ __u32 single_flag = eib->ipmsgtag; __u32 txbytes = 0; __u32 txpackets = 0; __u32 stat_maxcq = 0; struct sk_buff *skb; unsigned long saveflags; ll_header header; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (conn && conn->netdev && conn->netdev->priv) privptr = (struct netiucv_priv *)conn->netdev->priv; conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { atomic_dec(&skb->users); dev_kfree_skb_any(skb); if (privptr) { privptr->stats.tx_packets++; privptr->stats.tx_bytes += (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); } } } 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); 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; conn->prof.tx_pending++; if (conn->prof.tx_pending > conn->prof.tx_max_pending) conn->prof.tx_max_pending = conn->prof.tx_pending; if (rc) { conn->prof.tx_pending--; fsm_newstate(fi, CONN_STATE_IDLE); if (privptr) privptr->stats.tx_errors += txpackets; PRINT_WARN("iucv_send returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); } 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){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; int rc; __u16 msglimit; __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, conn->handle, conn, NULL, &msglimit); if (rc) { PRINT_WARN("%s: IUCV accept failed with error %d\n", netdev->name, rc); IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", 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){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); iucv_sever(eib->ippathid, udata); if (eib->ippathid != conn->pathid) { PRINT_INFO("%s: IR Connection Pending; " "pathid %d does not match original pathid %d\n", netdev->name, eib->ippathid, conn->pathid); IUCV_DBF_TEXT_(data, 2, "connreject: IR pathid %d, conn. pathid %d\n", eib->ippathid, conn->pathid); iucv_sever(conn->pathid, udata); }}static voidconn_action_connack(fsm_instance *fi, int event, void *arg){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); if (eib->ippathid != conn->pathid) { PRINT_INFO("%s: IR Connection Complete; " "pathid %d does not match original pathid %d\n", netdev->name, eib->ippathid, conn->pathid); IUCV_DBF_TEXT_(data, 2, "connack: IR pathid %d, conn. pathid %d\n", eib->ippathid, conn->pathid); conn->pathid = eib->ippathid; } netdev->tx_queue_len = eib->ipmsglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);}static voidconn_action_conntimsev(fsm_instance *fi, int event, void *arg){ struct iucv_connection *conn = (struct iucv_connection *)arg; __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); iucv_sever(conn->pathid, udata); fsm_newstate(fi, CONN_STATE_STARTWAIT);}static voidconn_action_connsever(fsm_instance *fi, int event, void *arg){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); iucv_sever(conn->pathid, udata); PRINT_INFO("%s: Remote dropped connection\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);}static voidconn_action_start(fsm_instance *fi, int event, void *arg){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; __u16 msglimit; int rc; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (!conn->handle) { IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); conn->handle = iucv_register_program(iucvMagic, conn->userid, netiucv_mask, &netiucv_ops, conn); fsm_newstate(fi, CONN_STATE_STARTWAIT); if (!conn->handle) { fsm_newstate(fi, CONN_STATE_REGERR); conn->handle = NULL; IUCV_DBF_TEXT(setup, 2, "NULL from iucv_register_program\n"); return; } PRINT_DEBUG("%s('%s'): registered successfully\n", conn->netdev->name, conn->userid); } PRINT_DEBUG("%s('%s'): connecting ...\n", conn->netdev->name, conn->userid); /* We must set the state before calling iucv_connect because the callback * handler could be called at any point after the connection request is * sent */ fsm_newstate(fi, CONN_STATE_SETUPWAIT); rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, conn->userid, iucv_host, 0, NULL, &msglimit, conn->handle, conn); switch (rc) { case 0: conn->netdev->tx_queue_len = msglimit; fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, CONN_EVENT_TIMER, conn); return; case 11: PRINT_INFO("%s: User %s is currently not available.\n", conn->netdev->name, netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); return; case 12: PRINT_INFO("%s: User %s is currently not ready.\n", conn->netdev->name, netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); return; case 13: PRINT_WARN("%s: Too many IUCV connections.\n", conn->netdev->name); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 14: PRINT_WARN( "%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: PRINT_WARN( "%s: No IUCV authorization in CP directory.\n", conn->netdev->name); fsm_newstate(fi, CONN_STATE_CONNERR); break; default: PRINT_WARN("%s: iucv_connect returned error %d\n", conn->netdev->name, rc); fsm_newstate(fi, CONN_STATE_CONNERR); break; } IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); iucv_unregister_program(conn->handle); conn->handle = NULL;}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){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); if (conn->handle) IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); iucv_unregister_program(conn->handle); conn->handle = NULL; netiucv_purge_skb_queue(&conn->commit_queue); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);}static voidconn_action_inval(fsm_instance *fi, int event, void *arg){ struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; PRINT_WARN("%s: Cannot connect without username\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");}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_STOPPED, CONN_EVENT_STOP, conn_action_stop }, { 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_TIMER, conn_action_conntimsev }, { 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 }, { CONN_STATE_IDLE, 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 struct net_device * upon call. */static voiddev_action_start(fsm_instance *fi, int event, void *arg){ struct net_device *dev = (struct net_device *)arg; struct netiucv_priv *privptr = dev->priv; struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); 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 struct net_device * upon call. */static voiddev_action_stop(fsm_instance *fi, int event, void *arg){ struct net_device *dev = (struct net_device *)arg; struct netiucv_priv *privptr = dev->priv; struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); 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 struct net_device * upon call. */static voiddev_action_connup(fsm_instance *fi, int event, void *arg){ struct net_device *dev = (struct net_device *)arg; struct netiucv_priv *privptr = dev->priv; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); switch (fsm_getstate(fi)) { case DEV_STATE_STARTWAIT: fsm_newstate(fi, DEV_STATE_RUNNING); PRINT_INFO("%s: connected with remote side %s\n", dev->name, privptr->conn->userid); IUCV_DBF_TEXT(setup, 3, "connection is up and running\n"); break; case DEV_STATE_STOPWAIT: PRINT_INFO( "%s: got connection UP event during shutdown!\n", dev->name); IUCV_DBF_TEXT(data, 2, "dev_action_connup: in DEV_STATE_STOPWAIT\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -