/* * disc_conf messages are also called no_resources or no_link * messages depending upon the "reason" field. */ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); unsigned short reason; if (skb->len != 2) goto out; reason = dn_ntohs(*(__u16 *)skb->data); sk->state = TCP_CLOSE; switch(scp->state) { case DN_CI: scp->state = DN_NR; break; case DN_DR: if (reason == NSP_REASON_DC) scp->state = DN_DRC; if (reason == NSP_REASON_NL) scp->state = DN_CN; break; case DN_DI: scp->state = DN_DIC; break; case DN_RUN: sk->shutdown |= SHUTDOWN_MASK; case DN_CC: scp->state = DN_CN; } if (!sk->dead) { if (sk->socket->state != SS_UNCONNECTED) sk->socket->state = SS_DISCONNECTING; sk->state_change(sk); } scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); out: kfree_skb(skb); }
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval) { struct dn_scp *scp = DN_SK(sk); struct sk_buff *skb; unsigned char *ptr; gfp_t gfp = GFP_ATOMIC; if ((skb = dn_alloc_skb(sk, DN_MAX_NSP_DATA_HEADER + 2, gfp)) == NULL) return; skb_reserve(skb, DN_MAX_NSP_DATA_HEADER); ptr = skb_put(skb, 2); DN_SKB_CB(skb)->nsp_flags = 0x10; *ptr++ = lsflags; *ptr = fcval; dn_nsp_queue_xmit(sk, skb, gfp, 1); scp->persist = dn_nsp_persist(sk); scp->persist_fxn = dn_nsp_xmit_timeout; }
void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg) { struct dn_scp *scp = DN_SK(sk); struct nsp_conn_init_msg *msg; unsigned char aux; unsigned char menuver; struct dn_skb_cb *cb; unsigned char type = 1; gfp_t allocation = (msgflg == NSP_CI) ? sk->sk_allocation : GFP_ATOMIC; struct sk_buff *skb = dn_alloc_skb(sk, 200, allocation); if (!skb) return; cb = DN_SKB_CB(skb); msg = (struct nsp_conn_init_msg *)skb_put(skb,sizeof(*msg)); msg->msgflg = msgflg; msg->dstaddr = 0x0000; /* Remote Node will assign it*/ msg->srcaddr = scp->addrloc; msg->services = scp->services_loc; /* Requested flow control */ msg->info = scp->info_loc; /* Version Number */ msg->segsize = cpu_to_le16(scp->segsize_loc); /* Max segment size */ if (scp->peer.sdn_objnum) type = 0; skb_put(skb, dn_sockaddr2username(&scp->peer, skb_tail_pointer(skb), type)); skb_put(skb, dn_sockaddr2username(&scp->addr, skb_tail_pointer(skb), 2)); menuver = DN_MENUVER_ACC | DN_MENUVER_USR; if (scp->peer.sdn_flags & SDF_PROXY) menuver |= DN_MENUVER_PRX; if (scp->peer.sdn_flags & SDF_UICPROXY) menuver |= DN_MENUVER_UIC; *skb_put(skb, 1) = menuver; /* Menu Version */ aux = scp->accessdata.acc_userl; *skb_put(skb, 1) = aux; if (aux > 0) memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux); aux = scp->accessdata.acc_passl; *skb_put(skb, 1) = aux; if (aux > 0) memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux); aux = scp->accessdata.acc_accl; *skb_put(skb, 1) = aux; if (aux > 0) memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux); aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl); *skb_put(skb, 1) = aux; if (aux > 0) memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux); scp->persist = dn_nsp_persist(sk); scp->persist_fxn = dn_nsp_retrans_conninit; cb->rt_flags = DN_RT_F_RQR; dn_nsp_send(skb); }
static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); struct dn_skb_cb *cb = DN_SKB_CB(skb); unsigned short reason; if (skb->len < 2) goto out; reason = le16_to_cpu(*(__le16 *)skb->data); skb_pull(skb, 2); scp->discdata_in.opt_status = cpu_to_le16(reason); scp->discdata_in.opt_optl = 0; memset(scp->discdata_in.opt_data, 0, 16); if (skb->len > 0) { u16 dlen = *skb->data; if ((dlen <= 16) && (dlen <= skb->len)) { scp->discdata_in.opt_optl = cpu_to_le16(dlen); skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen); } } scp->addrrem = cb->src_port; sk->sk_state = TCP_CLOSE; switch (scp->state) { case DN_CI: case DN_CD: scp->state = DN_RJ; sk->sk_err = ECONNREFUSED; break; case DN_RUN: sk->sk_shutdown |= SHUTDOWN_MASK; scp->state = DN_DN; break; case DN_DI: scp->state = DN_DIC; break; } if (!sock_flag(sk, SOCK_DEAD)) { if (sk->sk_socket->state != SS_UNCONNECTED) sk->sk_socket->state = SS_DISCONNECTING; sk->sk_state_change(sk); } /* * It appears that its possible for remote machines to send disc * init messages with no port identifier if we are in the CI and * possibly also the CD state. Obviously we shouldn't reply with * a message if we don't know what the end point is. */ if (scp->addrrem) { dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC); } scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); out: kfree_skb(skb); }