* add an asconf add/delete/set primary IP address parameter to the queue. * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR. * returns 0 if queued, -1 if not queued/removed. * NOTE: if adding, but a delete for the same address is already scheduled * (and not yet sent out), simply remove it from queue. Same for deleting * an address already scheduled for add. If a duplica
| 1213 | * ignore the new one. |
| 1214 | */ |
| 1215 | static int |
| 1216 | sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, |
| 1217 | uint16_t type) |
| 1218 | { |
| 1219 | struct sctp_asconf_addr *aa, *aa_next; |
| 1220 | |
| 1221 | /* make sure the request isn't already in the queue */ |
| 1222 | TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { |
| 1223 | /* address match? */ |
| 1224 | if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0) |
| 1225 | continue; |
| 1226 | /* |
| 1227 | * is the request already in queue but not sent? pass the |
| 1228 | * request already sent in order to resolve the following |
| 1229 | * case: 1. arrival of ADD, then sent 2. arrival of DEL. we |
| 1230 | * can't remove the ADD request already sent 3. arrival of |
| 1231 | * ADD |
| 1232 | */ |
| 1233 | if (aa->ap.aph.ph.param_type == type && aa->sent == 0) { |
| 1234 | return (-1); |
| 1235 | } |
| 1236 | /* is the negative request already in queue, and not sent */ |
| 1237 | if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) && |
| 1238 | (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) { |
| 1239 | /* add requested, delete already queued */ |
| 1240 | TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); |
| 1241 | /* remove the ifa from the restricted list */ |
| 1242 | sctp_del_local_addr_restricted(stcb, ifa); |
| 1243 | /* free the asconf param */ |
| 1244 | SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
| 1245 | SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n"); |
| 1246 | return (-1); |
| 1247 | } |
| 1248 | if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) && |
| 1249 | (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) { |
| 1250 | /* delete requested, add already queued */ |
| 1251 | TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); |
| 1252 | /* remove the aa->ifa from the restricted list */ |
| 1253 | sctp_del_local_addr_restricted(stcb, aa->ifa); |
| 1254 | /* free the asconf param */ |
| 1255 | SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
| 1256 | SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n"); |
| 1257 | return (-1); |
| 1258 | } |
| 1259 | } /* for each aa */ |
| 1260 | |
| 1261 | /* adding new request to the queue */ |
| 1262 | SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
| 1263 | SCTP_M_ASC_ADDR); |
| 1264 | if (aa == NULL) { |
| 1265 | /* didn't get memory */ |
| 1266 | SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n"); |
| 1267 | return (-1); |
| 1268 | } |
| 1269 | aa->special_del = 0; |
| 1270 | /* fill in asconf address parameter fields */ |
| 1271 | /* top level elements are "networked" during send */ |
| 1272 | aa->ap.aph.ph.param_type = type; |
no test coverage detected