diff options
Diffstat (limited to 'net/sctp/ulpevent.c')
-rw-r--r-- | net/sctp/ulpevent.c | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 2e11bc8d5d35..661ea2dd78ba 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) | |||
131 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | 131 | struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( |
132 | const struct sctp_association *asoc, | 132 | const struct sctp_association *asoc, |
133 | __u16 flags, __u16 state, __u16 error, __u16 outbound, | 133 | __u16 flags, __u16 state, __u16 error, __u16 outbound, |
134 | __u16 inbound, gfp_t gfp) | 134 | __u16 inbound, struct sctp_chunk *chunk, gfp_t gfp) |
135 | { | 135 | { |
136 | struct sctp_ulpevent *event; | 136 | struct sctp_ulpevent *event; |
137 | struct sctp_assoc_change *sac; | 137 | struct sctp_assoc_change *sac; |
138 | struct sk_buff *skb; | 138 | struct sk_buff *skb; |
139 | 139 | ||
140 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), | 140 | /* If the lower layer passed in the chunk, it will be |
141 | * an ABORT, so we need to include it in the sac_info. | ||
142 | */ | ||
143 | if (chunk) { | ||
144 | /* sctp_inqu_pop() has allready pulled off the chunk | ||
145 | * header. We need to put it back temporarily | ||
146 | */ | ||
147 | skb_push(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
148 | |||
149 | /* Copy the chunk data to a new skb and reserve enough | ||
150 | * head room to use as notification. | ||
151 | */ | ||
152 | skb = skb_copy_expand(chunk->skb, | ||
153 | sizeof(struct sctp_assoc_change), 0, gfp); | ||
154 | |||
155 | if (!skb) | ||
156 | goto fail; | ||
157 | |||
158 | /* put back the chunk header now that we have a copy */ | ||
159 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
160 | |||
161 | /* Embed the event fields inside the cloned skb. */ | ||
162 | event = sctp_skb2event(skb); | ||
163 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); | ||
164 | |||
165 | /* Include the notification structure */ | ||
166 | sac = (struct sctp_assoc_change *) | ||
167 | skb_push(skb, sizeof(struct sctp_assoc_change)); | ||
168 | |||
169 | /* Trim the buffer to the right length. */ | ||
170 | skb_trim(skb, sizeof(struct sctp_assoc_change) + | ||
171 | ntohs(chunk->chunk_hdr->length)); | ||
172 | } else { | ||
173 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), | ||
141 | MSG_NOTIFICATION, gfp); | 174 | MSG_NOTIFICATION, gfp); |
142 | if (!event) | 175 | if (!event) |
143 | goto fail; | 176 | goto fail; |
144 | skb = sctp_event2skb(event); | 177 | |
145 | sac = (struct sctp_assoc_change *) | 178 | skb = sctp_event2skb(event); |
146 | skb_put(skb, sizeof(struct sctp_assoc_change)); | 179 | sac = (struct sctp_assoc_change *) skb_put(skb, |
180 | sizeof(struct sctp_assoc_change)); | ||
181 | } | ||
147 | 182 | ||
148 | /* Socket Extensions for SCTP | 183 | /* Socket Extensions for SCTP |
149 | * 5.3.1.1 SCTP_ASSOC_CHANGE | 184 | * 5.3.1.1 SCTP_ASSOC_CHANGE |