1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * 4 * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 5 */ 6 #include <linux/errno.h> 7 #include <linux/types.h> 8 #include <linux/socket.h> 9 #include <linux/in.h> 10 #include <linux/kernel.h> 11 #include <linux/timer.h> 12 #include <linux/string.h> 13 #include <linux/sockios.h> 14 #include <linux/net.h> 15 #include <linux/slab.h> 16 #include <net/ax25.h> 17 #include <linux/inet.h> 18 #include <linux/netdevice.h> 19 #include <linux/skbuff.h> 20 #include <net/sock.h> 21 #include <net/tcp_states.h> 22 #include <linux/uaccess.h> 23 #include <linux/fcntl.h> 24 #include <linux/mm.h> 25 #include <linux/interrupt.h> 26 #include <net/netrom.h> 27 28 /* 29 * This routine purges all of the queues of frames. 30 */ 31 void nr_clear_queues(struct sock *sk) 32 { 33 struct nr_sock *nr = nr_sk(sk); 34 35 skb_queue_purge(&sk->sk_write_queue); 36 skb_queue_purge(&nr->ack_queue); 37 skb_queue_purge(&nr->reseq_queue); 38 skb_queue_purge(&nr->frag_queue); 39 } 40 41 /* 42 * This routine purges the input queue of those frames that have been 43 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the 44 * SDL diagram. 45 */ 46 void nr_frames_acked(struct sock *sk, unsigned short nr) 47 { 48 struct nr_sock *nrom = nr_sk(sk); 49 struct sk_buff *skb; 50 51 /* 52 * Remove all the ack-ed frames from the ack queue. 53 */ 54 if (nrom->va != nr) { 55 while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) { 56 skb = skb_dequeue(&nrom->ack_queue); 57 kfree_skb(skb); 58 nrom->va = (nrom->va + 1) % NR_MODULUS; 59 } 60 } 61 } 62 63 /* 64 * Requeue all the un-ack-ed frames on the output queue to be picked 65 * up by nr_kick called from the timer. This arrangement handles the 66 * possibility of an empty output queue. 67 */ 68 void nr_requeue_frames(struct sock *sk) 69 { 70 struct sk_buff *skb, *skb_prev = NULL; 71 72 while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) { 73 if (skb_prev == NULL) 74 skb_queue_head(&sk->sk_write_queue, skb); 75 else 76 skb_append(skb_prev, skb, &sk->sk_write_queue); 77 skb_prev = skb; 78 } 79 } 80 81 /* 82 * Validate that the value of nr is between va and vs. Return true or 83 * false for testing. 84 */ 85 int nr_validate_nr(struct sock *sk, unsigned short nr) 86 { 87 struct nr_sock *nrom = nr_sk(sk); 88 unsigned short vc = nrom->va; 89 90 while (vc != nrom->vs) { 91 if (nr == vc) return 1; 92 vc = (vc + 1) % NR_MODULUS; 93 } 94 95 return nr == nrom->vs; 96 } 97 98 /* 99 * Check that ns is within the receive window. 100 */ 101 int nr_in_rx_window(struct sock *sk, unsigned short ns) 102 { 103 struct nr_sock *nr = nr_sk(sk); 104 unsigned short vc = nr->vr; 105 unsigned short vt = (nr->vl + nr->window) % NR_MODULUS; 106 107 while (vc != vt) { 108 if (ns == vc) return 1; 109 vc = (vc + 1) % NR_MODULUS; 110 } 111 112 return 0; 113 } 114 115 /* 116 * This routine is called when the HDLC layer internally generates a 117 * control frame. 118 */ 119 void nr_write_internal(struct sock *sk, int frametype) 120 { 121 struct nr_sock *nr = nr_sk(sk); 122 struct sk_buff *skb; 123 unsigned char *dptr; 124 int len, timeout; 125 126 len = NR_TRANSPORT_LEN; 127 128 switch (frametype & 0x0F) { 129 case NR_CONNREQ: 130 len += 17; 131 break; 132 case NR_CONNACK: 133 len += (nr->bpqext) ? 2 : 1; 134 break; 135 case NR_DISCREQ: 136 case NR_DISCACK: 137 case NR_INFOACK: 138 break; 139 default: 140 printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); 141 return; 142 } 143 144 skb = alloc_skb(NR_NETWORK_LEN + len, GFP_ATOMIC); 145 if (!skb) 146 return; 147 148 /* 149 * Space for AX.25 and NET/ROM network header 150 */ 151 skb_reserve(skb, NR_NETWORK_LEN); 152 153 dptr = skb_put(skb, len); 154 155 switch (frametype & 0x0F) { 156 case NR_CONNREQ: 157 timeout = nr->t1 / HZ; 158 *dptr++ = nr->my_index; 159 *dptr++ = nr->my_id; 160 *dptr++ = 0; 161 *dptr++ = 0; 162 *dptr++ = frametype; 163 *dptr++ = nr->window; 164 memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN); 165 dptr[6] &= ~AX25_CBIT; 166 dptr[6] &= ~AX25_EBIT; 167 dptr[6] |= AX25_SSSID_SPARE; 168 dptr += AX25_ADDR_LEN; 169 memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); 170 dptr[6] &= ~AX25_CBIT; 171 dptr[6] &= ~AX25_EBIT; 172 dptr[6] |= AX25_SSSID_SPARE; 173 dptr += AX25_ADDR_LEN; 174 *dptr++ = timeout % 256; 175 *dptr++ = timeout / 256; 176 break; 177 178 case NR_CONNACK: 179 *dptr++ = nr->your_index; 180 *dptr++ = nr->your_id; 181 *dptr++ = nr->my_index; 182 *dptr++ = nr->my_id; 183 *dptr++ = frametype; 184 *dptr++ = nr->window; 185 if (nr->bpqext) 186 *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); 187 break; 188 189 case NR_DISCREQ: 190 case NR_DISCACK: 191 *dptr++ = nr->your_index; 192 *dptr++ = nr->your_id; 193 *dptr++ = 0; 194 *dptr++ = 0; 195 *dptr++ = frametype; 196 break; 197 198 case NR_INFOACK: 199 *dptr++ = nr->your_index; 200 *dptr++ = nr->your_id; 201 *dptr++ = 0; 202 *dptr++ = nr->vr; 203 *dptr++ = frametype; 204 break; 205 } 206 207 nr_transmit_buffer(sk, skb); 208 } 209 210 /* 211 * This routine is called to send an error reply. 212 */ 213 void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags) 214 { 215 struct sk_buff *skbn; 216 unsigned char *dptr; 217 int len; 218 219 len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; 220 221 if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) 222 return; 223 224 skb_reserve(skbn, 0); 225 226 dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); 227 228 skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN); 229 dptr[6] &= ~AX25_CBIT; 230 dptr[6] &= ~AX25_EBIT; 231 dptr[6] |= AX25_SSSID_SPARE; 232 dptr += AX25_ADDR_LEN; 233 234 skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN); 235 dptr[6] &= ~AX25_CBIT; 236 dptr[6] |= AX25_EBIT; 237 dptr[6] |= AX25_SSSID_SPARE; 238 dptr += AX25_ADDR_LEN; 239 240 *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); 241 242 if (mine) { 243 *dptr++ = 0; 244 *dptr++ = 0; 245 *dptr++ = skb->data[15]; 246 *dptr++ = skb->data[16]; 247 } else { 248 *dptr++ = skb->data[15]; 249 *dptr++ = skb->data[16]; 250 *dptr++ = 0; 251 *dptr++ = 0; 252 } 253 254 *dptr++ = cmdflags; 255 *dptr++ = 0; 256 257 if (!nr_route_frame(skbn, NULL)) 258 kfree_skb(skbn); 259 } 260 261 void nr_disconnect(struct sock *sk, int reason) 262 { 263 nr_stop_t1timer(sk); 264 nr_stop_t2timer(sk); 265 nr_stop_t4timer(sk); 266 nr_stop_idletimer(sk); 267 268 nr_clear_queues(sk); 269 270 nr_sk(sk)->state = NR_STATE_0; 271 272 sk->sk_state = TCP_CLOSE; 273 sk->sk_err = reason; 274 sk->sk_shutdown |= SEND_SHUTDOWN; 275 276 if (!sock_flag(sk, SOCK_DEAD)) { 277 sk->sk_state_change(sk); 278 sock_set_flag(sk, SOCK_DEAD); 279 } 280 } 281
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.