Commit 35c58418 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-x25-netdev-event-handling'

Martin Schiller says:

====================
net/x25: netdev event handling
====================

Link: https://lore.kernel.org/r/20201126063557.1283-1-ms@dev.tdt.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents f5d709ff 139d6eb1
Loading
Loading
Loading
Loading
+81 −1
Original line number Diff line number Diff line
@@ -418,14 +418,94 @@ int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
	return used;
}

/* Handle device status changes. */
static int lapb_device_event(struct notifier_block *this, unsigned long event,
			     void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct lapb_cb *lapb;

	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

	if (dev->type != ARPHRD_X25)
		return NOTIFY_DONE;

	lapb = lapb_devtostruct(dev);
	if (!lapb)
		return NOTIFY_DONE;

	switch (event) {
	case NETDEV_UP:
		lapb_dbg(0, "(%p) Interface up: %s\n", dev, dev->name);

		if (netif_carrier_ok(dev)) {
			lapb_dbg(0, "(%p): Carrier is already up: %s\n", dev,
				 dev->name);
			if (lapb->mode & LAPB_DCE) {
				lapb_start_t1timer(lapb);
			} else {
				if (lapb->state == LAPB_STATE_0) {
					lapb->state = LAPB_STATE_1;
					lapb_establish_data_link(lapb);
				}
			}
		}
		break;
	case NETDEV_GOING_DOWN:
		if (netif_carrier_ok(dev))
			lapb_disconnect_request(dev);
		break;
	case NETDEV_DOWN:
		lapb_dbg(0, "(%p) Interface down: %s\n", dev, dev->name);
		lapb_dbg(0, "(%p) S%d -> S0\n", dev, lapb->state);
		lapb_clear_queues(lapb);
		lapb->state = LAPB_STATE_0;
		lapb->n2count   = 0;
		lapb_stop_t1timer(lapb);
		lapb_stop_t2timer(lapb);
		break;
	case NETDEV_CHANGE:
		if (netif_carrier_ok(dev)) {
			lapb_dbg(0, "(%p): Carrier detected: %s\n", dev,
				 dev->name);
			if (lapb->mode & LAPB_DCE) {
				lapb_start_t1timer(lapb);
			} else {
				if (lapb->state == LAPB_STATE_0) {
					lapb->state = LAPB_STATE_1;
					lapb_establish_data_link(lapb);
				}
			}
		} else {
			lapb_dbg(0, "(%p) Carrier lost: %s\n", dev, dev->name);
			lapb_dbg(0, "(%p) S%d -> S0\n", dev, lapb->state);
			lapb_clear_queues(lapb);
			lapb->state = LAPB_STATE_0;
			lapb->n2count   = 0;
			lapb_stop_t1timer(lapb);
			lapb_stop_t2timer(lapb);
		}
		break;
	}

	return NOTIFY_DONE;
}

static struct notifier_block lapb_dev_notifier = {
	.notifier_call = lapb_device_event,
};

static int __init lapb_init(void)
{
	return 0;
	return register_netdevice_notifier(&lapb_dev_notifier);
}

static void __exit lapb_exit(void)
{
	WARN_ON(!list_empty(&lapb_list));

	unregister_netdevice_notifier(&lapb_dev_notifier);
}

MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
+9 −2
Original line number Diff line number Diff line
@@ -85,11 +85,18 @@ static void lapb_t1timer_expiry(struct timer_list *t)
	switch (lapb->state) {

		/*
		 *	If we are a DCE, keep going DM .. DM .. DM
		 *	If we are a DCE, send DM up to N2 times, then switch to
		 *	STATE_1 and send SABM(E).
		 */
		case LAPB_STATE_0:
			if (lapb->mode & LAPB_DCE)
			if (lapb->mode & LAPB_DCE &&
			    lapb->n2count != lapb->n2) {
				lapb->n2count++;
				lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
			} else {
				lapb->state = LAPB_STATE_1;
				lapb_establish_data_link(lapb);
			}
			break;

		/*
+16 −22
Original line number Diff line number Diff line
@@ -199,22 +199,6 @@ static void x25_remove_socket(struct sock *sk)
	write_unlock_bh(&x25_list_lock);
}

/*
 *	Kill all bound sockets on a dropped device.
 */
static void x25_kill_by_device(struct net_device *dev)
{
	struct sock *s;

	write_lock_bh(&x25_list_lock);

	sk_for_each(s, &x25_list)
		if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
			x25_disconnect(s, ENETUNREACH, 0, 0);

	write_unlock_bh(&x25_list_lock);
}

/*
 *	Handle device status changes.
 */
@@ -233,21 +217,31 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
#endif
	 ) {
		switch (event) {
		case NETDEV_UP:
		case NETDEV_REGISTER:
		case NETDEV_POST_TYPE_CHANGE:
			x25_link_device_up(dev);
			break;
		case NETDEV_GOING_DOWN:
		case NETDEV_DOWN:
			nb = x25_get_neigh(dev);
			if (nb) {
				x25_terminate_link(nb);
				x25_link_terminated(nb);
				x25_neigh_put(nb);
			}
			break;
		case NETDEV_DOWN:
			x25_kill_by_device(dev);
			x25_route_device_down(dev);
			break;
		case NETDEV_PRE_TYPE_CHANGE:
		case NETDEV_UNREGISTER:
			x25_link_device_down(dev);
			break;
		case NETDEV_CHANGE:
			if (!netif_carrier_ok(dev)) {
				nb = x25_get_neigh(dev);
				if (nb) {
					x25_link_terminated(nb);
					x25_neigh_put(nb);
				}
			}
			break;
		}
	}

+36 −11
Original line number Diff line number Diff line
@@ -74,16 +74,43 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,

	switch (frametype) {
	case X25_RESTART_REQUEST:
		switch (nb->state) {
		case X25_LINK_STATE_2:
			confirm = !x25_t20timer_pending(nb);
			x25_stop_t20timer(nb);
			nb->state = X25_LINK_STATE_3;
			if (confirm)
				x25_transmit_restart_confirmation(nb);
			break;
		case X25_LINK_STATE_3:
			/* clear existing virtual calls */
			x25_kill_by_neigh(nb);

			x25_transmit_restart_confirmation(nb);
			break;
		}
		break;

	case X25_RESTART_CONFIRMATION:
		switch (nb->state) {
		case X25_LINK_STATE_2:
			if (x25_t20timer_pending(nb)) {
				x25_stop_t20timer(nb);
				nb->state = X25_LINK_STATE_3;
			} else {
				x25_transmit_restart_request(nb);
				x25_start_t20timer(nb);
			}
			break;
		case X25_LINK_STATE_3:
			/* clear existing virtual calls */
			x25_kill_by_neigh(nb);

			x25_transmit_restart_request(nb);
			nb->state = X25_LINK_STATE_2;
			x25_start_t20timer(nb);
			break;
		}
		break;

	case X25_DIAGNOSTIC:
@@ -214,8 +241,6 @@ void x25_link_established(struct x25_neigh *nb)
{
	switch (nb->state) {
	case X25_LINK_STATE_0:
		nb->state = X25_LINK_STATE_2;
		break;
	case X25_LINK_STATE_1:
		x25_transmit_restart_request(nb);
		nb->state = X25_LINK_STATE_2;
@@ -232,6 +257,9 @@ void x25_link_established(struct x25_neigh *nb)
void x25_link_terminated(struct x25_neigh *nb)
{
	nb->state = X25_LINK_STATE_0;
	skb_queue_purge(&nb->queue);
	x25_stop_t20timer(nb);

	/* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
	x25_kill_by_neigh(nb);
}
@@ -277,9 +305,6 @@ void x25_link_device_up(struct net_device *dev)
 */
static void __x25_remove_neigh(struct x25_neigh *nb)
{
	skb_queue_purge(&nb->queue);
	x25_stop_t20timer(nb);

	if (nb->node.next) {
		list_del(&nb->node);
		x25_neigh_put(nb);
+0 −3
Original line number Diff line number Diff line
@@ -115,9 +115,6 @@ void x25_route_device_down(struct net_device *dev)
			__x25_remove_route(rt);
	}
	write_unlock_bh(&x25_route_list_lock);

	/* Remove any related forwarding */
	x25_clear_forward_by_dev(dev);
}

/*