LyoKICogUGVyZm9ybWFuY2UgZXZlbnRzIGNhbGxjaGFpbiBjb2RlLCBleHRyYWN0ZWQgZnJvbSBjb3JlLmM6CiAqCiAqICBDb3B5cmlnaHQgKEMpIDIwMDggVGhvbWFzIEdsZWl4bmVyIDx0Z2x4QGxpbnV0cm9uaXguZGU+CiAqICBDb3B5cmlnaHQgKEMpIDIwMDgtMjAxMSBSZWQgSGF0LCBJbmMuLCBJbmdvIE1vbG5hcgogKiAgQ29weXJpZ2h0IChDKSAyMDA4LTIwMTEgUmVkIEhhdCwgSW5jLiwgUGV0ZXIgWmlqbHN0cmEKICogIENvcHlyaWdodCAgqSAgMjAwOSBQYXVsIE1hY2tlcnJhcywgSUJNIENvcnAuIDxwYXVsdXNAYXUxLmlibS5jb20+CiAqCiAqIEZvciBsaWNlbnNpbmcgZGV0YWlscyBzZWUga2VybmVsLWJhc2UvQ09QWUlORwogKi8KCiNpbmNsdWRlIDxsaW51eC9wZXJmX2V2ZW50Lmg+CiNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CiNpbmNsdWRlICJpbnRlcm5hbC5oIgoKc3RydWN0IGNhbGxjaGFpbl9jcHVzX2VudHJpZXMgewoJc3RydWN0IHJjdV9oZWFkCQkJcmN1X2hlYWQ7CglzdHJ1Y3QgcGVyZl9jYWxsY2hhaW5fZW50cnkJKmNwdV9lbnRyaWVzWzBdOwp9OwoKaW50IHN5c2N0bF9wZXJmX2V2ZW50X21heF9zdGFjayBfX3JlYWRfbW9zdGx5ID0gUEVSRl9NQVhfU1RBQ0tfREVQVEg7CmludCBzeXNjdGxfcGVyZl9ldmVudF9tYXhfY29udGV4dHNfcGVyX3N0YWNrIF9fcmVhZF9tb3N0bHkgPSBQRVJGX01BWF9DT05URVhUU19QRVJfU1RBQ0s7CgpzdGF0aWMgaW5saW5lIHNpemVfdCBwZXJmX2NhbGxjaGFpbl9lbnRyeV9fc2l6ZW9mKHZvaWQpCnsKCXJldHVybiAoc2l6ZW9mKHN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeSkgKwoJCXNpemVvZihfX3U2NCkgKiAoc3lzY3RsX3BlcmZfZXZlbnRfbWF4X3N0YWNrICsKCQkJCSBzeXNjdGxfcGVyZl9ldmVudF9tYXhfY29udGV4dHNfcGVyX3N0YWNrKSk7Cn0KCnN0YXRpYyBERUZJTkVfUEVSX0NQVShpbnQsIGNhbGxjaGFpbl9yZWN1cnNpb25bUEVSRl9OUl9DT05URVhUU10pOwpzdGF0aWMgYXRvbWljX3QgbnJfY2FsbGNoYWluX2V2ZW50czsKc3RhdGljIERFRklORV9NVVRFWChjYWxsY2hhaW5fbXV0ZXgpOwpzdGF0aWMgc3RydWN0IGNhbGxjaGFpbl9jcHVzX2VudHJpZXMgKmNhbGxjaGFpbl9jcHVzX2VudHJpZXM7CgoKX193ZWFrIHZvaWQgcGVyZl9jYWxsY2hhaW5fa2VybmVsKHN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeV9jdHggKmVudHJ5LAoJCQkJICBzdHJ1Y3QgcHRfcmVncyAqcmVncykKewp9CgpfX3dlYWsgdm9pZCBwZXJmX2NhbGxjaGFpbl91c2VyKHN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeV9jdHggKmVudHJ5LAoJCQkJc3RydWN0IHB0X3JlZ3MgKnJlZ3MpCnsKfQoKc3RhdGljIHZvaWQgcmVsZWFzZV9jYWxsY2hhaW5fYnVmZmVyc19yY3Uoc3RydWN0IHJjdV9oZWFkICpoZWFkKQp7CglzdHJ1Y3QgY2FsbGNoYWluX2NwdXNfZW50cmllcyAqZW50cmllczsKCWludCBjcHU7CgoJZW50cmllcyA9IGNvbnRhaW5lcl9vZihoZWFkLCBzdHJ1Y3QgY2FsbGNoYWluX2NwdXNfZW50cmllcywgcmN1X2hlYWQpOwoKCWZvcl9lYWNoX3Bvc3NpYmxlX2NwdShjcHUpCgkJa2ZyZWUoZW50cmllcy0+Y3B1X2VudHJpZXNbY3B1XSk7CgoJa2ZyZWUoZW50cmllcyk7Cn0KCnN0YXRpYyB2b2lkIHJlbGVhc2VfY2FsbGNoYWluX2J1ZmZlcnModm9pZCkKewoJc3RydWN0IGNhbGxjaGFpbl9jcHVzX2VudHJpZXMgKmVudHJpZXM7CgoJZW50cmllcyA9IGNhbGxjaGFpbl9jcHVzX2VudHJpZXM7CglSQ1VfSU5JVF9QT0lOVEVSKGNhbGxjaGFpbl9jcHVzX2VudHJpZXMsIE5VTEwpOwoJY2FsbF9yY3UoJmVudHJpZXMtPnJjdV9oZWFkLCByZWxlYXNlX2NhbGxjaGFpbl9idWZmZXJzX3JjdSk7Cn0KCnN0YXRpYyBpbnQgYWxsb2NfY2FsbGNoYWluX2J1ZmZlcnModm9pZCkKewoJaW50IGNwdTsKCWludCBzaXplOwoJc3RydWN0IGNhbGxjaGFpbl9jcHVzX2VudHJpZXMgKmVudHJpZXM7CgoJLyoKCSAqIFdlIGNhbid0IHVzZSB0aGUgcGVyY3B1IGFsbG9jYXRpb24gQVBJIGZvciBkYXRhIHRoYXQgY2FuIGJlCgkgKiBhY2Nlc3NlZCBmcm9tIE5NSS4gVXNlIGEgdGVtcG9yYXJ5IG1hbnVhbCBwZXIgY3B1IGFsbG9jYXRpb24KCSAqIHVudGlsIHRoYXQgZ2V0cyBzb3J0ZWQgb3V0LgoJICovCglzaXplID0gb2Zmc2V0b2Yoc3RydWN0IGNhbGxjaGFpbl9jcHVzX2VudHJpZXMsIGNwdV9lbnRyaWVzW25yX2NwdV9pZHNdKTsKCgllbnRyaWVzID0ga3phbGxvYyhzaXplLCBHRlBfS0VSTkVMKTsKCWlmICghZW50cmllcykKCQlyZXR1cm4gLUVOT01FTTsKCglzaXplID0gcGVyZl9jYWxsY2hhaW5fZW50cnlfX3NpemVvZigpICogUEVSRl9OUl9DT05URVhUUzsKCglmb3JfZWFjaF9wb3NzaWJsZV9jcHUoY3B1KSB7CgkJZW50cmllcy0+Y3B1X2VudHJpZXNbY3B1XSA9IGttYWxsb2Nfbm9kZShzaXplLCBHRlBfS0VSTkVMLAoJCQkJCQkJIGNwdV90b19ub2RlKGNwdSkpOwoJCWlmICghZW50cmllcy0+Y3B1X2VudHJpZXNbY3B1XSkKCQkJZ290byBmYWlsOwoJfQoKCXJjdV9hc3NpZ25fcG9pbnRlcihjYWxsY2hhaW5fY3B1c19lbnRyaWVzLCBlbnRyaWVzKTsKCglyZXR1cm4gMDsKCmZhaWw6Cglmb3JfZWFjaF9wb3NzaWJsZV9jcHUoY3B1KQoJCWtmcmVlKGVudHJpZXMtPmNwdV9lbnRyaWVzW2NwdV0pOwoJa2ZyZWUoZW50cmllcyk7CgoJcmV0dXJuIC1FTk9NRU07Cn0KCmludCBnZXRfY2FsbGNoYWluX2J1ZmZlcnMoaW50IGV2ZW50X21heF9zdGFjaykKewoJaW50IGVyciA9IDA7CglpbnQgY291bnQ7CgoJbXV0ZXhfbG9jaygmY2FsbGNoYWluX211dGV4KTsKCgljb3VudCA9IGF0b21pY19pbmNfcmV0dXJuKCZucl9jYWxsY2hhaW5fZXZlbnRzKTsKCWlmIChXQVJOX09OX09OQ0UoY291bnQgPCAxKSkgewoJCWVyciA9IC1FSU5WQUw7CgkJZ290byBleGl0OwoJfQoKCS8qCgkgKiBJZiByZXF1ZXN0aW5nIHBlciBldmVudCBtb3JlIHRoYW4gdGhlIGdsb2JhbCBjYXAsCgkgKiByZXR1cm4gYSBkaWZmZXJlbnQgZXJyb3IgdG8gaGVscCB1c2Vyc3BhY2UgZmlndXJlCgkgKiB0aGlzIG91dC4KCSAqCgkgKiBBbmQgYWxzbyBkbyBpdCBoZXJlIHNvIHRoYXQgd2UgaGF2ZSAmY2FsbGNoYWluX211dGV4IGhlbGQuCgkgKi8KCWlmIChldmVudF9tYXhfc3RhY2sgPiBzeXNjdGxfcGVyZl9ldmVudF9tYXhfc3RhY2spIHsKCQllcnIgPSAtRU9WRVJGTE9XOwoJCWdvdG8gZXhpdDsKCX0KCglpZiAoY291bnQgPT0gMSkKCQllcnIgPSBhbGxvY19jYWxsY2hhaW5fYnVmZmVycygpOwpleGl0OgoJaWYgKGVycikKCQlhdG9taWNfZGVjKCZucl9jYWxsY2hhaW5fZXZlbnRzKTsKCgltdXRleF91bmxvY2soJmNhbGxjaGFpbl9tdXRleCk7CgoJcmV0dXJuIGVycjsKfQoKdm9pZCBwdXRfY2FsbGNoYWluX2J1ZmZlcnModm9pZCkKewoJaWYgKGF0b21pY19kZWNfYW5kX211dGV4X2xvY2soJm5yX2NhbGxjaGFpbl9ldmVudHMsICZjYWxsY2hhaW5fbXV0ZXgpKSB7CgkJcmVsZWFzZV9jYWxsY2hhaW5fYnVmZmVycygpOwoJCW11dGV4X3VubG9jaygmY2FsbGNoYWluX211dGV4KTsKCX0KfQoKc3RhdGljIHN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeSAqZ2V0X2NhbGxjaGFpbl9lbnRyeShpbnQgKnJjdHgpCnsKCWludCBjcHU7CglzdHJ1Y3QgY2FsbGNoYWluX2NwdXNfZW50cmllcyAqZW50cmllczsKCgkqcmN0eCA9IGdldF9yZWN1cnNpb25fY29udGV4dCh0aGlzX2NwdV9wdHIoY2FsbGNoYWluX3JlY3Vyc2lvbikpOwoJaWYgKCpyY3R4ID09IC0xKQoJCXJldHVybiBOVUxMOwoKCWVudHJpZXMgPSByY3VfZGVyZWZlcmVuY2UoY2FsbGNoYWluX2NwdXNfZW50cmllcyk7CglpZiAoIWVudHJpZXMpCgkJcmV0dXJuIE5VTEw7CgoJY3B1ID0gc21wX3Byb2Nlc3Nvcl9pZCgpOwoKCXJldHVybiAoKCh2b2lkICopZW50cmllcy0+Y3B1X2VudHJpZXNbY3B1XSkgKwoJCSgqcmN0eCAqIHBlcmZfY2FsbGNoYWluX2VudHJ5X19zaXplb2YoKSkpOwp9CgpzdGF0aWMgdm9pZApwdXRfY2FsbGNoYWluX2VudHJ5KGludCByY3R4KQp7CglwdXRfcmVjdXJzaW9uX2NvbnRleHQodGhpc19jcHVfcHRyKGNhbGxjaGFpbl9yZWN1cnNpb24pLCByY3R4KTsKfQoKc3RydWN0IHBlcmZfY2FsbGNoYWluX2VudHJ5ICoKcGVyZl9jYWxsY2hhaW4oc3RydWN0IHBlcmZfZXZlbnQgKmV2ZW50LCBzdHJ1Y3QgcHRfcmVncyAqcmVncykKewoJYm9vbCBrZXJuZWwgPSAhZXZlbnQtPmF0dHIuZXhjbHVkZV9jYWxsY2hhaW5fa2VybmVsOwoJYm9vbCB1c2VyICAgPSAhZXZlbnQtPmF0dHIuZXhjbHVkZV9jYWxsY2hhaW5fdXNlcjsKCS8qIERpc2FsbG93IGNyb3NzLXRhc2sgdXNlciBjYWxsY2hhaW5zLiAqLwoJYm9vbCBjcm9zc3Rhc2sgPSBldmVudC0+Y3R4LT50YXNrICYmIGV2ZW50LT5jdHgtPnRhc2sgIT0gY3VycmVudDsKCWNvbnN0IHUzMiBtYXhfc3RhY2sgPSBldmVudC0+YXR0ci5zYW1wbGVfbWF4X3N0YWNrOwoKCWlmICgha2VybmVsICYmICF1c2VyKQoJCXJldHVybiBOVUxMOwoKCXJldHVybiBnZXRfcGVyZl9jYWxsY2hhaW4ocmVncywgMCwga2VybmVsLCB1c2VyLCBtYXhfc3RhY2ssIGNyb3NzdGFzaywgdHJ1ZSk7Cn0KCnN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeSAqCmdldF9wZXJmX2NhbGxjaGFpbihzdHJ1Y3QgcHRfcmVncyAqcmVncywgdTMyIGluaXRfbnIsIGJvb2wga2VybmVsLCBib29sIHVzZXIsCgkJICAgdTMyIG1heF9zdGFjaywgYm9vbCBjcm9zc3Rhc2ssIGJvb2wgYWRkX21hcmspCnsKCXN0cnVjdCBwZXJmX2NhbGxjaGFpbl9lbnRyeSAqZW50cnk7CglzdHJ1Y3QgcGVyZl9jYWxsY2hhaW5fZW50cnlfY3R4IGN0eDsKCWludCByY3R4OwoKCWVudHJ5ID0gZ2V0X2NhbGxjaGFpbl9lbnRyeSgmcmN0eCk7CglpZiAocmN0eCA9PSAtMSkKCQlyZXR1cm4gTlVMTDsKCglpZiAoIWVudHJ5KQoJCWdvdG8gZXhpdF9wdXQ7CgoJY3R4LmVudHJ5ICAgICA9IGVudHJ5OwoJY3R4Lm1heF9zdGFjayA9IG1heF9zdGFjazsKCWN0eC5ucgkgICAgICA9IGVudHJ5LT5uciA9IGluaXRfbnI7CgljdHguY29udGV4dHMgICAgICAgPSAwOwoJY3R4LmNvbnRleHRzX21heGVkID0gZmFsc2U7CgoJaWYgKGtlcm5lbCAmJiAhdXNlcl9tb2RlKHJlZ3MpKSB7CgkJaWYgKGFkZF9tYXJrKQoJCQlwZXJmX2NhbGxjaGFpbl9zdG9yZV9jb250ZXh0KCZjdHgsIFBFUkZfQ09OVEVYVF9LRVJORUwpOwoJCXBlcmZfY2FsbGNoYWluX2tlcm5lbCgmY3R4LCByZWdzKTsKCX0KCglpZiAodXNlcikgewoJCWlmICghdXNlcl9tb2RlKHJlZ3MpKSB7CgkJCWlmICAoY3VycmVudC0+bW0pCgkJCQlyZWdzID0gdGFza19wdF9yZWdzKGN1cnJlbnQpOwoJCQllbHNlCgkJCQlyZWdzID0gTlVMTDsKCQl9CgoJCWlmIChyZWdzKSB7CgkJCW1tX3NlZ21lbnRfdCBmczsKCgkJCWlmIChjcm9zc3Rhc2spCgkJCQlnb3RvIGV4aXRfcHV0OwoKCQkJaWYgKGFkZF9tYXJrKQoJCQkJcGVyZl9jYWxsY2hhaW5fc3RvcmVfY29udGV4dCgmY3R4LCBQRVJGX0NPTlRFWFRfVVNFUik7CgoJCQlmcyA9IGdldF9mcygpOwoJCQlzZXRfZnMoVVNFUl9EUyk7CgkJCXBlcmZfY2FsbGNoYWluX3VzZXIoJmN0eCwgcmVncyk7CgkJCXNldF9mcyhmcyk7CgkJfQoJfQoKZXhpdF9wdXQ6CglwdXRfY2FsbGNoYWluX2VudHJ5KHJjdHgpOwoKCXJldHVybiBlbnRyeTsKfQoKLyoKICogVXNlZCBmb3Igc3lzY3RsX3BlcmZfZXZlbnRfbWF4X3N0YWNrIGFuZAogKiBzeXNjdGxfcGVyZl9ldmVudF9tYXhfY29udGV4dHNfcGVyX3N0YWNrLgogKi8KaW50IHBlcmZfZXZlbnRfbWF4X3N0YWNrX2hhbmRsZXIoc3RydWN0IGN0bF90YWJsZSAqdGFibGUsIGludCB3cml0ZSwKCQkJCSB2b2lkIF9fdXNlciAqYnVmZmVyLCBzaXplX3QgKmxlbnAsIGxvZmZfdCAqcHBvcykKewoJaW50ICp2YWx1ZSA9IHRhYmxlLT5kYXRhOwoJaW50IG5ld192YWx1ZSA9ICp2YWx1ZSwgcmV0OwoJc3RydWN0IGN0bF90YWJsZSBuZXdfdGFibGUgPSAqdGFibGU7CgoJbmV3X3RhYmxlLmRhdGEgPSAmbmV3X3ZhbHVlOwoJcmV0ID0gcHJvY19kb2ludHZlY19taW5tYXgoJm5ld190YWJsZSwgd3JpdGUsIGJ1ZmZlciwgbGVucCwgcHBvcyk7CglpZiAocmV0IHx8ICF3cml0ZSkKCQlyZXR1cm4gcmV0OwoKCW11dGV4X2xvY2soJmNhbGxjaGFpbl9tdXRleCk7CglpZiAoYXRvbWljX3JlYWQoJm5yX2NhbGxjaGFpbl9ldmVudHMpKQoJCXJldCA9IC1FQlVTWTsKCWVsc2UKCQkqdmFsdWUgPSBuZXdfdmFsdWU7CgoJbXV0ZXhfdW5sb2NrKCZjYWxsY2hhaW5fbXV0ZXgpOwoKCXJldHVybiByZXQ7Cn0K