diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 493 |
1 files changed, 170 insertions, 323 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 0cc3d9015c5d..69cd9bf3f561 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -75,20 +75,6 @@ static const char *link_unk_evt = "Unknown link event "; | |||
75 | */ | 75 | */ |
76 | #define START_CHANGEOVER 100000u | 76 | #define START_CHANGEOVER 100000u |
77 | 77 | ||
78 | /** | ||
79 | * struct tipc_link_name - deconstructed link name | ||
80 | * @addr_local: network address of node at this end | ||
81 | * @if_local: name of interface at this end | ||
82 | * @addr_peer: network address of node at far end | ||
83 | * @if_peer: name of interface at far end | ||
84 | */ | ||
85 | struct tipc_link_name { | ||
86 | u32 addr_local; | ||
87 | char if_local[TIPC_MAX_IF_NAME]; | ||
88 | u32 addr_peer; | ||
89 | char if_peer[TIPC_MAX_IF_NAME]; | ||
90 | }; | ||
91 | |||
92 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, | 78 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, |
93 | struct sk_buff *buf); | 79 | struct sk_buff *buf); |
94 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); | 80 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); |
@@ -97,8 +83,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr, | |||
97 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); | 83 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); |
98 | static int link_send_sections_long(struct tipc_port *sender, | 84 | static int link_send_sections_long(struct tipc_port *sender, |
99 | struct iovec const *msg_sect, | 85 | struct iovec const *msg_sect, |
100 | u32 num_sect, unsigned int total_len, | 86 | unsigned int len, u32 destnode); |
101 | u32 destnode); | ||
102 | static void link_state_event(struct tipc_link *l_ptr, u32 event); | 87 | static void link_state_event(struct tipc_link *l_ptr, u32 event); |
103 | static void link_reset_statistics(struct tipc_link *l_ptr); | 88 | static void link_reset_statistics(struct tipc_link *l_ptr); |
104 | static void link_print(struct tipc_link *l_ptr, const char *str); | 89 | static void link_print(struct tipc_link *l_ptr, const char *str); |
@@ -161,72 +146,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr) | |||
161 | } | 146 | } |
162 | 147 | ||
163 | /** | 148 | /** |
164 | * link_name_validate - validate & (optionally) deconstruct tipc_link name | ||
165 | * @name: ptr to link name string | ||
166 | * @name_parts: ptr to area for link name components (or NULL if not needed) | ||
167 | * | ||
168 | * Returns 1 if link name is valid, otherwise 0. | ||
169 | */ | ||
170 | static int link_name_validate(const char *name, | ||
171 | struct tipc_link_name *name_parts) | ||
172 | { | ||
173 | char name_copy[TIPC_MAX_LINK_NAME]; | ||
174 | char *addr_local; | ||
175 | char *if_local; | ||
176 | char *addr_peer; | ||
177 | char *if_peer; | ||
178 | char dummy; | ||
179 | u32 z_local, c_local, n_local; | ||
180 | u32 z_peer, c_peer, n_peer; | ||
181 | u32 if_local_len; | ||
182 | u32 if_peer_len; | ||
183 | |||
184 | /* copy link name & ensure length is OK */ | ||
185 | name_copy[TIPC_MAX_LINK_NAME - 1] = 0; | ||
186 | /* need above in case non-Posix strncpy() doesn't pad with nulls */ | ||
187 | strncpy(name_copy, name, TIPC_MAX_LINK_NAME); | ||
188 | if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0) | ||
189 | return 0; | ||
190 | |||
191 | /* ensure all component parts of link name are present */ | ||
192 | addr_local = name_copy; | ||
193 | if_local = strchr(addr_local, ':'); | ||
194 | if (if_local == NULL) | ||
195 | return 0; | ||
196 | *(if_local++) = 0; | ||
197 | addr_peer = strchr(if_local, '-'); | ||
198 | if (addr_peer == NULL) | ||
199 | return 0; | ||
200 | *(addr_peer++) = 0; | ||
201 | if_local_len = addr_peer - if_local; | ||
202 | if_peer = strchr(addr_peer, ':'); | ||
203 | if (if_peer == NULL) | ||
204 | return 0; | ||
205 | *(if_peer++) = 0; | ||
206 | if_peer_len = strlen(if_peer) + 1; | ||
207 | |||
208 | /* validate component parts of link name */ | ||
209 | if ((sscanf(addr_local, "%u.%u.%u%c", | ||
210 | &z_local, &c_local, &n_local, &dummy) != 3) || | ||
211 | (sscanf(addr_peer, "%u.%u.%u%c", | ||
212 | &z_peer, &c_peer, &n_peer, &dummy) != 3) || | ||
213 | (z_local > 255) || (c_local > 4095) || (n_local > 4095) || | ||
214 | (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) || | ||
215 | (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) || | ||
216 | (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME)) | ||
217 | return 0; | ||
218 | |||
219 | /* return link name components, if necessary */ | ||
220 | if (name_parts) { | ||
221 | name_parts->addr_local = tipc_addr(z_local, c_local, n_local); | ||
222 | strcpy(name_parts->if_local, if_local); | ||
223 | name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer); | ||
224 | strcpy(name_parts->if_peer, if_peer); | ||
225 | } | ||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * link_timeout - handle expiration of link timer | 149 | * link_timeout - handle expiration of link timer |
231 | * @l_ptr: pointer to link | 150 | * @l_ptr: pointer to link |
232 | * | 151 | * |
@@ -485,15 +404,9 @@ static void link_release_outqueue(struct tipc_link *l_ptr) | |||
485 | */ | 404 | */ |
486 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) | 405 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) |
487 | { | 406 | { |
488 | struct sk_buff *buf = l_ptr->defragm_buf; | 407 | kfree_skb(l_ptr->reasm_head); |
489 | struct sk_buff *next; | 408 | l_ptr->reasm_head = NULL; |
490 | 409 | l_ptr->reasm_tail = NULL; | |
491 | while (buf) { | ||
492 | next = buf->next; | ||
493 | kfree_skb(buf); | ||
494 | buf = next; | ||
495 | } | ||
496 | l_ptr->defragm_buf = NULL; | ||
497 | } | 410 | } |
498 | 411 | ||
499 | /** | 412 | /** |
@@ -1065,8 +978,7 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
1065 | */ | 978 | */ |
1066 | int tipc_link_send_sections_fast(struct tipc_port *sender, | 979 | int tipc_link_send_sections_fast(struct tipc_port *sender, |
1067 | struct iovec const *msg_sect, | 980 | struct iovec const *msg_sect, |
1068 | const u32 num_sect, unsigned int total_len, | 981 | unsigned int len, u32 destaddr) |
1069 | u32 destaddr) | ||
1070 | { | 982 | { |
1071 | struct tipc_msg *hdr = &sender->phdr; | 983 | struct tipc_msg *hdr = &sender->phdr; |
1072 | struct tipc_link *l_ptr; | 984 | struct tipc_link *l_ptr; |
@@ -1080,8 +992,7 @@ again: | |||
1080 | * Try building message using port's max_pkt hint. | 992 | * Try building message using port's max_pkt hint. |
1081 | * (Must not hold any locks while building message.) | 993 | * (Must not hold any locks while building message.) |
1082 | */ | 994 | */ |
1083 | res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, | 995 | res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf); |
1084 | sender->max_pkt, &buf); | ||
1085 | /* Exit if build request was invalid */ | 996 | /* Exit if build request was invalid */ |
1086 | if (unlikely(res < 0)) | 997 | if (unlikely(res < 0)) |
1087 | return res; | 998 | return res; |
@@ -1121,8 +1032,7 @@ exit: | |||
1121 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) | 1032 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) |
1122 | goto again; | 1033 | goto again; |
1123 | 1034 | ||
1124 | return link_send_sections_long(sender, msg_sect, | 1035 | return link_send_sections_long(sender, msg_sect, len, |
1125 | num_sect, total_len, | ||
1126 | destaddr); | 1036 | destaddr); |
1127 | } | 1037 | } |
1128 | tipc_node_unlock(node); | 1038 | tipc_node_unlock(node); |
@@ -1133,8 +1043,8 @@ exit: | |||
1133 | if (buf) | 1043 | if (buf) |
1134 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); | 1044 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); |
1135 | if (res >= 0) | 1045 | if (res >= 0) |
1136 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | 1046 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
1137 | total_len, TIPC_ERR_NO_NODE); | 1047 | len, TIPC_ERR_NO_NODE); |
1138 | return res; | 1048 | return res; |
1139 | } | 1049 | } |
1140 | 1050 | ||
@@ -1154,18 +1064,17 @@ exit: | |||
1154 | */ | 1064 | */ |
1155 | static int link_send_sections_long(struct tipc_port *sender, | 1065 | static int link_send_sections_long(struct tipc_port *sender, |
1156 | struct iovec const *msg_sect, | 1066 | struct iovec const *msg_sect, |
1157 | u32 num_sect, unsigned int total_len, | 1067 | unsigned int len, u32 destaddr) |
1158 | u32 destaddr) | ||
1159 | { | 1068 | { |
1160 | struct tipc_link *l_ptr; | 1069 | struct tipc_link *l_ptr; |
1161 | struct tipc_node *node; | 1070 | struct tipc_node *node; |
1162 | struct tipc_msg *hdr = &sender->phdr; | 1071 | struct tipc_msg *hdr = &sender->phdr; |
1163 | u32 dsz = total_len; | 1072 | u32 dsz = len; |
1164 | u32 max_pkt, fragm_sz, rest; | 1073 | u32 max_pkt, fragm_sz, rest; |
1165 | struct tipc_msg fragm_hdr; | 1074 | struct tipc_msg fragm_hdr; |
1166 | struct sk_buff *buf, *buf_chain, *prev; | 1075 | struct sk_buff *buf, *buf_chain, *prev; |
1167 | u32 fragm_crs, fragm_rest, hsz, sect_rest; | 1076 | u32 fragm_crs, fragm_rest, hsz, sect_rest; |
1168 | const unchar *sect_crs; | 1077 | const unchar __user *sect_crs; |
1169 | int curr_sect; | 1078 | int curr_sect; |
1170 | u32 fragm_no; | 1079 | u32 fragm_no; |
1171 | int res = 0; | 1080 | int res = 0; |
@@ -1207,7 +1116,7 @@ again: | |||
1207 | 1116 | ||
1208 | if (!sect_rest) { | 1117 | if (!sect_rest) { |
1209 | sect_rest = msg_sect[++curr_sect].iov_len; | 1118 | sect_rest = msg_sect[++curr_sect].iov_len; |
1210 | sect_crs = (const unchar *)msg_sect[curr_sect].iov_base; | 1119 | sect_crs = msg_sect[curr_sect].iov_base; |
1211 | } | 1120 | } |
1212 | 1121 | ||
1213 | if (sect_rest < fragm_rest) | 1122 | if (sect_rest < fragm_rest) |
@@ -1283,8 +1192,8 @@ reject: | |||
1283 | buf = buf_chain->next; | 1192 | buf = buf_chain->next; |
1284 | kfree_skb(buf_chain); | 1193 | kfree_skb(buf_chain); |
1285 | } | 1194 | } |
1286 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | 1195 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
1287 | total_len, TIPC_ERR_NO_NODE); | 1196 | len, TIPC_ERR_NO_NODE); |
1288 | } | 1197 | } |
1289 | 1198 | ||
1290 | /* Append chain of fragments to send queue & send them */ | 1199 | /* Append chain of fragments to send queue & send them */ |
@@ -1592,15 +1501,15 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1592 | 1501 | ||
1593 | /* Ensure bearer is still enabled */ | 1502 | /* Ensure bearer is still enabled */ |
1594 | if (unlikely(!b_ptr->active)) | 1503 | if (unlikely(!b_ptr->active)) |
1595 | goto cont; | 1504 | goto discard; |
1596 | 1505 | ||
1597 | /* Ensure message is well-formed */ | 1506 | /* Ensure message is well-formed */ |
1598 | if (unlikely(!link_recv_buf_validate(buf))) | 1507 | if (unlikely(!link_recv_buf_validate(buf))) |
1599 | goto cont; | 1508 | goto discard; |
1600 | 1509 | ||
1601 | /* Ensure message data is a single contiguous unit */ | 1510 | /* Ensure message data is a single contiguous unit */ |
1602 | if (unlikely(skb_linearize(buf))) | 1511 | if (unlikely(skb_linearize(buf))) |
1603 | goto cont; | 1512 | goto discard; |
1604 | 1513 | ||
1605 | /* Handle arrival of a non-unicast link message */ | 1514 | /* Handle arrival of a non-unicast link message */ |
1606 | msg = buf_msg(buf); | 1515 | msg = buf_msg(buf); |
@@ -1616,20 +1525,18 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1616 | /* Discard unicast link messages destined for another node */ | 1525 | /* Discard unicast link messages destined for another node */ |
1617 | if (unlikely(!msg_short(msg) && | 1526 | if (unlikely(!msg_short(msg) && |
1618 | (msg_destnode(msg) != tipc_own_addr))) | 1527 | (msg_destnode(msg) != tipc_own_addr))) |
1619 | goto cont; | 1528 | goto discard; |
1620 | 1529 | ||
1621 | /* Locate neighboring node that sent message */ | 1530 | /* Locate neighboring node that sent message */ |
1622 | n_ptr = tipc_node_find(msg_prevnode(msg)); | 1531 | n_ptr = tipc_node_find(msg_prevnode(msg)); |
1623 | if (unlikely(!n_ptr)) | 1532 | if (unlikely(!n_ptr)) |
1624 | goto cont; | 1533 | goto discard; |
1625 | tipc_node_lock(n_ptr); | 1534 | tipc_node_lock(n_ptr); |
1626 | 1535 | ||
1627 | /* Locate unicast link endpoint that should handle message */ | 1536 | /* Locate unicast link endpoint that should handle message */ |
1628 | l_ptr = n_ptr->links[b_ptr->identity]; | 1537 | l_ptr = n_ptr->links[b_ptr->identity]; |
1629 | if (unlikely(!l_ptr)) { | 1538 | if (unlikely(!l_ptr)) |
1630 | tipc_node_unlock(n_ptr); | 1539 | goto unlock_discard; |
1631 | goto cont; | ||
1632 | } | ||
1633 | 1540 | ||
1634 | /* Verify that communication with node is currently allowed */ | 1541 | /* Verify that communication with node is currently allowed */ |
1635 | if ((n_ptr->block_setup & WAIT_PEER_DOWN) && | 1542 | if ((n_ptr->block_setup & WAIT_PEER_DOWN) && |
@@ -1639,10 +1546,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1639 | !msg_redundant_link(msg)) | 1546 | !msg_redundant_link(msg)) |
1640 | n_ptr->block_setup &= ~WAIT_PEER_DOWN; | 1547 | n_ptr->block_setup &= ~WAIT_PEER_DOWN; |
1641 | 1548 | ||
1642 | if (n_ptr->block_setup) { | 1549 | if (n_ptr->block_setup) |
1643 | tipc_node_unlock(n_ptr); | 1550 | goto unlock_discard; |
1644 | goto cont; | ||
1645 | } | ||
1646 | 1551 | ||
1647 | /* Validate message sequence number info */ | 1552 | /* Validate message sequence number info */ |
1648 | seq_no = msg_seqno(msg); | 1553 | seq_no = msg_seqno(msg); |
@@ -1678,98 +1583,100 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1678 | 1583 | ||
1679 | /* Now (finally!) process the incoming message */ | 1584 | /* Now (finally!) process the incoming message */ |
1680 | protocol_check: | 1585 | protocol_check: |
1681 | if (likely(link_working_working(l_ptr))) { | 1586 | if (unlikely(!link_working_working(l_ptr))) { |
1682 | if (likely(seq_no == mod(l_ptr->next_in_no))) { | 1587 | if (msg_user(msg) == LINK_PROTOCOL) { |
1683 | l_ptr->next_in_no++; | 1588 | link_recv_proto_msg(l_ptr, buf); |
1684 | if (unlikely(l_ptr->oldest_deferred_in)) | 1589 | head = link_insert_deferred_queue(l_ptr, head); |
1685 | head = link_insert_deferred_queue(l_ptr, | 1590 | tipc_node_unlock(n_ptr); |
1686 | head); | 1591 | continue; |
1687 | deliver: | 1592 | } |
1688 | if (likely(msg_isdata(msg))) { | 1593 | |
1689 | tipc_node_unlock(n_ptr); | 1594 | /* Traffic message. Conditionally activate link */ |
1690 | tipc_port_recv_msg(buf); | 1595 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); |
1691 | continue; | 1596 | |
1692 | } | 1597 | if (link_working_working(l_ptr)) { |
1693 | switch (msg_user(msg)) { | 1598 | /* Re-insert buffer in front of queue */ |
1694 | int ret; | 1599 | buf->next = head; |
1695 | case MSG_BUNDLER: | 1600 | head = buf; |
1696 | l_ptr->stats.recv_bundles++; | ||
1697 | l_ptr->stats.recv_bundled += | ||
1698 | msg_msgcnt(msg); | ||
1699 | tipc_node_unlock(n_ptr); | ||
1700 | tipc_link_recv_bundle(buf); | ||
1701 | continue; | ||
1702 | case NAME_DISTRIBUTOR: | ||
1703 | n_ptr->bclink.recv_permitted = true; | ||
1704 | tipc_node_unlock(n_ptr); | ||
1705 | tipc_named_recv(buf); | ||
1706 | continue; | ||
1707 | case BCAST_PROTOCOL: | ||
1708 | tipc_link_recv_sync(n_ptr, buf); | ||
1709 | tipc_node_unlock(n_ptr); | ||
1710 | continue; | ||
1711 | case CONN_MANAGER: | ||
1712 | tipc_node_unlock(n_ptr); | ||
1713 | tipc_port_recv_proto_msg(buf); | ||
1714 | continue; | ||
1715 | case MSG_FRAGMENTER: | ||
1716 | l_ptr->stats.recv_fragments++; | ||
1717 | ret = tipc_link_recv_fragment( | ||
1718 | &l_ptr->defragm_buf, | ||
1719 | &buf, &msg); | ||
1720 | if (ret == 1) { | ||
1721 | l_ptr->stats.recv_fragmented++; | ||
1722 | goto deliver; | ||
1723 | } | ||
1724 | if (ret == -1) | ||
1725 | l_ptr->next_in_no--; | ||
1726 | break; | ||
1727 | case CHANGEOVER_PROTOCOL: | ||
1728 | type = msg_type(msg); | ||
1729 | if (link_recv_changeover_msg(&l_ptr, | ||
1730 | &buf)) { | ||
1731 | msg = buf_msg(buf); | ||
1732 | seq_no = msg_seqno(msg); | ||
1733 | if (type == ORIGINAL_MSG) | ||
1734 | goto deliver; | ||
1735 | goto protocol_check; | ||
1736 | } | ||
1737 | break; | ||
1738 | default: | ||
1739 | kfree_skb(buf); | ||
1740 | buf = NULL; | ||
1741 | break; | ||
1742 | } | ||
1743 | tipc_node_unlock(n_ptr); | 1601 | tipc_node_unlock(n_ptr); |
1744 | tipc_net_route_msg(buf); | ||
1745 | continue; | 1602 | continue; |
1746 | } | 1603 | } |
1604 | goto unlock_discard; | ||
1605 | } | ||
1606 | |||
1607 | /* Link is now in state WORKING_WORKING */ | ||
1608 | if (unlikely(seq_no != mod(l_ptr->next_in_no))) { | ||
1747 | link_handle_out_of_seq_msg(l_ptr, buf); | 1609 | link_handle_out_of_seq_msg(l_ptr, buf); |
1748 | head = link_insert_deferred_queue(l_ptr, head); | 1610 | head = link_insert_deferred_queue(l_ptr, head); |
1749 | tipc_node_unlock(n_ptr); | 1611 | tipc_node_unlock(n_ptr); |
1750 | continue; | 1612 | continue; |
1751 | } | 1613 | } |
1752 | 1614 | l_ptr->next_in_no++; | |
1753 | /* Link is not in state WORKING_WORKING */ | 1615 | if (unlikely(l_ptr->oldest_deferred_in)) |
1754 | if (msg_user(msg) == LINK_PROTOCOL) { | ||
1755 | link_recv_proto_msg(l_ptr, buf); | ||
1756 | head = link_insert_deferred_queue(l_ptr, head); | 1616 | head = link_insert_deferred_queue(l_ptr, head); |
1617 | deliver: | ||
1618 | if (likely(msg_isdata(msg))) { | ||
1757 | tipc_node_unlock(n_ptr); | 1619 | tipc_node_unlock(n_ptr); |
1620 | tipc_port_recv_msg(buf); | ||
1758 | continue; | 1621 | continue; |
1759 | } | 1622 | } |
1760 | 1623 | switch (msg_user(msg)) { | |
1761 | /* Traffic message. Conditionally activate link */ | 1624 | int ret; |
1762 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); | 1625 | case MSG_BUNDLER: |
1763 | 1626 | l_ptr->stats.recv_bundles++; | |
1764 | if (link_working_working(l_ptr)) { | 1627 | l_ptr->stats.recv_bundled += msg_msgcnt(msg); |
1765 | /* Re-insert buffer in front of queue */ | 1628 | tipc_node_unlock(n_ptr); |
1766 | buf->next = head; | 1629 | tipc_link_recv_bundle(buf); |
1767 | head = buf; | 1630 | continue; |
1631 | case NAME_DISTRIBUTOR: | ||
1632 | n_ptr->bclink.recv_permitted = true; | ||
1633 | tipc_node_unlock(n_ptr); | ||
1634 | tipc_named_recv(buf); | ||
1635 | continue; | ||
1636 | case BCAST_PROTOCOL: | ||
1637 | tipc_link_recv_sync(n_ptr, buf); | ||
1638 | tipc_node_unlock(n_ptr); | ||
1639 | continue; | ||
1640 | case CONN_MANAGER: | ||
1641 | tipc_node_unlock(n_ptr); | ||
1642 | tipc_port_recv_proto_msg(buf); | ||
1643 | continue; | ||
1644 | case MSG_FRAGMENTER: | ||
1645 | l_ptr->stats.recv_fragments++; | ||
1646 | ret = tipc_link_recv_fragment(&l_ptr->reasm_head, | ||
1647 | &l_ptr->reasm_tail, | ||
1648 | &buf); | ||
1649 | if (ret == LINK_REASM_COMPLETE) { | ||
1650 | l_ptr->stats.recv_fragmented++; | ||
1651 | msg = buf_msg(buf); | ||
1652 | goto deliver; | ||
1653 | } | ||
1654 | if (ret == LINK_REASM_ERROR) | ||
1655 | tipc_link_reset(l_ptr); | ||
1768 | tipc_node_unlock(n_ptr); | 1656 | tipc_node_unlock(n_ptr); |
1769 | continue; | 1657 | continue; |
1658 | case CHANGEOVER_PROTOCOL: | ||
1659 | type = msg_type(msg); | ||
1660 | if (link_recv_changeover_msg(&l_ptr, &buf)) { | ||
1661 | msg = buf_msg(buf); | ||
1662 | seq_no = msg_seqno(msg); | ||
1663 | if (type == ORIGINAL_MSG) | ||
1664 | goto deliver; | ||
1665 | goto protocol_check; | ||
1666 | } | ||
1667 | break; | ||
1668 | default: | ||
1669 | kfree_skb(buf); | ||
1670 | buf = NULL; | ||
1671 | break; | ||
1770 | } | 1672 | } |
1771 | tipc_node_unlock(n_ptr); | 1673 | tipc_node_unlock(n_ptr); |
1772 | cont: | 1674 | tipc_net_route_msg(buf); |
1675 | continue; | ||
1676 | unlock_discard: | ||
1677 | |||
1678 | tipc_node_unlock(n_ptr); | ||
1679 | discard: | ||
1773 | kfree_skb(buf); | 1680 | kfree_skb(buf); |
1774 | } | 1681 | } |
1775 | read_unlock_bh(&tipc_net_lock); | 1682 | read_unlock_bh(&tipc_net_lock); |
@@ -2432,114 +2339,48 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
2432 | } | 2339 | } |
2433 | 2340 | ||
2434 | /* | 2341 | /* |
2435 | * A pending message being re-assembled must store certain values | ||
2436 | * to handle subsequent fragments correctly. The following functions | ||
2437 | * help storing these values in unused, available fields in the | ||
2438 | * pending message. This makes dynamic memory allocation unnecessary. | ||
2439 | */ | ||
2440 | static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno) | ||
2441 | { | ||
2442 | msg_set_seqno(buf_msg(buf), seqno); | ||
2443 | } | ||
2444 | |||
2445 | static u32 get_fragm_size(struct sk_buff *buf) | ||
2446 | { | ||
2447 | return msg_ack(buf_msg(buf)); | ||
2448 | } | ||
2449 | |||
2450 | static void set_fragm_size(struct sk_buff *buf, u32 sz) | ||
2451 | { | ||
2452 | msg_set_ack(buf_msg(buf), sz); | ||
2453 | } | ||
2454 | |||
2455 | static u32 get_expected_frags(struct sk_buff *buf) | ||
2456 | { | ||
2457 | return msg_bcast_ack(buf_msg(buf)); | ||
2458 | } | ||
2459 | |||
2460 | static void set_expected_frags(struct sk_buff *buf, u32 exp) | ||
2461 | { | ||
2462 | msg_set_bcast_ack(buf_msg(buf), exp); | ||
2463 | } | ||
2464 | |||
2465 | /* | ||
2466 | * tipc_link_recv_fragment(): Called with node lock on. Returns | 2342 | * tipc_link_recv_fragment(): Called with node lock on. Returns |
2467 | * the reassembled buffer if message is complete. | 2343 | * the reassembled buffer if message is complete. |
2468 | */ | 2344 | */ |
2469 | int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | 2345 | int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail, |
2470 | struct tipc_msg **m) | 2346 | struct sk_buff **fbuf) |
2471 | { | 2347 | { |
2472 | struct sk_buff *prev = NULL; | 2348 | struct sk_buff *frag = *fbuf; |
2473 | struct sk_buff *fbuf = *fb; | 2349 | struct tipc_msg *msg = buf_msg(frag); |
2474 | struct tipc_msg *fragm = buf_msg(fbuf); | 2350 | u32 fragid = msg_type(msg); |
2475 | struct sk_buff *pbuf = *pending; | 2351 | bool headstolen; |
2476 | u32 long_msg_seq_no = msg_long_msgno(fragm); | 2352 | int delta; |
2477 | 2353 | ||
2478 | *fb = NULL; | 2354 | skb_pull(frag, msg_hdr_sz(msg)); |
2479 | 2355 | if (fragid == FIRST_FRAGMENT) { | |
2480 | /* Is there an incomplete message waiting for this fragment? */ | 2356 | if (*head || skb_unclone(frag, GFP_ATOMIC)) |
2481 | while (pbuf && ((buf_seqno(pbuf) != long_msg_seq_no) || | 2357 | goto out_free; |
2482 | (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) { | 2358 | *head = frag; |
2483 | prev = pbuf; | 2359 | skb_frag_list_init(*head); |
2484 | pbuf = pbuf->next; | ||
2485 | } | ||
2486 | |||
2487 | if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) { | ||
2488 | struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm); | ||
2489 | u32 msg_sz = msg_size(imsg); | ||
2490 | u32 fragm_sz = msg_data_sz(fragm); | ||
2491 | u32 exp_fragm_cnt; | ||
2492 | u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE; | ||
2493 | |||
2494 | if (msg_type(imsg) == TIPC_MCAST_MSG) | ||
2495 | max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; | ||
2496 | if (fragm_sz == 0 || msg_size(imsg) > max) { | ||
2497 | kfree_skb(fbuf); | ||
2498 | return 0; | ||
2499 | } | ||
2500 | exp_fragm_cnt = msg_sz / fragm_sz + !!(msg_sz % fragm_sz); | ||
2501 | pbuf = tipc_buf_acquire(msg_size(imsg)); | ||
2502 | if (pbuf != NULL) { | ||
2503 | pbuf->next = *pending; | ||
2504 | *pending = pbuf; | ||
2505 | skb_copy_to_linear_data(pbuf, imsg, | ||
2506 | msg_data_sz(fragm)); | ||
2507 | /* Prepare buffer for subsequent fragments. */ | ||
2508 | set_long_msg_seqno(pbuf, long_msg_seq_no); | ||
2509 | set_fragm_size(pbuf, fragm_sz); | ||
2510 | set_expected_frags(pbuf, exp_fragm_cnt - 1); | ||
2511 | } else { | ||
2512 | pr_debug("Link unable to reassemble fragmented message\n"); | ||
2513 | kfree_skb(fbuf); | ||
2514 | return -1; | ||
2515 | } | ||
2516 | kfree_skb(fbuf); | ||
2517 | return 0; | ||
2518 | } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) { | ||
2519 | u32 dsz = msg_data_sz(fragm); | ||
2520 | u32 fsz = get_fragm_size(pbuf); | ||
2521 | u32 crs = ((msg_fragm_no(fragm) - 1) * fsz); | ||
2522 | u32 exp_frags = get_expected_frags(pbuf) - 1; | ||
2523 | skb_copy_to_linear_data_offset(pbuf, crs, | ||
2524 | msg_data(fragm), dsz); | ||
2525 | kfree_skb(fbuf); | ||
2526 | |||
2527 | /* Is message complete? */ | ||
2528 | if (exp_frags == 0) { | ||
2529 | if (prev) | ||
2530 | prev->next = pbuf->next; | ||
2531 | else | ||
2532 | *pending = pbuf->next; | ||
2533 | msg_reset_reroute_cnt(buf_msg(pbuf)); | ||
2534 | *fb = pbuf; | ||
2535 | *m = buf_msg(pbuf); | ||
2536 | return 1; | ||
2537 | } | ||
2538 | set_expected_frags(pbuf, exp_frags); | ||
2539 | return 0; | 2360 | return 0; |
2361 | } else if (*head && | ||
2362 | skb_try_coalesce(*head, frag, &headstolen, &delta)) { | ||
2363 | kfree_skb_partial(frag, headstolen); | ||
2364 | } else { | ||
2365 | if (!*head) | ||
2366 | goto out_free; | ||
2367 | if (!skb_has_frag_list(*head)) | ||
2368 | skb_shinfo(*head)->frag_list = frag; | ||
2369 | else | ||
2370 | (*tail)->next = frag; | ||
2371 | *tail = frag; | ||
2372 | (*head)->truesize += frag->truesize; | ||
2373 | } | ||
2374 | if (fragid == LAST_FRAGMENT) { | ||
2375 | *fbuf = *head; | ||
2376 | *tail = *head = NULL; | ||
2377 | return LINK_REASM_COMPLETE; | ||
2540 | } | 2378 | } |
2541 | kfree_skb(fbuf); | ||
2542 | return 0; | 2379 | return 0; |
2380 | out_free: | ||
2381 | pr_warn_ratelimited("Link unable to reassemble fragmented message\n"); | ||
2382 | kfree_skb(*fbuf); | ||
2383 | return LINK_REASM_ERROR; | ||
2543 | } | 2384 | } |
2544 | 2385 | ||
2545 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 2386 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) |
@@ -2585,25 +2426,21 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window) | |||
2585 | static struct tipc_link *link_find_link(const char *name, | 2426 | static struct tipc_link *link_find_link(const char *name, |
2586 | struct tipc_node **node) | 2427 | struct tipc_node **node) |
2587 | { | 2428 | { |
2588 | struct tipc_link_name link_name_parts; | ||
2589 | struct tipc_bearer *b_ptr; | ||
2590 | struct tipc_link *l_ptr; | 2429 | struct tipc_link *l_ptr; |
2430 | struct tipc_node *n_ptr; | ||
2431 | int i; | ||
2591 | 2432 | ||
2592 | if (!link_name_validate(name, &link_name_parts)) | 2433 | list_for_each_entry(n_ptr, &tipc_node_list, list) { |
2593 | return NULL; | 2434 | for (i = 0; i < MAX_BEARERS; i++) { |
2594 | 2435 | l_ptr = n_ptr->links[i]; | |
2595 | b_ptr = tipc_bearer_find_interface(link_name_parts.if_local); | 2436 | if (l_ptr && !strcmp(l_ptr->name, name)) |
2596 | if (!b_ptr) | 2437 | goto found; |
2597 | return NULL; | 2438 | } |
2598 | 2439 | } | |
2599 | *node = tipc_node_find(link_name_parts.addr_peer); | 2440 | l_ptr = NULL; |
2600 | if (!*node) | 2441 | n_ptr = NULL; |
2601 | return NULL; | 2442 | found: |
2602 | 2443 | *node = n_ptr; | |
2603 | l_ptr = (*node)->links[b_ptr->identity]; | ||
2604 | if (!l_ptr || strcmp(l_ptr->name, name)) | ||
2605 | return NULL; | ||
2606 | |||
2607 | return l_ptr; | 2444 | return l_ptr; |
2608 | } | 2445 | } |
2609 | 2446 | ||
@@ -2646,6 +2483,7 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2646 | struct tipc_link *l_ptr; | 2483 | struct tipc_link *l_ptr; |
2647 | struct tipc_bearer *b_ptr; | 2484 | struct tipc_bearer *b_ptr; |
2648 | struct tipc_media *m_ptr; | 2485 | struct tipc_media *m_ptr; |
2486 | int res = 0; | ||
2649 | 2487 | ||
2650 | l_ptr = link_find_link(name, &node); | 2488 | l_ptr = link_find_link(name, &node); |
2651 | if (l_ptr) { | 2489 | if (l_ptr) { |
@@ -2668,9 +2506,12 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2668 | case TIPC_CMD_SET_LINK_WINDOW: | 2506 | case TIPC_CMD_SET_LINK_WINDOW: |
2669 | tipc_link_set_queue_limits(l_ptr, new_value); | 2507 | tipc_link_set_queue_limits(l_ptr, new_value); |
2670 | break; | 2508 | break; |
2509 | default: | ||
2510 | res = -EINVAL; | ||
2511 | break; | ||
2671 | } | 2512 | } |
2672 | tipc_node_unlock(node); | 2513 | tipc_node_unlock(node); |
2673 | return 0; | 2514 | return res; |
2674 | } | 2515 | } |
2675 | 2516 | ||
2676 | b_ptr = tipc_bearer_find(name); | 2517 | b_ptr = tipc_bearer_find(name); |
@@ -2678,15 +2519,18 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2678 | switch (cmd) { | 2519 | switch (cmd) { |
2679 | case TIPC_CMD_SET_LINK_TOL: | 2520 | case TIPC_CMD_SET_LINK_TOL: |
2680 | b_ptr->tolerance = new_value; | 2521 | b_ptr->tolerance = new_value; |
2681 | return 0; | 2522 | break; |
2682 | case TIPC_CMD_SET_LINK_PRI: | 2523 | case TIPC_CMD_SET_LINK_PRI: |
2683 | b_ptr->priority = new_value; | 2524 | b_ptr->priority = new_value; |
2684 | return 0; | 2525 | break; |
2685 | case TIPC_CMD_SET_LINK_WINDOW: | 2526 | case TIPC_CMD_SET_LINK_WINDOW: |
2686 | b_ptr->window = new_value; | 2527 | b_ptr->window = new_value; |
2687 | return 0; | 2528 | break; |
2529 | default: | ||
2530 | res = -EINVAL; | ||
2531 | break; | ||
2688 | } | 2532 | } |
2689 | return -EINVAL; | 2533 | return res; |
2690 | } | 2534 | } |
2691 | 2535 | ||
2692 | m_ptr = tipc_media_find(name); | 2536 | m_ptr = tipc_media_find(name); |
@@ -2695,15 +2539,18 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2695 | switch (cmd) { | 2539 | switch (cmd) { |
2696 | case TIPC_CMD_SET_LINK_TOL: | 2540 | case TIPC_CMD_SET_LINK_TOL: |
2697 | m_ptr->tolerance = new_value; | 2541 | m_ptr->tolerance = new_value; |
2698 | return 0; | 2542 | break; |
2699 | case TIPC_CMD_SET_LINK_PRI: | 2543 | case TIPC_CMD_SET_LINK_PRI: |
2700 | m_ptr->priority = new_value; | 2544 | m_ptr->priority = new_value; |
2701 | return 0; | 2545 | break; |
2702 | case TIPC_CMD_SET_LINK_WINDOW: | 2546 | case TIPC_CMD_SET_LINK_WINDOW: |
2703 | m_ptr->window = new_value; | 2547 | m_ptr->window = new_value; |
2704 | return 0; | 2548 | break; |
2549 | default: | ||
2550 | res = -EINVAL; | ||
2551 | break; | ||
2705 | } | 2552 | } |
2706 | return -EINVAL; | 2553 | return res; |
2707 | } | 2554 | } |
2708 | 2555 | ||
2709 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, | 2556 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, |