Message ID | 20200708043754.46554-1-xie.he.0141@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | David Miller |
Headers | show |
Series | drivers/net/wan/x25_asy: Fix to make it work | expand |
From: Xie He <xie.he.0141@gmail.com> Date: Tue, 7 Jul 2020 21:37:54 -0700 > This driver is not working because of problems of its receiving code. > This patch fixes it to make it work. > > When the driver receives an LAPB frame, it should first pass the frame > to the LAPB module to process. After processing, the LAPB module passes > the data (the packet) back to the driver, the driver should then add a > one-byte pseudo header and pass the data to upper layers. > > The changes to the "x25_asy_bump" function and the > "x25_asy_data_indication" function are to correctly implement this > procedure. > > Also, the "x25_asy_unesc" function ignores any frame that is shorter > than 3 bytes. However the shortest frames are 2-byte long. So we need > to change it to allow 2-byte frames to pass. > > Signed-off-by: Xie He <xie.he.0141@gmail.com> Something's not right, because I find it hard to believe this has been so fundamentally broken for such a long period of time. Maybe the drivers all handle things differently, and whilst your change might fix some drivers, it will break others. I'm not applying this until this situation is better understood.
From: David Miller <davem@davemloft.net> Date: Wed, Jul 8, 2020 at 10:13 AM -0700 > Something's not right, because I find it hard to believe this has been > so fundamentally broken for such a long period of time. > > Maybe the drivers all handle things differently, and whilst your change > might fix some drivers, it will break others. > > I'm not applying this until this situation is better understood. Yes, it was hard for me to believe, too. At first when I tried this driver, it was silently not able to establish LAPB connections, I found that it was because it was ignoring 2-byte frames. I changed it to make 2-byte frames pass. Then I encountered kernel panic. I don't know how to solve it, so I looked at the way "lapbether" does things and changed this driver according to the "lapbether" driver. And it worked. The "lapbether" driver and this driver both use the "lapb" module to implement the LAPB protocol, so they should implement LAPB-related code in the same way. This patch only changes this driver and does not affect other drivers. I don't know how I can better explain this situation. Please tell me anything I can do to help. Thanks!
This email is a detailed explanation of how to test the LAPB drivers, just in case you have time to check. Thanks! This email has 4 parts. 1) How to set up "lapbether" links (for comparison) 2) How to set up "x25_asy" links 3) How to test using AF_X25 sockets 4) How to test using AF_PACKET sockets (for simpler debugging) You can compare the behavior of "lapbether" and "x25_asy". You can also compare the behavior of "x25_asy" before and after my change. For the C code in this email, I'm sorry that for brevity, I didn't include error checking. Declarations and statements are also mixed which doesn't conform to the style in the Linux kernel. I won't produce this kind of code when I am actually doing programming. If you have any issue using or understanding my code. Please feel free to ask me. Thanks! -------------------------------------------------------- 1) How to set up "lapbether" links First set up a virtual Ethernet link: sudo ip link add veth1 type veth peer name veth0 sudo ip link set veth0 up sudo ip link set veth1 up Then: sudo modprobe lapb sudo modprobe lapbether The lapbether driver will set up an LAPB interface for each Ethernet interface, named lapb0, lapb1, lapb2, ... Find the LAPB interfaces corresponding to veth0 and veth1, and use sudo ip link set lapbN up to bring them up. -------------------------------------------------------- 2) How to set up "x25_asy" links First: sudo modprobe lapb sudo modprobe x25_asy Then set up a virtual TTY link: socat -d -d pty,cfmakeraw pty,cfmakeraw & This will open a pair of PTY ports. (The "socat" program can be installed from package managers.) Then use a C program to set the line discipline for the two PTY ports: int ldisc = N_X25; int fd = open("path/to/pty", O_RDWR); ioctl(fd, TIOCSETD, &ldisc); close(fd); Then we'll get two network interfaces named x25asy0 and x25asy1. Then we do: sudo ip link set x25asyN up to bring them up. -------------------------------------------------------- 3) How to test using AF_X25 sockets Note that don't test a "lapbether" link and a "x25_asy" link at the same time using AF_X25 sockets. There would be a kernel panic because of bugs in the x25 module. I don't know how to fix this issue now but may be able to in the future. First: sudo modprobe x25 Then set up the routing table: sudo route -A x25 add 1/1 lapb1 or sudo route -A x25 add 1/1 x25asy0 Then in the server C program: int sockfd = socket(AF_X25, SOCK_SEQPACKET, 0); /* Bind local address */ struct sockaddr_x25 serv_addr = { .sx25_family = AF_X25, }; strcpy(serv_addr.sx25_addr.x25_addr, "111"); /* 111: server addr */ bind(sockfd, (struct sockaddr *)&serv_addr, sizeof serv_addr); /* Wait for connections */ listen(sockfd, 5); /* Accept connection */ struct sockaddr_x25 client_addr; socklen_t client_addr_len = sizeof client_addr; int connected_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len); char buffer[1000]; ssize_t length = recv(connected_sockfd, buffer, sizeof buffer, 0); close(connected_sockfd); close(sockfd); And in the client C program: int sockfd = socket(AF_X25, SOCK_SEQPACKET, 0); /* Bind local address */ struct sockaddr_x25 local_addr = { .sx25_family = AF_X25, }; strcpy(local_addr.sx25_addr.x25_addr, "777"); /* 777: local addr */ bind(sockfd, (struct sockaddr *)&local_addr, sizeof local_addr); /* Connect to the server */ struct sockaddr_x25 serv_addr = { .sx25_family = AF_X25, }; strcpy(serv_addr.sx25_addr.x25_addr, "111"); /* 111: server addr */ connect(sockfd, (struct sockaddr *)&serv_addr, sizeof serv_addr); send(sockfd, "data", 4, MSG_EOR); usleep(10000); /* Wait a while before closing */ close(sockfd); -------------------------------------------------------- 4) How to test using AF_PACKET sockets In the connected-side C program: int sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); /* Get interface index */ struct ifreq ifr; strcpy(ifr.ifr_name, "interface_name"); ioctl(sockfd, SIOCGIFINDEX, &ifr); int ifindex = ifr.ifr_ifindex; struct sockaddr_ll sender_addr; socklen_t sender_addr_len = sizeof sender_addr; char buffer[1500]; while (1) { ssize_t length = recvfrom(sockfd, buffer, sizeof buffer, 0, (struct sockaddr *)&sender_addr, &sender_addr_len); if (sender_addr.sll_ifindex != ifindex) continue; else if (buffer[0] == 0) printf("Data received.\n"); else if (buffer[0] == 1) printf("Connected by the other side.\n"); else if (buffer[0] == 2) { printf("Disconnected by the other side.\n"); break; } } close(sockfd); In the connecting-side C program: int sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); /* Get interface index */ struct ifreq ifr; strcpy(ifr.ifr_name, "interface_name"); ioctl(sockfd, SIOCGIFINDEX, &ifr); int ifindex = ifr.ifr_ifindex; struct sockaddr_ll addr = { .sll_family = AF_PACKET, .sll_ifindex = ifindex, }; /* Connect */ sendto(sockfd, "\x01", 1, 0, (struct sockaddr *)&addr, sizeof addr); /* Send data */ sendto(sockfd, "\x00" "data", 5, 0, (struct sockaddr *)&addr, sizeof addr); sleep(1); /* Wait a while before disconnecting */ /* Disconnect */ sendto(sockfd, "\x02", 1, 0, (struct sockaddr *)&addr, sizeof addr); close(sockfd);
On 7/7/20 9:37 PM, Xie He wrote: > This driver is not working because of problems of its receiving code. > This patch fixes it to make it work. > > When the driver receives an LAPB frame, it should first pass the frame > to the LAPB module to process. After processing, the LAPB module passes > the data (the packet) back to the driver, the driver should then add a > one-byte pseudo header and pass the data to upper layers. > > The changes to the "x25_asy_bump" function and the > "x25_asy_data_indication" function are to correctly implement this > procedure. > > Also, the "x25_asy_unesc" function ignores any frame that is shorter > than 3 bytes. However the shortest frames are 2-byte long. So we need > to change it to allow 2-byte frames to pass. > > Signed-off-by: Xie He <xie.he.0141@gmail.com> > --- > drivers/net/wan/x25_asy.c | 16 +++++++++------- > 1 file changed, 9 insertions(+), 7 deletions(-) > > diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c > index 69773d228ec1..3fd8938e591b 100644 > --- a/drivers/net/wan/x25_asy.c > +++ b/drivers/net/wan/x25_asy.c > @@ -183,7 +183,7 @@ static inline void x25_asy_unlock(struct x25_asy *sl) > netif_wake_queue(sl->dev); > } > > -/* Send one completely decapsulated IP datagram to the IP layer. */ > +/* Send an LAPB frame to the LAPB module to process. */ > > static void x25_asy_bump(struct x25_asy *sl) > { > @@ -195,13 +195,12 @@ static void x25_asy_bump(struct x25_asy *sl) > count = sl->rcount; > dev->stats.rx_bytes += count; > > - skb = dev_alloc_skb(count+1); > + skb = dev_alloc_skb(count); > if (skb == NULL) { > netdev_warn(sl->dev, "memory squeeze, dropping packet\n"); > dev->stats.rx_dropped++; > return; > } > - skb_push(skb, 1); /* LAPB internal control */ > skb_put_data(skb, sl->rbuff, count); > skb->protocol = x25_type_trans(skb, sl->dev); > err = lapb_data_received(skb->dev, skb); > @@ -209,7 +208,6 @@ static void x25_asy_bump(struct x25_asy *sl) > kfree_skb(skb); > printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); > } else { > - netif_rx(skb); > dev->stats.rx_packets++; > } > } > @@ -356,12 +354,16 @@ static netdev_tx_t x25_asy_xmit(struct sk_buff *skb, > */ > > /* > - * Called when I frame data arrives. We did the work above - throw it > - * at the net layer. > + * Called when I frame data arrives. We add a pseudo header for upper > + * layers and pass it to upper layers. > */ > > static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) > { It is not clear to me what guarantee we have to have one byte of headroom in the skb at this point. You might add to be safe : (as done in lapbeth_data_indication(), but after the skb_push() which seems wrong) if (skb_cow(skb, 1)) { kfree_skb(skb); /* This line I am not sure, but looking at * lapb_data_indication() this might be needed. */ return NET_RX_DROP; } > + skb_push(skb, 1); > + skb->data[0] = X25_IFACE_DATA; > + skb->protocol = x25_type_trans(skb, dev); > + > return netif_rx(skb); > } > > @@ -657,7 +659,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) > switch (s) { > case X25_END: > if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && > - sl->rcount > 2) > + sl->rcount >= 2) > x25_asy_bump(sl); > clear_bit(SLF_ESCAPE, &sl->flags); > sl->rcount = 0; >
On Mon, Jul 13, 2020 at 2:21 PM Eric Dumazet <eric.dumazet@gmail.com> wrote: > > It is not clear to me what guarantee we have to have one byte of headroom in the skb > at this point. > > You might add to be safe : (as done in lapbeth_data_indication(), but after the skb_push() which seems wrong) > > if (skb_cow(skb, 1)) { > kfree_skb(skb); /* This line I am not sure, but looking at > * lapb_data_indication() this might be needed. > */ > return NET_RX_DROP; > } > Thank you for your review, Eric! The function "x25_asy_data_indication" is called by the "lapb" module (net/lapb/). Before the "lapb" module calls this function, it has removed from the skb an LAPB header which is at least 2 bytes (in the function "lapb_decode"). So I thought there would always be a headroom of one byte at this point. But yes, it is always safer to add "skb_cow" at this point, so that it is clearer the code would not crash here. I'll add it in the second version of this patch. Thank you for your suggestion! And yes, I agree that in "lapbeth_data_indication", the order of "skb_push" and "skb_cow" is probably wrong. Let us submit another patch to fix this problem!
On 2020-07-08 21:04, Xie He wrote: > From: David Miller <davem@davemloft.net> > Date: Wed, Jul 8, 2020 at 10:13 AM -0700 >> Something's not right, because I find it hard to believe this has been >> so fundamentally broken for such a long period of time. >> >> Maybe the drivers all handle things differently, and whilst your >> change >> might fix some drivers, it will break others. >> >> I'm not applying this until this situation is better understood. > > Yes, it was hard for me to believe, too. > > At first when I tried this driver, it was silently not able to > establish > LAPB connections, I found that it was because it was ignoring > 2-byte frames. I changed it to make 2-byte frames pass. Then I > encountered kernel panic. I don't know how to solve it, so I looked > at the way "lapbether" does things and changed this driver according > to the "lapbether" driver. And it worked. > > The "lapbether" driver and this driver both use the "lapb" module to > implement the LAPB protocol, so they should implement LAPB-related > code in the same way. > > This patch only changes this driver and does not affect other drivers. > > I don't know how I can better explain this situation. Please tell me > anything I can do to help. Thanks! It really seems very strange that this driver seems to contain such fundamental errors. I have never used it. But the explanations and fixes look plausible to me.
On Tue, Jul 14, 2020 at 1:07 AM -0700 Martin Schiller <ms@dev.tdt.de> wrote: > > It really seems very strange that this driver seems to contain such > fundamental errors. I have never used it. > > But the explanations and fixes look plausible to me. Thank you for reviewing this patch, Martin! Yes, this situation is very strange. I guess not so many people have tried this driver. The comment of this driver says it doesn't implement the checksum, which is required by the international standard. So I guess it can't be used for practical purposes anyway. I tried this driver because I was personally interested in X.25.
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 69773d228ec1..3fd8938e591b 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -183,7 +183,7 @@ static inline void x25_asy_unlock(struct x25_asy *sl) netif_wake_queue(sl->dev); } -/* Send one completely decapsulated IP datagram to the IP layer. */ +/* Send an LAPB frame to the LAPB module to process. */ static void x25_asy_bump(struct x25_asy *sl) { @@ -195,13 +195,12 @@ static void x25_asy_bump(struct x25_asy *sl) count = sl->rcount; dev->stats.rx_bytes += count; - skb = dev_alloc_skb(count+1); + skb = dev_alloc_skb(count); if (skb == NULL) { netdev_warn(sl->dev, "memory squeeze, dropping packet\n"); dev->stats.rx_dropped++; return; } - skb_push(skb, 1); /* LAPB internal control */ skb_put_data(skb, sl->rbuff, count); skb->protocol = x25_type_trans(skb, sl->dev); err = lapb_data_received(skb->dev, skb); @@ -209,7 +208,6 @@ static void x25_asy_bump(struct x25_asy *sl) kfree_skb(skb); printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); } else { - netif_rx(skb); dev->stats.rx_packets++; } } @@ -356,12 +354,16 @@ static netdev_tx_t x25_asy_xmit(struct sk_buff *skb, */ /* - * Called when I frame data arrives. We did the work above - throw it - * at the net layer. + * Called when I frame data arrives. We add a pseudo header for upper + * layers and pass it to upper layers. */ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) { + skb_push(skb, 1); + skb->data[0] = X25_IFACE_DATA; + skb->protocol = x25_type_trans(skb, dev); + return netif_rx(skb); } @@ -657,7 +659,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) switch (s) { case X25_END: if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && - sl->rcount > 2) + sl->rcount >= 2) x25_asy_bump(sl); clear_bit(SLF_ESCAPE, &sl->flags); sl->rcount = 0;
This driver is not working because of problems of its receiving code. This patch fixes it to make it work. When the driver receives an LAPB frame, it should first pass the frame to the LAPB module to process. After processing, the LAPB module passes the data (the packet) back to the driver, the driver should then add a one-byte pseudo header and pass the data to upper layers. The changes to the "x25_asy_bump" function and the "x25_asy_data_indication" function are to correctly implement this procedure. Also, the "x25_asy_unesc" function ignores any frame that is shorter than 3 bytes. However the shortest frames are 2-byte long. So we need to change it to allow 2-byte frames to pass. Signed-off-by: Xie He <xie.he.0141@gmail.com> --- drivers/net/wan/x25_asy.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)