af_spx.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:24k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * This module implements the (SPP-derived) Sequenced Packet eXchange
  3.  * (SPX) protocol for Linux 2.1.X as specified in
  4.  * NetWare SPX Services Specification, Semantics and API
  5.  *  Revision:       1.00
  6.  *  Revision Date:  February 9, 1993
  7.  *
  8.  * Developers:
  9.  *      Jay Schulist    <jschlst@samba.org>
  10.  * Jim Freeman <jfree@caldera.com>
  11.  *
  12.  * Changes:
  13.  * Alan Cox : Fixed an skb_unshare check for NULL
  14.  * that crashed it under load. Renamed and
  15.  * made static the ipx ops. Removed the hack
  16.  * ipx methods interface. Dropped AF_SPX - its
  17.  * the wrong abstraction.
  18.  * Eduardo Trapani : Added a check for the return value of
  19.  * ipx_if_offset that crashed sock_alloc_send_skb.
  20.  * Added spx_datagram_poll() so that select()
  21.  * works now on SPX sockets.  Added updating
  22.  * of the alloc count to follow rmt_seq.
  23.  *
  24.  * This program is free software; you can redistribute it and/or
  25.  *      modify it under the terms of the GNU General Public License
  26.  *      as published by the Free Software Foundation; either version
  27.  *      2 of the License, or (at your option) any later version.
  28.  *
  29.  * None of the authors or maintainers or their employers admit
  30.  * liability nor provide warranty for any of this software.
  31.  * This material is provided "as is" and at no charge.
  32.  */
  33. #include <linux/module.h>
  34. #include <net/ipx.h>
  35. #include <net/spx.h>
  36. #include <net/sock.h>
  37. #include <asm/byteorder.h>
  38. #include <asm/uaccess.h>
  39. #include <linux/uio.h>
  40. #include <linux/unistd.h>
  41. #include <linux/poll.h>
  42. static struct proto_ops *ipx_operations;
  43. static struct proto_ops spx_ops;
  44. static __u16  connids;
  45. /* Functions needed for SPX connection start up */
  46. static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
  47. static void spx_retransmit(unsigned long data);
  48. static void spx_watchdog(unsigned long data);
  49. void spx_rcv(struct sock *sk, int bytes);
  50. extern void ipx_remove_socket(struct sock *sk);
  51. /* Datagram poll: the same code as datagram_poll() in net/core
  52. but the right spx buffers are looked at and
  53. there is no question on the type of the socket
  54. */
  55. static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
  56. {
  57. struct sock *sk = sock->sk;
  58. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  59. unsigned int mask;
  60. poll_wait(file, sk->sleep, wait);
  61. mask = 0;
  62. /* exceptional events? */
  63. if (sk->err || !skb_queue_empty(&sk->error_queue))
  64. mask |= POLLERR;
  65. if (sk->shutdown & RCV_SHUTDOWN)
  66. mask |= POLLHUP;
  67. /* readable? */
  68. if (!skb_queue_empty(&pdata->rcv_queue))
  69. mask |= POLLIN | POLLRDNORM;
  70. /* Need to check for termination and startup */
  71. if (sk->state==TCP_CLOSE)
  72. mask |= POLLHUP;
  73. /* connection hasn't started yet? */
  74. if (sk->state == TCP_SYN_SENT)
  75. return mask;
  76. /* writable? */
  77. if (sock_writeable(sk))
  78. mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
  79. else
  80. set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
  81. return mask;
  82. }
  83. /* Create the SPX specific data */
  84. static int spx_sock_init(struct sock *sk)
  85. {
  86.         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  87.         pdata->state            = SPX_CLOSED;
  88.         pdata->sequence         = 0;
  89. pdata->acknowledge = 0;
  90.         pdata->source_connid    = htons(connids);
  91. pdata->rmt_seq = 0;
  92.         connids++;
  93.         pdata->owner            = (void *)sk;
  94.         pdata->sndbuf           = sk->sndbuf;
  95.         pdata->watchdog.function = spx_watchdog;
  96.         pdata->watchdog.data    = (unsigned long)sk;
  97.         pdata->wd_interval      = VERIFY_TIMEOUT;
  98. pdata->retransmit.function = spx_retransmit;
  99. pdata->retransmit.data = (unsigned long)sk;
  100. pdata->retransmits = 0;
  101.         pdata->retries          = 0;
  102.         pdata->max_retries      = RETRY_COUNT;
  103. skb_queue_head_init(&pdata->rcv_queue);
  104. skb_queue_head_init(&pdata->transmit_queue);
  105. skb_queue_head_init(&pdata->retransmit_queue);
  106.         return (0);
  107. }
  108. static int spx_create(struct socket *sock, int protocol)
  109. {
  110. struct sock *sk;
  111. /*
  112.  * Called on connection receive so cannot be GFP_KERNEL
  113.  */
  114.  
  115. sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
  116. if(sk == NULL)
  117.                 return (-ENOMEM);
  118. switch(sock->type)
  119.         {
  120.                 case SOCK_SEQPACKET:
  121. sock->ops = &spx_ops;
  122. break;
  123. default:
  124. sk_free(sk);
  125.                         return (-ESOCKTNOSUPPORT);
  126.         }
  127. sock_init_data(sock, sk);
  128. spx_sock_init(sk);
  129. sk->data_ready  = spx_rcv;
  130. sk->destruct  = NULL;
  131.         sk->no_check  = 1;
  132.         MOD_INC_USE_COUNT;
  133. return (0);
  134. }
  135. void spx_close_socket(struct sock *sk)
  136. {
  137. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  138. pdata->state = SPX_CLOSED;
  139. sk->state  = TCP_CLOSE;
  140. del_timer(&pdata->retransmit);
  141. del_timer(&pdata->watchdog);
  142. }
  143. void spx_destroy_socket(struct sock *sk)
  144. {
  145. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  146. struct sk_buff *skb;
  147.         ipx_remove_socket(sk);
  148.         while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
  149.                 kfree_skb(skb);
  150. while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL)
  151.                 kfree_skb(skb);
  152. while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
  153. kfree_skb(skb);
  154. while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
  155.                 kfree_skb(skb);
  156.         sk_free(sk);
  157. MOD_DEC_USE_COUNT;
  158. }
  159. /* Release an SPX socket */
  160. static int spx_release(struct socket *sock)
  161. {
  162.   struct sock *sk = sock->sk;
  163. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  164. if(sk == NULL)
  165. return (0);
  166. if(!sk->dead)
  167.                 sk->state_change(sk);
  168.         sk->dead = 1;
  169. if(pdata->state != SPX_CLOSED)
  170. {
  171. spx_transmit(sk, NULL, DISCON, 0);
  172. spx_close_socket(sk);
  173. }
  174. sock->sk = NULL;
  175. sk->socket  = NULL;
  176. spx_destroy_socket(sk);
  177.         return (0);
  178. }
  179. /* Move a socket into listening state. */
  180. static int spx_listen(struct socket *sock, int backlog)
  181. {
  182.         struct sock *sk = sock->sk;
  183.         if(sock->state != SS_UNCONNECTED)
  184.                 return (-EINVAL);
  185. if(sock->type != SOCK_SEQPACKET)
  186. return (-EOPNOTSUPP);
  187.         if(sk->zapped != 0)
  188.                 return (-EAGAIN);
  189.         sk->max_ack_backlog = backlog;
  190.         if(sk->state != TCP_LISTEN)
  191.         {
  192.                 sk->ack_backlog = 0;
  193.                 sk->state = TCP_LISTEN;
  194.         }
  195.         sk->socket->flags |= __SO_ACCEPTCON;
  196.         return (0);
  197. }
  198. /* Accept a pending SPX connection */
  199. static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
  200. {
  201.         struct sock *sk;
  202.         struct sock *newsk;
  203.         struct sk_buff *skb;
  204. int err;
  205. if(sock->sk == NULL)
  206. return (-EINVAL);
  207. sk = sock->sk;
  208.         if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON))
  209.                 return (-EINVAL);
  210.         if(sock->type != SOCK_SEQPACKET)
  211. return (-EOPNOTSUPP);
  212. if(sk->state != TCP_LISTEN)
  213.                 return (-EINVAL);
  214. cli();
  215. do {
  216. skb = skb_dequeue(&sk->receive_queue);
  217. if(skb == NULL)
  218. {
  219.                  if(flags & O_NONBLOCK)
  220. {
  221.                                 sti();
  222.                                 return (-EWOULDBLOCK);
  223.                         }
  224.                  interruptible_sleep_on(sk->sleep);
  225.                  if(signal_pending(current))
  226.                  {
  227.                          sti();
  228.                          return (-ERESTARTSYS);
  229.                  }
  230. }
  231. } while (skb == NULL);
  232. newsk  = skb->sk;
  233.         newsk->pair  = NULL;
  234. sti();
  235. err = spx_transmit(newsk, skb, CONACK, 0);   /* Connection ACK */
  236. if(err)
  237. return (err);
  238. /* Now attach up the new socket */
  239. sock->sk  = NULL;
  240.         sk->ack_backlog--;
  241.         newsock->sk  = newsk;
  242. newsk->state  = TCP_ESTABLISHED;
  243. newsk->protinfo.af_ipx.dest_addr = newsk->tp_pinfo.af_spx.dest_addr;
  244. return (0);
  245. }
  246. /* Build a connection to an SPX socket */
  247. static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
  248.                 int addr_len, int flags)
  249. {
  250. struct sock *sk = sock->sk;
  251.         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  252.         struct sockaddr_ipx src;
  253. struct sk_buff *skb;
  254. int size, err;
  255. size = sizeof(src);
  256. err  = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
  257. if(err)
  258. return (err);
  259.         pdata->source_addr.net = src.sipx_network;
  260.         memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
  261.         pdata->source_addr.sock = (unsigned short)src.sipx_port;
  262. err = ipx_operations->connect(sock, uaddr, addr_len, flags);
  263.         if(err)
  264.                 return (err);
  265.         pdata->dest_addr = sk->protinfo.af_ipx.dest_addr;
  266. pdata->state  = SPX_CONNECTING;
  267. sock->state  = SS_CONNECTING;
  268.         sk->state  = TCP_SYN_SENT;
  269.         /* Send Connection request */
  270. err = spx_transmit(sk, NULL, CONREQ, 0);
  271.         if(err)
  272.                 return (err);
  273. cli();
  274.         do {
  275.                 skb = skb_dequeue(&sk->receive_queue);
  276.                 if(skb == NULL)
  277.                 {
  278.                         if(flags & O_NONBLOCK)
  279.                         {
  280.                                 sti();
  281.                                 return (-EWOULDBLOCK);
  282.                         }
  283.                         interruptible_sleep_on(sk->sleep);
  284.                         if(signal_pending(current))
  285.                         {
  286.                                 sti();
  287.                                 return (-ERESTARTSYS);
  288.                         }
  289.                 }
  290.         } while (skb == NULL);
  291.         if(pdata->state == SPX_CLOSED)
  292.         {
  293. sti();
  294.                 del_timer(&pdata->watchdog);
  295.                 return (-ETIMEDOUT);
  296.         }
  297. sock->state = SS_CONNECTED;
  298. sk->state  = TCP_ESTABLISHED;
  299. kfree_skb(skb);
  300. sti();
  301.         return (0);
  302. }
  303. /*
  304.  * Calculate the timeout for a packet. Thankfully SPX has a large
  305.  * fudge factor (3/4 secs) and does not pay much attention to RTT.
  306.  * As we simply have a default retry time of 1*HZ and a max retry
  307.  * time of 5*HZ. Between those values we increase the timeout based
  308.  * on the number of retransmit tries.
  309.  *
  310.  * FixMe: This is quite fake, but will work for now. (JS)
  311.  */
  312. static inline unsigned long spx_calc_rtt(int tries)
  313. {
  314.         if(tries < 1)
  315.                 return (RETRY_TIME);
  316.         if(tries > 5)
  317.                 return (MAX_RETRY_DELAY);
  318.         return (tries * HZ);
  319. }
  320. static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
  321. {
  322. struct sk_buff *skb2;
  323. int err = 0;
  324. skb = skb_unshare(skb, GFP_ATOMIC);
  325. if(skb == NULL)
  326. return (-ENOBUFS);
  327. switch(type)
  328. {
  329. case (CONREQ):
  330. case (DATA):
  331. if(!skb_queue_empty(&pdata->retransmit_queue))
  332. {
  333. skb_queue_tail(&pdata->transmit_queue, skb);
  334. return 0;
  335. }
  336. case (TQUEUE):
  337. pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
  338. add_timer(&pdata->retransmit);
  339. skb2 = skb_clone(skb, GFP_NOIO);
  340.                 if(skb2 == NULL)
  341.                          return -ENOBUFS;
  342.                  skb_queue_tail(&pdata->retransmit_queue, skb2);
  343. case (ACK):
  344. case (CONACK):
  345. case (WDREQ):
  346. case (WDACK):
  347. case (DISCON):
  348. case (DISACK):
  349. case (RETRAN):
  350. default:
  351. /* Send data */
  352.          err = ipxrtr_route_skb(skb);
  353.          if(err)
  354.                  kfree_skb(skb);
  355. }
  356. return (err);
  357. }
  358. /* SPX packet transmit engine */
  359. static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
  360. {
  361.         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  362.         struct ipxspxhdr *ipxh;
  363. unsigned long flags;
  364. int err;
  365. if(skb == NULL)
  366. {
  367. int offset  = ipx_if_offset(pdata->dest_addr.net);
  368.          int size    = offset + sizeof(struct ipxspxhdr);
  369.          if (offset < 0) /* ENETUNREACH */
  370.          return(-ENETUNREACH);
  371. save_flags(flags);
  372. cli();
  373.          skb = sock_alloc_send_skb(sk, size, 0, &err);
  374.          if(skb == NULL) {
  375. restore_flags(flags);
  376.                  return (-ENOMEM);
  377. }
  378.          skb_reserve(skb, offset);
  379.          skb->h.raw = skb->nh.raw = skb_put(skb,sizeof(struct ipxspxhdr));
  380. restore_flags(flags);
  381. }
  382. /* IPX header */
  383. ipxh = (struct ipxspxhdr *)skb->nh.raw;
  384. ipxh->ipx.ipx_checksum  = 0xFFFF;
  385. ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN);
  386.         ipxh->ipx.ipx_tctrl     = 0;
  387. ipxh->ipx.ipx_type  = IPX_TYPE_SPX;
  388.         ipxh->ipx.ipx_dest      = pdata->dest_addr;
  389.         ipxh->ipx.ipx_source    = pdata->source_addr;
  390. /* SPX header */
  391.         ipxh->spx.dtype         = 0;
  392. ipxh->spx.sequence      = htons(pdata->sequence);
  393. ipxh->spx.ackseq        = htons(pdata->rmt_seq);
  394. ipxh->spx.sconn         = pdata->source_connid;
  395.         ipxh->spx.dconn         = pdata->dest_connid;
  396.         ipxh->spx.allocseq      = htons(pdata->alloc);
  397. /* Reset/Set WD timer */
  398.         mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
  399. switch(type)
  400. {
  401. case (DATA): /* Data */
  402. ipxh->ipx.ipx_pktsize  = htons(SPX_SYS_PKT_LEN + len);
  403. ipxh->spx.cctl  = (CCTL_ACK | CCTL_EOM);
  404.                  pdata->sequence++;
  405. break;
  406. case (ACK): /* ACK */
  407. pdata->rmt_seq++;
  408. case (WDACK): /* WD ACK */
  409. case (CONACK): /* Connection ACK */
  410. ipxh->spx.cctl  = CCTL_SYS;
  411. ipxh->spx.ackseq  = htons(pdata->rmt_seq);
  412. break;
  413. case (CONREQ): /* Connection Request */
  414. del_timer(&pdata->watchdog);
  415. case (WDREQ): /* WD Request */
  416. pdata->source_connid    = htons(connids++);
  417.                  pdata->dest_connid      = 0xFFFF;
  418.                  pdata->alloc  = 3 + pdata->rmt_seq;
  419. ipxh->spx.cctl          = (CCTL_ACK | CCTL_SYS);
  420. ipxh->spx.sconn         = pdata->source_connid;
  421.         ipxh->spx.dconn         = pdata->dest_connid;
  422.         ipxh->spx.allocseq      = htons(pdata->alloc);
  423. break;
  424. case (DISCON): /* Informed Disconnect */
  425. ipxh->spx.cctl  = CCTL_ACK;
  426. ipxh->spx.dtype  = SPX_DTYPE_ECONN;
  427. break;
  428. case (DISACK): /* Informed Disconnect ACK */
  429. ipxh->spx.cctl   = 0;
  430. ipxh->spx.dtype  = SPX_DTYPE_ECACK;
  431. ipxh->spx.sequence  = 0;
  432. ipxh->spx.ackseq  = htons(pdata->rmt_seq++);
  433. break;
  434. default:
  435. return (-EOPNOTSUPP);
  436. }
  437. /* Send data */
  438.         return (spx_route_skb(pdata, skb, type));
  439. }
  440. /* Check the state of the connection and send a WD request if needed. */
  441. static void spx_watchdog(unsigned long data)
  442. {
  443. struct sock *sk = (struct sock*)data;
  444.         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  445.         del_timer(&pdata->watchdog);
  446. if(pdata->state == SPX_CLOSED)
  447.                 return;
  448. if(pdata->retries > pdata->max_retries)
  449.         {
  450. spx_close_socket(sk); /* Unilateral Abort */
  451.                 return;
  452.         }
  453.         /* Send WD request */
  454. spx_transmit(sk, NULL, WDREQ, 0);
  455. pdata->retries++;
  456.         return;
  457. }
  458. static void spx_retransmit(unsigned long data)
  459. {
  460. struct sock *sk = (struct sock*)data;
  461.         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  462. struct sk_buff *skb;
  463. unsigned long flags;
  464. int err;
  465. del_timer(&pdata->retransmit);
  466. if(pdata->state == SPX_CLOSED)
  467. return;
  468. if(pdata->retransmits > RETRY_COUNT)
  469. {
  470. spx_close_socket(sk);   /* Unilateral Abort */
  471.                 return;
  472.         }
  473. /* Need to leave skb on the queue, aye the fear */
  474. save_flags(flags);
  475. cli();
  476. skb = skb_peek(&pdata->retransmit_queue);
  477. if(skb_cloned(skb))
  478.                 skb = skb_copy(skb, GFP_ATOMIC);
  479.         else
  480.                 skb = skb_clone(skb, GFP_ATOMIC);
  481. restore_flags(flags);
  482. pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
  483. add_timer(&pdata->retransmit);
  484. err = spx_route_skb(pdata, skb, RETRAN);
  485. pdata->retransmits++;
  486. return;
  487. }
  488. /* Check packet for retransmission, ConReqAck aware */
  489. static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
  490. {
  491. struct ipxspxhdr *ipxh;
  492. struct sk_buff *skb;
  493. skb = skb_dequeue(&pdata->retransmit_queue);
  494. if(!skb)
  495. return (-ENOENT);
  496. /* Check Data/ACK seq */
  497. switch(type)
  498. {
  499. case ACK: /* Check Sequence, Should == 1 */
  500. ipxh = (struct ipxspxhdr *)skb->nh.raw;
  501. if(!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
  502. break;
  503. case CONACK:
  504. del_timer(&pdata->retransmit);
  505. pdata->retransmits = 0;
  506. kfree_skb(skb);
  507. if(skb_queue_empty(&pdata->retransmit_queue))
  508. {
  509. skb = skb_dequeue(&pdata->transmit_queue);
  510. if(skb != NULL)
  511. spx_route_skb(pdata, skb, TQUEUE);
  512. }
  513. return (0);
  514. }
  515. skb_queue_head(&pdata->retransmit_queue, skb);
  516. return (-1);
  517. }
  518. /* SPX packet receive engine */
  519. void spx_rcv(struct sock *sk, int bytes)
  520. {
  521. struct sk_buff *skb;
  522. struct ipxspxhdr *ipxh;
  523. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  524. skb = skb_dequeue(&sk->receive_queue);
  525. if(skb == NULL)
  526. return;
  527. ipxh = (struct ipxspxhdr *)skb->nh.raw;
  528. /* Can't receive on a closed connection */
  529.         if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))
  530. goto toss_skb;
  531. if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)
  532. goto toss_skb;
  533.         if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
  534. goto toss_skb;
  535.         if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
  536. goto toss_skb;
  537. /* Reset WD timer on any received packet */
  538. del_timer(&pdata->watchdog);
  539. pdata->retries = 0;
  540. pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
  541.         add_timer(&pdata->watchdog);
  542. switch(ipxh->spx.cctl)
  543. {
  544. case (CCTL_SYS | CCTL_ACK):
  545. if((ipxh->spx.sequence == 0) /* ConReq */
  546. && (ipxh->spx.ackseq == 0)
  547. && (ipxh->spx.dconn == 0xFFFF))
  548. {
  549. pdata->state = SPX_CONNECTED;
  550. pdata->dest_addr        = ipxh->ipx.ipx_source;
  551. pdata->source_addr      = ipxh->ipx.ipx_dest;
  552. pdata->dest_connid      = ipxh->spx.sconn;
  553. pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
  554. skb_queue_tail(&sk->receive_queue, skb);
  555. wake_up_interruptible(sk->sleep);
  556. }
  557. else /* WD Request */
  558. spx_transmit(sk, skb, WDACK, 0);
  559. goto finish;
  560. case CCTL_SYS: /* ACK */
  561. if((ipxh->spx.dtype == 0)       /* ConReq ACK */
  562.                                 && (ipxh->spx.sconn != 0xFFFF)
  563.                                 && (ipxh->spx.dconn != 0xFFFF)
  564.                                 && (ipxh->spx.sequence == 0)
  565.                                 && (ipxh->spx.ackseq == 0)
  566.                                 && (pdata->state != SPX_CONNECTED))
  567.                         {
  568.                                 pdata->state = SPX_CONNECTED;
  569. pdata->dest_connid = ipxh->spx.sconn;
  570. if(spx_retransmit_chk(pdata, 0, CONACK) < 0)
  571. goto toss_skb;
  572.                                 skb_queue_tail(&sk->receive_queue, skb);
  573.                                 wake_up_interruptible(sk->sleep);
  574.                                 goto finish;
  575.                         }
  576. spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
  577. goto toss_skb;
  578. case (CCTL_ACK):
  579. /* Informed Disconnect */
  580. if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
  581. {
  582. spx_transmit(sk, skb, DISACK, 0);
  583. spx_close_socket(sk);
  584. goto finish;
  585. }
  586. /* Fall through */
  587. default:
  588. if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
  589. {
  590. pdata->rmt_seq = ntohs(ipxh->spx.sequence);
  591. pdata->rmt_ack = ntohs(ipxh->spx.ackseq);
  592. pdata->alloc   = pdata->rmt_seq + 3;
  593. if(pdata->rmt_ack > 0 || pdata->rmt_ack == 0)
  594. spx_retransmit_chk(pdata,pdata->rmt_ack, ACK);
  595. skb_queue_tail(&pdata->rcv_queue, skb);
  596. wake_up_interruptible(sk->sleep);
  597. if(ipxh->spx.cctl&CCTL_ACK)
  598. spx_transmit(sk, NULL, ACK, 0);
  599. goto finish;
  600. }
  601. if(ipxh->spx.dtype == SPX_DTYPE_ECACK)
  602. {
  603. if(pdata->state != SPX_CLOSED)
  604. spx_close_socket(sk);
  605. goto toss_skb;
  606. }
  607. }
  608. toss_skb: /* Catch All */
  609. kfree_skb(skb);
  610. finish:
  611.         return;
  612. }
  613. /* Get message/packet data from user-land */
  614. static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
  615. struct scm_cookie *scm)
  616. {
  617. struct sock *sk = sock->sk;
  618. int flags = msg->msg_flags;
  619. struct sk_buff *skb;
  620. int err, offset, size;
  621. if(len > 534)
  622.                 return (-EMSGSIZE);
  623.         if(sk->zapped)
  624.                 return (-ENOTCONN); /* Socket not bound */
  625. if(flags&~MSG_DONTWAIT)
  626.                 return (-EINVAL);
  627. offset = ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
  628.         size  = offset + sizeof(struct ipxspxhdr) + len;
  629. cli();
  630.         skb   = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err);
  631. sti();
  632.         if(skb == NULL)
  633.                 return (err);
  634. skb->sk = sk;
  635.         skb_reserve(skb, offset);
  636. skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
  637. err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
  638. if(err)
  639.         {
  640.                 kfree_skb(skb);
  641.                 return (-EFAULT);
  642.         }
  643. err = spx_transmit(sk, skb, DATA, len);
  644. if(err)
  645. return (-EAGAIN);
  646.         return (len);
  647. }
  648. /* Send message/packet data to user-land */
  649. static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
  650. int flags, struct scm_cookie *scm)
  651. {
  652. struct sk_buff *skb;
  653. struct ipxspxhdr *ispxh;
  654. struct sock *sk = sock->sk;
  655. struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
  656. struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
  657. int copied, err;
  658.         if(sk->zapped)
  659.                 return (-ENOTCONN); /* Socket not bound */
  660. lock_sock(sk);
  661. restart:
  662.         while(skb_queue_empty(&pdata->rcv_queue))      /* No data */
  663.         {
  664.                 /* Socket errors? */
  665.                 err = sock_error(sk);
  666.                 if(err)
  667. return (err);
  668.                 /* Socket shut down? */
  669.                 if(sk->shutdown & RCV_SHUTDOWN)
  670. return (-ESHUTDOWN);
  671.                 /* handle signals */
  672.                 if(signal_pending(current))
  673. return (-ERESTARTSYS);
  674.                 /* User doesn't want to wait */
  675.                 if(flags&MSG_DONTWAIT)
  676. return (-EAGAIN);
  677. release_sock(sk);
  678.          save_flags(flags);
  679.          cli();
  680.          if(skb_peek(&pdata->rcv_queue) == NULL)
  681.                  interruptible_sleep_on(sk->sleep);
  682.          restore_flags(flags);
  683.          lock_sock(sk);
  684.         }
  685.         skb = skb_dequeue(&pdata->rcv_queue);
  686.         if(skb == NULL) 
  687. goto restart;
  688. ispxh  = (struct ipxspxhdr *)skb->nh.raw;
  689. copied  = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
  690.         if(copied > size)
  691. {
  692.                 copied = size;
  693.                 msg->msg_flags |= MSG_TRUNC;
  694.         }
  695. err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
  696.         if(err)
  697.                 return (-EFAULT);
  698. msg->msg_namelen = sizeof(*sipx);
  699. if(sipx)
  700. {
  701. sipx->sipx_family = AF_IPX;
  702.                 sipx->sipx_port = ispxh->ipx.ipx_source.sock;
  703.                 memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
  704.                 sipx->sipx_network = ispxh->ipx.ipx_source.net;
  705.                 sipx->sipx_type  = ispxh->ipx.ipx_type;
  706.         }
  707. kfree_skb(skb);
  708.         release_sock(sk);
  709. return (copied);
  710. }
  711. /*
  712.  * Functions which just wrap their IPX cousins
  713.  */
  714. static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  715. {
  716.         int err;
  717.         err = ipx_operations->bind(sock, uaddr, addr_len);
  718.         return (err);
  719. }
  720. static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
  721.                          int *usockaddr_len, int peer)
  722. {
  723. int err;
  724. err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
  725. return (err);
  726. }
  727. static int spx_ioctl (struct socket *sock, unsigned int cmd,
  728.                          unsigned long arg)
  729. {
  730. int err;
  731. err = ipx_operations->ioctl(sock, cmd, arg);
  732. return (err);
  733. }
  734. static int spx_setsockopt(struct socket *sock, int level, int optname,
  735.                          char *optval, int optlen)
  736. {
  737. int err;
  738. err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
  739. return (err);
  740. }
  741. static int spx_getsockopt(struct socket *sock, int level, int optname,
  742.                          char *optval, int *optlen)
  743. {
  744. int err;
  745. err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
  746. return (err);
  747. }
  748. static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
  749. family: PF_IPX,
  750. release: spx_release,
  751. bind: spx_bind,
  752. connect: spx_connect,
  753. socketpair: sock_no_socketpair,
  754. accept: spx_accept,
  755. getname: spx_getname,
  756. poll: spx_datagram_poll,
  757. ioctl: spx_ioctl,
  758. listen: spx_listen,
  759. shutdown: sock_no_shutdown,
  760. setsockopt: spx_setsockopt,
  761. getsockopt: spx_getsockopt,
  762. sendmsg: spx_sendmsg,
  763. recvmsg: spx_recvmsg,
  764. mmap: sock_no_mmap,
  765. sendpage: sock_no_sendpage,
  766. };
  767. #include <linux/smp_lock.h>
  768. SOCKOPS_WRAP(spx, PF_IPX);
  769. static struct net_proto_family spx_family_ops = {
  770. family: PF_IPX,
  771. create: spx_create,
  772. };
  773. static char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0n";
  774. static int __init spx_proto_init(void)
  775. {
  776. int error;
  777. connids = (__u16)jiffies; /* initalize random */
  778. error = ipx_register_spx(&ipx_operations, &spx_family_ops);
  779.         if (error)
  780.                 printk(KERN_ERR "SPX: unable to register with IPX.n");
  781. /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
  782. printk(banner);
  783. return 0;
  784. }
  785. module_init(spx_proto_init);
  786. static void __exit spx_proto_finito(void)
  787. {
  788. ipx_unregister_spx();
  789. return;
  790. }
  791. module_exit(spx_proto_finito);